faceyspacey / react-universal-component

🚀 The final answer to a React Universal Component: simultaneous SSR + Code Splitting

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ReactDOM.hydrate Expected server HTML to contain a matching <div> in <div>

primozs opened this issue · comments

I noticed this issue in my app and then checked universal-demo example.
universal-demo has the same issue.
https://github.com/faceyspacey/universal-demo
screenshot 2019-01-15 at 12 50 30

same with
https://github.com/ScriptedAlchemy/redux-first-router-demo

Demo is outdated but check the Babel plugin and RUC docs. Usually because you need to enable the ignoreBabelRename

@ScriptedAlchemy Hi,
I read the docs, i read the old issues. I experimented with loadingTransition, ignoreBabelRename, chunkName. but no results.

I am sorry to bother you, but would you maybe have time to update one of the demos?
https://github.com/faceyspacey/universal-demo
https://github.com/ScriptedAlchemy/redux-first-router-demo
Cheers

Look on my profile for a repo called Icarus, its a great example and works as expected. Ill try and update the demos this weekend

Thank you for the info and your work!
Cheers

@primozs yeah this is pretty much chunk flushing issues.

I changed alot to try it out, even deleted my node modules and package locks.

all i really did was fiddle with the ignore babel rename option.

Ill probably roll a major release of the plugin and disable the renames alltogether

check the open PR - on universal-demo

okay, actually, im releasing a major version bump of babel-plugin-universal-import.

The ability to rename will be gone, followed by the removing the rename option from RUC.

RUC was merged into react a while back. And is now known as Suspense. Unless Suspense doesnt cater for SSR, ill likely rebuild RUC as yet another HOC to react. They kept most my api so its easy enough to fix the issue

@ScriptedAlchemy I will try now.

okay this was actually a crazy one˜. i thought i was going insane.

if you saw me UniversalComponent that i have in the demos, you can pass a function thats an import or pass a string which then activates import('./${page}')

Now... in webpack 4, this creates a import, but webpack will hyphenate the folders, however, this gets in the way of standardizing the request paths for FE and BE.

So what exactly is going on here?!?

ill tell ya. if i dynamic import(../src) then i get src/components-Rudy.chunk.js but we wanted src/components/Rudy.chunk.js

why does this happen? because as we import a folder, itll add all the files in other folders to the name. however if we pass import() as a prop, then theres not much to glob together.

this one is hard, and why i used dashes in the first place.

Solutions:

move the universal utility file down to the components folder.

use import() as a prop on universal, not a string

How do we resolve this? eh, harder to solve. Ill likely just push both - and / to the chunk report on the server (the problem is resolution) then it'll try and cater for both possibilities.

@ScriptedAlchemy Cheers
I have updated

package.json
"babel-plugin-universal-import": "^4.0.0",

yarn.lock
babel-plugin-universal-import@^4.0.0:
  version "4.0.0"
  resolved "https://registry.yarnpkg.com/babel-plugin-universal-import/-/babel-plugin-universal-import-4.0.0.tgz#e104049e8bd1ff3e028bbfb0a358554c3e28e347"...

In my universal load function i commented out everything to basic config so I have only this

in its one file
const loadComponent = (func, opts = {}) =>
  universal(func, {
    loading: Loader,
    error: PageError
...
  });

in route switcher file
const UniversalComponent = loadComponent(({ page }) =>
  import(`../pages/${page}`)
);

I have my individual pages and routes in their own package modules
and in the main src app I have a dir called pages where I only import and export 
individual page from its individual package. This files are then loaded 
with UniversalComponent. Could this be the issue. 

I have restarted the server so for sure server build should have the same code

from the server I get

[FLUSH CHUNKS]: Unable to find pages-SomePage in Webpack chunks. Please check usage of Babel plugin.

client entry index.js

my main client render function is async this probably should not be the problem

const render = async Component => {
... redux-first-router initial dispatch
.... all the providers
  if (rootElement.hasChildNodes) {
   // in this case SSR i get 
   // Warning: Expected server HTML to contain a matching <span> in <div>.
   // the last time i went down the tree and remove out everything I came to notice RUC was making this warning
    ReactDOM.hydrate(content, rootElement);
  } else {
    ReactDOM.render(content, rootElement);
  }
}

when everything is setup and after redux-offline persist callback i finally render 
render(Main).then(() => {
   ... and more stuff
});

Yes, I was following Suspense and wondering about the connection and how it will all play out also with SSR thank you for the info!

okay this was actually a crazy one˜. i thought i was going insane.

if you saw me UniversalComponent that i have in the demos, you can pass a function thats an import or pass a string which then activates import('./${page}')

Now... in webpack 4, this creates a import, but webpack will hyphenate the folders, however, this gets in the way of standardizing the request paths for FE and BE.

So what exactly is going on here?!?

ill tell ya. if i dynamic import(../src) then i get src/components-Rudy.chunk.js but we wanted src/components/Rudy.chunk.js

why does this happen? because as we import a folder, itll add all the files in other folders to the name. however if we pass import() as a prop, then theres not much to glob together.

this one is hard, and why i used dashes in the first place.

Solutions:

move the universal utility file down to the components folder.

use import() as a prop on universal, not a string

How do we resolve this? eh, harder to solve. Ill likely just push both - and / to the chunk report on the server (the problem is resolution) then it'll try and cater for both possibilities.

I will try

@ScriptedAlchemy Hura! :)

It started to work by changing my client app entry files structure a bit

packages
   | ....
src
   |- client
       |- components
          |- App
          |- I18nLoader  
       |- pages
          |- Dashboard.js
          |- ....
          |- Switcher.js
          |- loadComponent
   | index.js
   | Main.js


1. I moved Main.js with route Switcher to root
2. pages (imports exports) from other packages are still in pages dir eg.: Dashboard
3. Switcher and universal component load I moved from components to pages

import in Switcher looks like this
const UniversalComponent = loadComponent(({ page }) => import(`./${page}`));

Thank You very much for your help!!
Cheers

The best thing is to get rid of that import(.${}) entirely. And just pass as a function prop. Then page()

This also makes builds faster because you are not blindly importing everything.

On a side note. You raised an important issue. What I’m going to do is allow flush chunks to resolve or try to resolve chunks by flipping the name between slashes and dashes.

Thank you for this info!