3

I've migrated an old website to Nextjs and i need the scripts to load every time a page component is loaded. But if i use the next/link component to navigate between pages, the scripts run only the first time the page is loaded. I've tried putting the inside the Head component in every page, but it still doesn't work. There is a workaround for this?

Julian Gr
  • 93
  • 1
  • 9

2 Answers2

4

The two solutions to loading external scripts in Next.js seem to be to:

  1. Load them using a combination of _document.js and next.config.js

_document.js

          <script
            type="text/javascript"
            dangerouslySetInnerHTML={{ __html: process.env.jquery }}
          ></script>

next.config.js

const fs = require("fs")

module.exports = ({
  env: {
    jquery: fs.readFileSync("./public/js/jquery.js").toString(),
  }
})

Reference: https://stackoverflow.com/a/65349130/2167762

  1. Load them using React's useEffect hook, like with a custom useScript hook /pages/index.js
import { useEffect } from "react"

const useScript = (url) => {
  useEffect(() => {
    const script = document.createElement("script")

    script.src = url
    script.async = true

    document.body.appendChild(script)

    return () => {
      document.body.removeChild(script)
    }
  }, [url])
}

//export default function Home({ posts }) {
export default function Home() {
  useScript("js/jquery.js")
  return <p>Component</p>
}

Reference: https://stackoverflow.com/a/34425083/2167762

So which should you use?

The first seems to work "great" but is actually quite buggy -- I only get the JavaScript working sometimes after refreshing in development, and never in production.

(This would correspond to your problem with the scripts not loading when navigating with <Link>.)

The latter seems to work much better, although sometimes when I refresh in dev the scripts seem to load out of order, potentially causing runtime errors.

In production, however, the scripts seem to load & run consistently. I haven't explicitly tested <Link>, but it should work with the useEffect() method.

3

It'll be helpful to see the scripts you're loading. I faced a similar issue whiles using styled components in the version 9 of Nextjs. It had something to do with the server side rendering. Usually, using the Head should work. ie.

import Head from "next/head";

const HeadComponent = () => {
  return (
    <>
      <Head>
        <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
      </Head>
    </>
  );
};

You could also choose to dynamically import the scripts to the root of your app using:

import dynamic from "next/dynamic";

function MyApp({ Component, pageProps }) {
    const Script = dynamic(() => import("../Script"));
    return (
        <>
            <Component {...pageProps} />
            <Script />
        </>
    );
}

export default MyApp;

I realised that the above makes all resources load in Nextjs

ninsau
  • 518
  • 2
  • 5
  • 18