Home > Software design >  Why does the next.js Script tag with the beforeInteractive strategy don't load thirdParty scrip
Why does the next.js Script tag with the beforeInteractive strategy don't load thirdParty scrip

Time:05-22

I try to understand how the next.js Script tag with the strategy beforeInteractive works. For testing i just used lodash. But i keep getting a ReferenceError: _ is not defined. I thought when a script is loaded with beforeInteractive it should be globally available inside my page Component since it get injected into the initial Html from the server and i could use it for example in the useEffect hook to alter a div. Can someone explain to me why it's not working or what i'm doing wrong? I don't installed it via npm because im trying to figure out how it works.

I have a simple _document.js and i added a Next.js script tag with the strategy beforeInteractive to this _document.js. The next.js docs says: This strategy only works inside _document.js and is designed to load scripts that are needed by the entire site (i.e. the script will load when any page in the application has been loaded server-side).

import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
        <Script
          src="https://unpkg.com/[email protected]"
          strategy="beforeInteractive"
        ></Script>
      </body>
    </Html>
  )
}

Then i have a simple page Component inside the pages folder. I added the getServerSideProps function to use ServerSideRendering.

If you export a function called getServerSideProps (Server-Side Rendering) from a page, Next.js will pre-render this page on each request using the data returned by getServerSideProps.

import Head from 'next/head';
import {useEffect, useState} from 'react';

const TestComponent = () => {
    const [change,setChange] = useState('not changed');

    useEffect(()=> {
        console.log(_);
        setChange(_.join(['one','two'],' - '));
    });

    return (
        <>
            <Head>
                <title>Test</title>
            </Head>
            <div>{change}</div>
        </>
    );
};

export async function getServerSideProps(context) {
    return {
      props: {},
    }
  }

export default TestComponent;

CodePudding user response:

First and foremost, I'm failing to see virtually any reason you'd want to do this, when you can (and should) simply use install it to node_modules. You're also going to possibly run the risk of the bundle having issues if the library type isn't a module and the next configuration requires a module.

Solution based on the question:

There's two ways. Firstly, see the docs on this exact thing.

Please use the above method mentioned in the docs.

If that's not an option for whatever reason...

The second is a less than ideal, but working solution.

Create a folder for your static files. Ex: <root>/static/js/hello.js. Then in your _document file,

<script type="text/javascript" src="/static/hello.js"></script>

CodePudding user response:

Putting aside the fact that you should be importing Lodash as a node module, there does seem to be an issue when using next/script in _document (no matter what the external script actually is).

As an alternative, you can use the <script> tag directly in the _document's <Head> with the defer property. This closely matches what the next/script would output.

import { Html, Head, Main, NextScript } from 'next/document'

export default function Document() {
    return (
        <Html>
            <Head>
                <script
                    type="text/javascript"
                    src="https://unpkg.com/[email protected]/lodash.js"
                    defer
                ></script>
            </Head>
            <body>
                <Main />
                <NextScript />
            </body>
        </Html>
    )
}
  • Related