Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React/nextJS: How to debug different nodes of SSR react application?

I'm running a nextJS application, which is running SSR.

But as I do get the error:

Warning: Did not expect server HTML to contain a <div> in <div>.

So there seems to be a difference between the server-side and the client side nodes. How can I find those differences?

This is the repo of an example app:

https://github.com/jaqua/nextjs-app

Just run npm install and npm run dev

like image 701
user3142695 Avatar asked Dec 01 '18 13:12

user3142695


People also ask

How do I debug Next.js SSR?

Now go to the Debug panel ( Ctrl + Shift + D on Windows/Linux, ⇧ + ⌘ + D on macOS), select a launch configuration, then press F5 or select Debug: Start Debugging from the Command Palette to start your debugging session.

Is Next.js SSR by default?

However, in the past, I did not want to use it for all my React apps. Next. js does not work without server-side rendering (SSR) by default.

Why Next.js is better than React?

The web apps built using NextJS are very fast. The web apps built using ReactJS are slow as compared to NextJS. Next doesn't require offline support.

Is React SSR or CSR?

In fact, it was Facebook's release of the React library that popularised a CSR approach to applications by making it more technologically accessible. On the other hand, a web-based app serving mainly static content, like this website, would be expected to opt for an SSR approach.


1 Answers

As comparing two html manually can be rather cumbersome depending on the size of your page, it's advised to first assess what could be wrong rather than brute-forcing. From my experience in 99% of the cases an SSR mismatch occurs when you either:

  • Included and rendered a Component which doesn't behave the same way on the client and the server (e.g they use global variables to determine where the code is being run and conditionally render elements based on that). For example there was a clipboard module that would only work on the client because it would use a variable of window.
  • Rendering of data fetched from an asynchronous source which is only present on either the server or the client. You need to make the same data available for both during the initial render.

If nothing comes out to mind after this, you need to proceed by elimination. In case the error occurs on every page, it is likely to be a result of a misconfiguration of the server. For example, are you doing your own renderToString? Double check you didn't add an extra nested div in there, the string should be right inside the element you mount React on.

If that is not the case, try to extract one by one the components you are rendering, and you should be able to narrow down pretty quickly which is causing your issue.

Also keep in mind that you would need to restart your server every-time you make a change (unless you have a nodemon or similar config reloading the server-side code when you modify your source) for it to be applied!


As a last resort, you could potentially make your own diff between the server response and the client first render.

1) Open your console from your site, and paste the following:

console.log(document.documentElement.innerHTML)

2) Click on the Copy button, and paste that in a client.html file

3) Now run in your terminal:

curl YOUR_URL > server.html 

4) It's likely the server will return you a minified version of your html, so you need to indent it in order to make it match with your client html, use something like this for that purpose.

5) Once you've done this, you can now run the actual diff in your terminal:

diff server.html client.html

This will list you every part of the files that differ between each other. You can ignore diffs related to Javascript as the indenting will most likely be bad anyway, but concentrate on the html ones, where you might be able to spot differences and infer what is going wrong.


In your case, your translation system is likely to be the root cause of the issue. I would advice to follow more standard practices rather than next-i18next which seem pretty new and more likely to have problems. Someone else apparently also has an issue with SSR, and to be honest stuff like this is quite scary.

I know it can look a bit troublesome to setup, but here is my own i18n config which can be required either on the server or the client provided you specify a global variable to determine one which environment you are (here __BROWSER__).

import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import { reactI18nextModule } from 'react-i18next'

i18n
  .use(require(__BROWSER__ ? 'i18next-xhr-backend' : 'i18next-node-fs-backend'))
  .use(LanguageDetector)
  .use(reactI18nextModule)
  .init({
    fallbackLng: 'en',
    ns: ['translations'],
    defaultNS: 'translations',

    interpolation: {
      escapeValue: false,
    },

    react: {
      wait: true,
    },

    backend: {
      loadPath: __BROWSER__
        ? '/locales/{{lng}}/{{ns}}.json'
        : require('path').join(__dirname, '/locales/{{lng}}/{{ns}}.json'),
    },
  })

export default i18n

You simply need to use the middleware, serve the locales from your server so the client can load them from xhr and have the I18nextProvider require the i18n instance. The full SSR docs are here.

like image 137
Preview Avatar answered Oct 06 '22 14:10

Preview