vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.96k stars 26.69k forks source link

If Script is removed via vanilla JS logic, it doesn't re-mount on consecutive renders #48093

Open aloeugene opened 1 year ago

aloeugene commented 1 year ago

Verify canary release

Provide environment information

Operating System:
    Platform: darwin
    Arch: arm64
    Version: Darwin Kernel Version 22.3.0: Mon Jan 30 20:38:37 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6000
Binaries:
    Node: 18.14.2
    npm: 9.5.0
    Yarn: N/A
    pnpm: N/A
Relevant packages:
    next: 13.2.4
    eslint-config-next: 13.2.1
    react: 18.2.0
    react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

Script optimization (next/script)

Link to the code that reproduces this issue

https://codesandbox.io/p/sandbox/naughty-meitner-jlzxub?file=%2Fpages%2Findex.tsx

To Reproduce

Steps to reproduce are inserted into the linked codesandbox.

In short:

  1. Have multiple routes to switch between.
  2. Add <Script>-implemented script to the DOM when initial/home page mounts.
  3. Right before navigating to a different route (router.events.on('routeChangeStart')) remove the script from step 2 via vanilla JS code (document.body.removeChild(...)).
  4. Navigate from a different route back to the initial/home page.
  5. Observe that there's no script added to the DOM, though the component itself mounts correctly.

Describe the Bug

When navigating between app routes, <Script>-implemented scripts are not being added to the DOM if they were removed via vanilla JS means (e.g. document.body.removeChild(...)) before route switch.

Expected Behavior

When navigating between app routes, <Script>-implemented scripts should be added to the DOM if they were removed via vanilla JS means (e.g. document.body.removeChild(...)) before route switch.

Which browser are you using? (if relevant)

Arc (Version 0.96.0 (38004)), Chromium Engine Version 111.0.5563.146

How are you deploying your application? (if relevant)

No response

aloeugene commented 1 year ago

Just for a little bit of context for the potential "why the hell would anybody do that?" questions.

I'm working on implementing an online news media website and it sometimes requires doing weird things with ad providers' scripts in order for them to integrate correctly with out Next.js application. This is one of the behaviors we need to support in order for ad provider scripts to work correctly between SPA-specific page navigations.

Requirements here are:

For now, I had to implement it via an ugly custom React hook that handles adding/removing the regular html <script> element to the page via useEffect means. It's kinda sad to look at and I'd like to just be able to use an out-of-the-box solution which takes 2-3 lines instead of the 30+ lines hook...