faceyspacey / react-universal-component

🚀 The final answer to a React Universal Component: simultaneous SSR + Code Splitting
MIT License
1.7k stars 80 forks source link

🐞 Duplicated chunk files with `-css` suffix are emitted #158

Closed ivan-aksamentov closed 5 years ago

ivan-aksamentov commented 6 years ago

Webpack emits unnecessary files: CSS with duplicated content and empty JS files (containing only webpack wrapper)

Details

I have the following file structure (similar to what a typical Next.js app might have):

src/pages/Home.css
src/pages/Home.js

Inside Home.js I import .css file like this:

import './Home.css'

and I get duplicates emitted by webpack during client compilation:

.dev/client/pages/Home.css
.dev/client/pages/Home.js
.dev/client/pages/Home-css.css
.dev/client/pages/Home-css.js

My hypothesis is that someone somewhere tries to import Home.css as if it were Home.css.js. Webpack should only resolve .js files, and not .css:

resolve: { extensions: ['.js'] },

so I don't understand what's going on.

Duplicates disappear if I move .css files into a separate directory, for example:

src/styles/Home.css
src/pages/Home.js

so that CSS import becomes extensionless:

import '../styles/Home'

After some more digging

(1) These suffixed -css.* output files are not used anywhere and never requested by the browser. (2) The suffixed -css.js file contain only an empty webpack wrapper function. (3) Contents of .css and -css.css files are byte-to-byte identical (except for source map comments, which differ in filenames). (4) If I create a file called Home.jsx (same name, different extension) and include into my Home.js as:

import HomeJSX from './Home.jsx'

, the chunk will be called Home-jsx, which I think is desired and expected.

(5) If I create a file called HomeSweetHome.jsx and include into my Home.js as:

import HomeJSX from './HomeSweetHome.jsx'

, the new chunk will be called HomeSweetHome-jsx, which is not desired, but adding '.jsx' to webpack resolve.extensions makes chunk name a plain neat HomeSweetHome. This does not happen with CSS chunks if I add '.css' to resolve.extensions. Now, what I want is that trick to work for .css files, so that duplicates would be merged into the page chunk.

I think there might be a problem with how react-universal-component or babel-plugin-universal-import create chunk names from file paths to universal components and to the children of these.

Any ideas why dupes happen and how to fix it? Is it related to extract-css-chunks-webpack-plugin or webpack-flush-chunks?

Issue is present in both, development and production, with or without CSS modules.

Repro:

Any commit will do in this repo, here is the last one:

https://github.com/ivan-aksamentov/reactlandia-bolerplate-lite/tree/781f3d0618770016c26b3a25ef23e746700e41d8

Quick start on Unix:

git clone https://github.com/ivan-aksamentov/reactlandia-bolerplate-lite.git
cd reactlandia-bolerplate-lite
git checkout 781f3d0618770016c26b3a25ef23e746700e41d8
npm install
npm run dev

Ctrl+C

find .dev/

You should observe that there are way too many files, because there are unnecessary ones with -css suffixes.

Source files of interest:

Versions

Ubuntu 16.04
node 10.11
npm 6.4.1
"@babel/core": "^7.1.0",
"webpack": "^4.19.1",
"react": "^16.5.2",
"react-universal-component": "^4.0.0-alpha.0",
"babel-plugin-universal-import": "^4.0.0-alpha.3",
"extract-css-chunks-webpack-plugin": "^3.1.2-beta.6",
"webpack-flush-chunks": "^3.0.0-alpha.1"
"redux-first-router": "^1.9.19",
"redux": "^4.0.0",

P.S. it is basically a copypasta of an issue in the aforementioned repo. I duplicate here for better visibility.

lutzk commented 6 years ago

afaik that is because with webpack import() you create an asyncContext webpack cant know during build wich files will be used later - so it compiles everything in there solution: just create a dir with all dynamic imports like here: https://github.com/faceyspacey/universal-demo/tree/master/src/components - but no other files

or alternative: you can keep you folder structure and create one more dir e.g: dynamicContext or what fits you and in there you re export you dynamic imports like: dynamicContext/Home.js: export default from 'src/pages/Home.js'; and then you use that file to dynamic import your Home component

i am not sure about but i think with import() you should be able to give a regex filter in a magic coment - if import() would be used directly

ScriptedAlchemy commented 5 years ago

Gonna close this as it’s not hurting anyone and can be fixed with Webpack itself