BuilderIO / partytown

Relocate resource intensive third-party scripts off of the main thread and into a web worker. πŸŽ‰
https://partytown.builder.io
MIT License
13.06k stars 434 forks source link

Scripts not being intercepted on a client-side transition #74

Open housseindjirdeh opened 2 years ago

housseindjirdeh commented 2 years ago

Hi folks! I'm noticing an interesting issue adding Partytown to a Next.js app and I'm not sure if it's intended behavior or if I'm just doing something wrong πŸ˜….

Consider a basic Next.js application with two routes that have the <Partytown/> React component included in its head along with a 3P script with type="text/partytown":

Page 1:

import { Partytown } from "@builder.io/partytown/react";

const Home = () => {
  return (
    <>
      <Head>
        <Partytown debug={true} logScriptExecution={true} />
        <script
          src="https://cdn.jsdelivr.net/npm/cookieconsent@3/build/cookieconsent.min.js"
          type="text/partytown"
        />
      </Head>
      <Link href="/about">About</Link>
    </>
  );
};

Page 2:

import { Partytown } from "@builder.io/partytown/react";

const About = () => {
  return (
    <>
      <Head>
        <Partytown debug={true} logScriptExecution={true} />
        <script
          src="https://connect.facebook.net/en_US/sdk.js"
          type="text/partytown"
        />
      </Head>
      <Link href="/">About</Link>
    </>
  );
};

When I reload either of the two pages where the Partytown snippet gets injected server-side, the script seems to be intercepted by the service worker correctly and I see that it gets executed via the debug logs:

Screen Shot 2022-02-12 at 12 29 15 PM

However when I navigate from one page to the other via a client-side transition, the script on the second page doesn't seem to be fetched or executed. Here's a video that shows how the script on the second page doesn't load on a client-side navigation but does during an SSR reload:

https://user-images.githubusercontent.com/12476932/153726259-1ddb5dd8-694e-4ae8-98ce-3e5ec436d0c7.mov

Similarly, if I remove the script in Page 1 and then navigate to Page 2 where the Partytown snippet should get injected and instantiated client-side, it doesn't seem to work as well πŸ€”.


I set up a reproduction here: https://codesandbox.io/s/mystifying-goldberg-o12j7?file=/pages/index.js. Please let me know if you need any more details and/or if I can help debug where the potential issue may be happening.

valse commented 2 years ago

Hi, I have the same question too: I successfully loaded the GTM script on my custom Next.js Document page and, at start, the pageview event is triggered as expected.

I tried, then, to push the pageview event client side, listening on "routeChangeComplete" router event but the command is never forwarded to the service worker:

useEffect(() => {
    const pageview = (url) => {
      dataLayer.push({
        event: "pageview",
        page: url,
      })
    }

    router.events.on("routeChangeComplete", pageview)

    return () => {
      router.events.off("routeChangeComplete", pageview)
    }
}, [router.events])
danielroe commented 2 years ago

We're encountering the same with Nuxt. I think implementing with MutationObserver might be a straightforward approach?

itsmnthn commented 2 years ago

I faced this same issue while implementing this with Nuxt2. Initial event works well but using window.dataLayer.push(event) doesn't trigger GTM request for that event.

I've created simple implementation here nuxt2-partytown-demo

If this issue is fixed then I'm planning to write a module/plugin for Nuxt2 to implement Partytown

itsmnthn commented 2 years ago

I ran gtag integration test locally and it seems button click is not sending event as it suppose to send { event: 'button-click', from: 'partytown' }

test/integration/gtag at https://github.com/BuilderIO/partytown/blob/main/tests/integrations/gtm/index.html`

Also tried live test https://partytown.builder.io/tests/integrations/gtm/ with same problem.

Is this expected behaviour and I am not understanding something or there is problem?

CruScanlan commented 2 years ago

I am getting the same issue. I cannot find a way to send a page view event to the Partytown GTM script from the main thread in Next.js.

itsmnthn commented 2 years ago

Check this demo nuxt2-partytown-demo I tried using hidden input on main thread and dispatchEvent('change') on button click and listen the same input change event in text/partytown gtag script and use gtag('pageView', 'about') but with no luck.

doing window.dataLayer.push inside partytown script where gtag is initialised works only once, letter it just doesn't send new event after it.

valse commented 2 years ago

Hi, I finally found how to use GA with Partytown and Next.js.... here my post about it: I'd like to try with GTM too.

wardpeet commented 2 years ago

@adamdbradley what's would be the correct approach here to help implement?

1) Create mutation observer that listens to newly created script tags with type text/partytown and route them through partytown. 2) Create a function that you can call to inject partytown tags?

One would be the most automated one, where you don't have to think about implementation details as a end-user. The second option would be more on the framework side, where you can do the logic with a Script component.

mrakus-sofomo commented 1 year ago

This is because the Playwright component mounts a snippet to the header, this snippet, only checks once for the existence of the text/partytown scripts, when the document is loaded. The logic does not rerun when page transition happens. https://github.com/BuilderIO/partytown/blob/main/src/lib/main/snippet.ts#L156

Edit: I've scratched around a bit more and it seems that the worker uses requestAnimationFrame, to detect the next scripts. I'll try to debug it some more, I'm annoyed by this bug, especially since it's been open for so long.

gioboa commented 1 year ago

Thanks for your help @mrakus-sofomo let's try to solve this issue

mrakus-sofomo commented 7 months ago

@gioboa Is this issue still present in nextjs worker script? https://nextjs.org/docs/pages/building-your-application/optimizing/scripts#offloading-scripts-to-a-web-worker-experimental

gioboa commented 7 months ago

@gioboa Is this issue still present in nextjs worker script? https://nextjs.org/docs/pages/building-your-application/optimizing/scripts#offloading-scripts-to-a-web-worker-experimental

I guess so. I didn't solve it yet