gregberge / loadable-components

The recommended Code Splitting library for React ✂️✨
https://loadable-components.com
MIT License
7.69k stars 382 forks source link

SSR: ChunkExtractor tries to load unexisting script #220

Closed ElForastero closed 5 years ago

ElForastero commented 5 years ago

🐛 Bug Report

During SSR, chunks generated with webpack and ones that loadable tries to load have different names.

It happens when we have template literals in our import paths. It this case webpack generates chunks with one extra component name in the end. Like Path-To-Component/Component-Component. 🤷‍♂️

To Reproduce

platform is used to segrerate desktop and mobile templates.

const About = loadable(() => import(`Pages/Static/${platform}/About`));

webpack.config.js

{
  output: {
    chunkFilename: 'js/[name].[chunkhash:8].chunk.js',
}

With this setup webpack generates the following chunks structure:

├── Pages-Static
│   ├── desktop-About-About.a2ddc8ae.chunk.js
│   ├── desktop-Feedback-Feedback.83cc2d57.chunk.js

loadable-stats.json contains correct paths and names:

image

But for some reason, ChunkExtractor tries to load files with different names. This happens only during SSR.

node:28532) UnhandledPromiseRejectionWarning: Invariant Violation: loadable: cannot find Pages-Static/desktop-About in stats
    at invariant (/Users/forastero/www/powerthesaurus-client/node_modules/@loadable/component/dist/loadable.cjs.js:13:15)
    at ChunkExtractor.getChunkGroup (/Users/forastero/www/powerthesaurus-client/node_modules/@loadable/server/lib/ChunkExtractor.js:166:36)
    at one (/Users/forastero/www/powerthesaurus-client/node_modules/@loadable/server/lib/ChunkExtractor.js:190:30)
    at /Users/forastero/www/powerthesaurus-client/node_modules/@loadable/server/lib/ChunkExtractor.js:34:12
    at arrayMap (/Users/forastero/www/powerthesaurus-client/node_modules/lodash/lodash.js:639:23)
    at map (/Users/forastero/www/powerthesaurus-client/node_modules/lodash/lodash.js:9556:14)
    at Function.flatMap (/Users/forastero/www/powerthesaurus-client/node_modules/lodash/lodash.js:9259:26)
    at getAssets (/Users/forastero/www/powerthesaurus-client/node_modules/@loadable/server/lib/ChunkExtractor.js:33:49)
    at ChunkExtractor.getChunkAssets (/Users/forastero/www/powerthesaurus-client/node_modules/@loadable/server/lib/ChunkExtractor.js:203:14)
    at ChunkExtractor.getMainAssets (/Users/forastero/www/powerthesaurus-client/node_modules/@loadable/server/lib/ChunkExtractor.js:294:23)

I'm not sure if this is a bug with @loadable or with webpack itself. 🤔

Link to repl or repo (highly encouraged)

I'm ready to reproduce the bug, if this is not something ridiculous. Maybe I'm doing something wrong.

Run npx envinfo --system --binaries --npmPackages @loadable/component,@loadable/server,@loadable/webpack-plugin,@loadable/babel-plugin --markdown --clipboard

Paste the results here:

## System:
 - OS: macOS 10.14.3
 - CPU: (8) x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
 - Memory: 405.02 MB / 16.00 GB
 - Shell: 5.3 - /bin/zsh
## Binaries:
 - Node: 11.7.0 - /usr/local/bin/node
 - Yarn: 1.13.0 - /usr/local/bin/yarn
 - npm: 6.5.0 - /usr/local/bin/npm
 - Watchman: 4.9.0 - /usr/local/bin/watchman
## npmPackages:
 - @loadable/babel-plugin: ^5.0.1 => 5.2.2
 - @loadable/component: ^5.1.2 => 5.2.2
 - @loadable/server: ^5.1.3 => 5.4.0
 - @loadable/webpack-plugin: ^5.0.2 => 5.4.0
gregberge commented 5 years ago

Hello @ElForastero, I think it has been fixed in #219. It will be fixed in next release.

ElForastero commented 5 years ago

After update to 5.6.0 chunks are built without subdirectories, but the problem with chunk names during SSR is still present.

So the issue is still actual.

## System:
 - OS: macOS 10.14.3
 - CPU: (8) x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
 - Memory: 807.32 MB / 16.00 GB
 - Shell: 5.3 - /bin/zsh
## Binaries:
 - Node: 11.7.0 - /usr/local/bin/node
 - Yarn: 1.13.0 - /usr/local/bin/yarn
 - npm: 6.5.0 - /usr/local/bin/npm
 - Watchman: 4.9.0 - /usr/local/bin/watchman
## npmPackages:
 - @loadable/babel-plugin: ^5.0.1 => 5.6.0
 - @loadable/component: ^5.1.2 => 5.6.0
 - @loadable/server: ^5.1.3 => 5.6.0
 - @loadable/webpack-plugin: ^5.0.2 => 5.5.0
ElForastero commented 5 years ago

Currently, we solved this issue by not using template literals inside dynamic import paths.

Like this:

image

ElForastero commented 5 years ago

@neoziro Probably it should be reopened. 🤷‍♂️

valeriivolkovskyi commented 5 years ago

same issue, any updates?

gregberge commented 5 years ago

Hi @Volkovskiy, can you explain your specific case?

Also others could answer these three questions. This way we could try to know what is exactly the problem.

cevou commented 5 years ago

I do have the same issue:

cevou commented 5 years ago

I think the issue is here: https://github.com/smooth-code/loadable-components/blob/8decb0d73b1e1f1233d731ca7d1469f61d2b4231/packages/babel-plugin/src/properties/chunkName.js#L121

The pre and postfix of the template literal are added to the [request] keyword. However, this is already done in the userRequest which replaces [request] in the webpack ContextModule. Because of that the postfix is added twice.

If I replace the above line with just [request] everything works fine.

gregberge commented 5 years ago

Thanks @cevou for investigating! Could you submit a PR to fix it? Also we should try to find a way to write automated tests about it.

cevou commented 5 years ago

I think it's an issue, that the babel-plugin always overrides the webpackChunkName - even if the user specifies a custom name it will be overwritten.

I don't have an immediate solution, but if it would be possible to get rid of the whole chunkName function (it is only used for the chunkExtractor.addChunk(...)) and somehow use the actual chunkNames generated by webpack based on the user's configuration it would remove a source of error.

If we change the chunkNameFromTemplateLiteral function now and webpack changes any of their code it might not be compatible again.

gregberge commented 5 years ago

I just tested it in the server-side-rendering example:

const Sub = loadable(props => import(`./letters/${props.letter}/test`))

<Sub letter="Z" />

I don't have any problem:

<script async data-chunk="letters-Z-test" src="/dist/web/letters-Z-test.js"></script>

I close it for now, please submit a new issue with a good reproducible example if you experience the bug.

akagomez commented 5 years ago

Thanks for looking into it @neoziro.

I can confirm I've encountered this issue also (and was able to work around it with @cevou's fix).

I'll try reproducing it with the provided server-side example.