The two solutions to loading external scripts in Next.js seem to be to:
- 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
- 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.