Single-file configuration emits JS assets in its own chunk group
notpeelz opened this issue ยท 37 comments
Webpack issue here webpack/webpack#7300
I tried using the "Extracting all CSS in a single file" configuration from the README.
It works fine for the most part, except that the className mappings (created by css-loader ) are now loaded in a new js file.
I'm not sure if this is a limitation of MCEP or a side-effect of the new webpack splitChunks feature.
Is there any way to have the css mapping modules merged into their parent chunks?
Possibly related to #41
limitation of the splitChunks feature. It may need a type filter.
You should be able to workaround it by passing a function to test:
test: module => module.nameForCondition &&
/\.css$/.test(module.nameForCondition()) &&
!/^javascript/.test(module.type)That test rule doesn't get rid of the js file but it shrinks it to 61 bytes:
(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);Any idea why it doesn't get rid of the JS file entirely?
I also ran into this same problem - the 61 byte chunk is small but html-webpack-plugin will attempt to inject it into the HTML.
@yyx990803 that's expected. You can exclude the file by manually handling the asset injection (and filtering out JS style assets), but then the SPA doesn't load and fails silently (at least for me it does).
@louistakepillz yeah, I ended up with a temporary hack: prepending the content of the chunk to the main entry file.
@louistakepillz i noticed that removing enforce: true results in no extra chunks being generated for css mappings, not sure if it has any negative impact though and why it's needed in the first place ๐
@fmal taking out enforce: true fixes everything for me as well.
Removing enforce: true doesn't work for me because, while everything gets put into one CSS file:
- It is based on the bundle name not the split chunk name.
- None of the defined CSS chunks get split into separate files. They're all fed into the CSS file named after the entry.
I'm looking at writing a plugin (as a proof-of-concept) that taps into compilation.hooks.beforeChunkAssets to attempt to remove the extra javascript chunks.
Would that be the right approach or would there be a better one?
Sorry, to be clearer I'm doing that to get access to the chunk template to tap into template.hooks.renderManifest because that's where it appears the javascript file is being added.
Though I guess ideally there'd be a way to not even populate the file at all.
/cc @sokra
I got a bit further with this. I was able to figure out how to remove the generated assets but unfortunately they still get added to the deferredModules list in the entry. I'm think it is because chunks exist for them and they get generated into multiple assets (one .css and one .js). I very well could be misunderstanding how that works, though.
I'm not sure how to go about fixing that.
Example of what I have done here: https://github.com/thecrypticace/webpack-css-chunks-test/blob/plugins/build/RemoveStyleScriptChunksPlugin.js
For me, the app loads even without the tiny chunk included in the page. I'm not sure why though. It could be that I'm using runtimeChunk: 'single' but this is a guess.
I just add npm script
"postbuild": "echo $'\n (window.webpackJsonp = window.webpackJsonp || []).push([[0], []]);' >> 'dist/index.js'"
I'm using script-ext-html-webpack-plugin inline the style.js file. another temporary fix.
new ScriptExtHtmlWebpackPlugin({
inline: /styles.*\.js$/,
defaultAttribute: 'defer',
})I'm also seeing this issue. Does anyone have a solution? This seems unsolved.
It is unsolved, but I believe webpack/webpack#7300 is the real culprit. It is in the webpack 4.x milestone.
Does it "work for the most part" though?
Either way it would be helpful to have TWO examples:
- Extract a single CSS file for the entire build
- Extract one CSS file per entry point (I'm not sure what to name those, chunks, or bundles)
With webpack3 + ExtractTextPlugin I had 3 entry points, "common", "page1" "page2" (to simplify). Common bundle was used across the site. The others contained only the css / js for the Vue components used on those parts of the site.
So with Webpack 4 I don't want just one CSS file, I want one CSS file for each bundle. I tried many snippets of code, and of those that worked, they only resulted in a single file, and did not concatenate css per bundle. (edit: or is that a vue-loader v15 issue?)
Same issue
Any update about this?
@louistakepillz yeah, I ended up with a temporary hack: prepending the content of the chunk to the main entry file.
@yyx990803 how did you exclude it from html-webpack-plugin ?
Really hope this can be fixed soon. Meanwhile, here's another horrible postbuild script that may help someone:
const fs = require('fs');
const path = require('path');
const distDir = path.resolve(`DIST_DIR_HERE`);
let mainJs;
let stylesJs;
try {
fs.readdirSync(distDir)
.filter(file => file.startsWith('main') || file.startsWith('styles'))
.forEach(file => {
if (file.startsWith('main')) {
mainJs = path.resolve(`${distDir}/${file}`);
} else {
stylesJs = fs.readFileSync(`${distDir}/${file}`);
}
});
if (mainJs && stylesJs) {
fs.appendFileSync(mainJs, stylesJs);
}
} catch (e) {
throw e;
}
Any idea how to solve this? Can we try something...?
I also ran into this same problem - the 61 byte chunk is small but
html-webpack-pluginwill attempt to inject it into the HTML.
+1
Removing enforce: true also did the trick for me.
I find it personally frustrating even after holding off upgrading to v4 for almost 2 years this issue still hasn't been fixed. It appears fixed now in v5, but there is no release date for that yet.
I can appreciate Webpack is a very complex beast, however splitting css from the bundle is not a unique scenario or edge case - it's a basic requirement for build tools. It does make you question given how complex Webpack has become even with basic requirements the maintainers are struggling to efficiently maintain it anymore. I'm sure I'm not the only one pondering on whether alternative build tools have the same fundamental problems.
In any case, many developers rely on webpack as a build tool in their applications so it would be great if there could be more transparency and assistance from the maintainers in finding solutions to these long-oustanding issues that many developers experience with Webpack rather than letting them drag on for years.
Already solved for webpack@5, we really have a lot of problems and little help from other developers, this does not mean that we do not see problems, it means that we do not have enough time, so we are happy for any help
@evilebottnawi - Completely understand, but is that change something we can either put into a quick custom plugin for v4 or back fill to v4? I highly doubt that since v5 isn't even officially out yet that many of the plugins we are all using would be updated to be compatible out of the box currently.
That said I posted what I thought was a solution last night but couldn't work out how to prevent all the css modules from being added to deferredModules and loading the webpack JSONP async loading chunk in our bundle. That breaks our JS even though our CSS builds correctly.
Setting enforce: true on the splitChunks for our CSS files causes that to occur, setting it to false causes all CSS to be bundled into a single file named the same as you main bundle.
I'd like to enforce and prevent the async modules.
Where in the compilation could I clear out that list of deferredModules and I'd be able to code around this for now.
I also ran into this same problem - the 61 byte chunk is small but
html-webpack-pluginwill attempt to inject it into the HTML.
can you show the method ? thank you
emmm, 2 years passed ๐
Partial fixed webpack/webpack#7300 (comment) (for webpack@5), but need to be improved more on webpack side, closed here, nothing to do more
@evilebottnawi technically not true, those of us who can't upgrade until our dependencies have done so are still stuck without a solution.
At least answer the question I last posed on how to complete the workarounds
I posted what I thought was a solution last night but couldn't work out how to prevent all the css modules from being added to deferredModules and loading the webpack JSONP async loading chunk in our bundle. That breaks our JS even though our CSS builds correctly.
Setting enforce: true on the splitChunks for our CSS files causes that to occur, setting it to false causes all CSS to be bundled into a single file named the same as you main bundle.
I'd like to enforce and prevent the async modules.
Where in the compilation could I clear out that list of deferredModules and I'd be able to code around this for now.
At least with that I could probably make a webpack4 compatible plugin to fix the issues until we can safely migrate to v5.
I don't know if it helps, but when I remove the extension from the output - the file seems to compile as it should.
filename: 'format/[name]'
Then, once I configure it to be ".js", it's getting compiled empty.
filename: 'format/[name].js'
I created a plugin that worked for us until the webpack 5 upgrade. If you can't upgrade to webpack 5, give this a shot: https://github.com/michaeldurfey/fix-style-emits-webpack-plugin

