Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lots of instances of TypeError: n is not a function on website when incorporating event handlers #550

Open
rosesyrett opened this issue Oct 18, 2024 · 2 comments

Comments

@rosesyrett
Copy link

rosesyrett commented Oct 18, 2024

Description and Background

Since implementing web-vitals into my website I've seen a significant amount of TypeError instances that seem to be originating from the transpiled web-vitals.js script on the browser.

This is probably an issue with my implementation of this library, however I would just like to see if there's any indication it could be a broader issue. I'm unsure how my implementation is incorrect, going from the useful instructions in the documentation.

How I've used web-vitals

I've recently added the web-vitals npm package to my website, and started monitoring a small percentage of my traffic with these event handlers. I have wrapped all of my react components with these, i.e. we have a setup.ts function that sets up e.g. connections to sentry, our analytics pipeline, and also sets up these event handlers (given the presence of an experimental flag, which is set to about 1% currently... so 1% of requests will go through this logic). Here is what the relevant part of that file looks like:

import * as Sentry from "@sentry/browser"; // eslint-disable-line import/no-namespace
import { Integrations } from "@sentry/tracing";

import { Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from "web-vitals";

function setupSentry(): void {
    Sentry.init({...});
    ...
}

export function sendAnalyticsMetricEvent(metric: Metric, timeoutMs = 2000): void {
    const subtype: string = "core_web_vitals.".concat(metric.name.toLowerCase());

    // we need to ensure the metric is serialized properly first.
    // It's possible some metrics contain circular references. In this case, just discard those keys.
    // See this issue: https://github.com/GoogleChrome/web-vitals/issues/77
    // Note: I may also want to update this function to handle e.g. LCP entries elements,
    // which are HTML elements that can't be stringified and will otherwise be completely
    // ommitted.
    let cache: any[] = [];
    let data = JSON.stringify({ ...metric, attribution: {} }, function (key, value) {
        if (typeof value === "object" && value !== null) {
            if (cache.indexOf(value) !== -1) {
                // Circular reference found, discard key
                return;
            }
            // Store value in our collection
            cache.push(value);
        }
        return value;
    });

    // Timeout promise that rejects after `timeoutMs` milliseconds
    const timeoutPromise = new Promise((_, reject) => {
        setTimeout(() => {
            reject(new Error("Analytics event timed out."));
        }, timeoutMs);
    });

    const analyticsPromise = analytics.event(
        "page_load",
        "web_vitals",
        "",
        true,
        JSON.parse(data),
        subtype
    );

    Promise.race([analyticsPromise, timeoutPromise]).catch((error) => {
        console.error(error.message); // Handle timeout or other errors
    });
}

export function setup(components: ReactComponentManifest): void {
    setupSentry();

    ...

    analytics.init();

    ...

    if (environment.getFeature("my_experiment_flag")) {
        onCLS(sendAnalyticsMetricEvent);
        onINP(sendAnalyticsMetricEvent);
        onLCP(sendAnalyticsMetricEvent);
        onFCP(sendAnalyticsMetricEvent);
        onTTFB(sendAnalyticsMetricEvent);
    }
}

So all we're doing is setting up callbacks for the event handlers, which will take the event, add an 'attribution' to it (for now, this is empty; later on, we will actually use event handlers for metrics from the web-vitals/attribution part of the library), and sanitize it, i.e. serialize and deserialize it before sending it through our analytics pipeline.

When I was testing this out, everything was fine, I was seeing the callbacks being fired correctly. However since releasing this feature on my website we have noticed some interesting sentry errors. Here is what it looks like when I visit any part of our website with the experimental flag enabled:

image

I'm not sure why the error is shown twice in the above screenshot. After this has surfaced, the website correctly calls the event handlers, and I can see data correctly being routed through our analytics pipeline. Presumably there are some initial metrics on page load which are not reported on because of this error.

Error details/ stack trace

TypeError: n is not a function

../node_modules/web-vitals/dist/web-vitals.js in c at line 1:2842

)):(i=e.value,o=[e])}})),i>r.value&&(r.value=i,r.entries=o,t())},u=s("layout-shift",c);u&&(t=d(e,r,L,n.reportAllChanges),p((function(){c(u.t 

../node_modules/web-vitals/dist/web-vitals.js in at line 1:868

ceObserver((function(e){Promise.resolve().then((function(){n(e.getEntries())}))}));return r.observe(Object.assign({type:e,buffered:!0},t||{} 

Environment details

We are on node v18.20.4, npm version 10.7.0. We are running a django application with a react frontend mostly written in typescript. Please let me know if you'd like to see more details, I can attach a package.lock or something similar but many of our libraries are internal (our repository is hosted on github enterprise).

@tunetheweb
Copy link
Member

tunetheweb commented Oct 18, 2024

Both are saying your sendAnalyticsMetricEvent callback function is not a function. Is it possible that it's not defined yet by the time the library is loaded?

@philipwalton
Copy link
Member

Also, your sendAnalyticsMetricEvent() function has a different signature than what's expected by the onXXX() function in this library, so I think something's missing in the "how you use web-vitals" example above that would explain this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants