Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to include dom-manipulating scripts into SSR Next.js App

I am experiencing following error:

Warning: Text content did not match. Server: "But I want to be altered by the client" Client: "Test"
    in div (at pages/index.tsx:17)
    in div (at pages/index.tsx:6)
    in HomePage (at _app.tsx:5)
    in MyApp
    in Container (created by AppContainer)
    in AppContainer

... with the following setup:

A NextJS App Component:

function HomePage() {
  return (
    <>
      <div id="test-div">I am rendered on the server.</div>
      <script src="http://localhost:8080/bundle.js"></script>
    </>
  );
}

export default HomePage;

(Note: The URL http://localhost:8080/bundle.js assumes webpack-dev-server is running and serving that resource)

The included "example" script:

const element = document.getElementById('test-div') as any;
element.innerHTML = 'But I want to be altered by the client';

In a simple setup I would just have a static html file, declaring a div element and including the "example" script.

But I would like to use NextJS, because I want to render dynamic (SSR) content into the page (eg. Text contents from a cms).

I noticed, that sometimes (if script execution takes some more ms of time), there is no error. Just do something time consuming in the example script.

Another hacky approach is to use setTimeout in the example script. I don't want to do that until I know why this is happening:

setTimeout(function() {
  const element = document.getElementById('test-div') as any;
  element.innerHTML = 'But I want to be altered by the client';
}, 20);

like image 317
Edgar Alloro Avatar asked Apr 18 '20 22:04

Edgar Alloro


People also ask

How do I use SSR in NextJS?

Pages on which the data have to change for a particular type of request, those pages use SSR as data is not the same for every request and may vary with it. To use SSR for a page, we need to export an async function called “getServerSideProps“. This async function is called each time a request is made for the page.

CAN node js manipulate DOM?

You can't use code running in Node. js to manipulate the DOM that a browser has built, or directly handle a click on a button rendered in the browser because both the button and DOM will be in the browser and not in the Node. js program.

Should I use NextJS without SSR?

Next. js does not work without server-side rendering (SSR) by default. I preferred using a non-SSR solution like Create React App, when my app did not require SSR, because SSR had caused me so many unnecessary problems. Turns out Next is still 💯/💯, even if you only need index.

Can you use React components in NextJS?

When setting runtime to 'experimental-edge' , the server will be running entirely in the Edge Runtime. Now, you can start using React Server Components in Next. js.

How does next JS support SSR?

How Next.js supports SSR? By default, Next.js pre-renders every page. This means that Next.js generates HTML for each page in advance, instead of having it all done by client-side JavaScript. Pre-rendering can result in better performance and SEO. Each generated HTML is associated with minimal JavaScript code necessary for that page.

What is the best way to add a script to next?

**EDIT: As of Next 11, I recommend using Next's custom Script Component. When building out a Next.js website, it is a very common requirement to include a third party <script> to some of the website's pages. For example, you may need to include a script that supports a chatbot, or scheduling tool, or maybe just a simple widget.

What is Client Side Rendering (SSR)?

In Client Side Rendering, when a user requests a server to load a web page, the server sends the request to the browser. the browser then loads the JavaScript and executes react and displays a interactable page to the user. How Next.js supports SSR? By default, Next.js pre-renders every page.

Do I need to include a <script> in my website?

When building out a Next.js website, it is a very common requirement to include a third party <script> to some of the website's pages. For example, you may need to include a script that supports a chatbot, or scheduling tool, or maybe just a simple widget.


1 Answers

Next.js 11.0.0 and above

You can use Next.js Script component to load third-party scripts.

// pages/index.js
import Script from 'next/script'

function Home() {
  return (
    <>
      <Script src="https://www.google-analytics.com/analytics.js" />
    </>
  )
}

With next/script, you can define the strategy property and Next.js will optimize loading for the script.

Before Next.js 11.0.0

Browser and document, window objects are not available during server-side rendering.

You can initialize scripts that manipulate DOM after React component did mount.

useEffect(() => init(), [])

To add an external script you can do the following:

useEffect(() => require('../babylon.js'), [])

To include a script from another server you can add a script tag:

useEffect(() => {
  const script = document.createElement("script");
  script.src = "http://localhost:8080/bundle.js";
  script.async = true;
  document.body.appendChild(script);
},[])

If you're adding DOM listeners you would also need to do cleanup.

Using the Effect Hook

Effects with Cleanup

like image 112
Nikolai Kiselev Avatar answered Oct 22 '22 09:10

Nikolai Kiselev