Skip to content

Instantly share code, notes, and snippets.

@kherock
Last active January 26, 2024 20:20
Show Gist options
  • Save kherock/69ecd01619c72b3b94806c46342ba8d8 to your computer and use it in GitHub Desktop.
Save kherock/69ecd01619c72b3b94806c46342ba8d8 to your computer and use it in GitHub Desktop.
Remove empty CSS modules workaround
const EMPTY_MODULES_CLEANUP_DEP_TYPES = new Set([
'harmony side effect evaluation',
'import()',
'single entry',
]);
class SetMap extends Map {
add (key, value) {
const set = this.get(key);
if (set === undefined) {
super.set(key, new Set([value]));
} else {
set.add(value);
}
}
}
/**
* Temporary workaround to clean up empty .js files left behind by
* mini-css-extract-plugin. This is already fixed in webpack@5.
*
* @see {@link https://github.com/webpack-contrib/mini-css-extract-plugin/issues/357}
*/
module.exports = class MiniCssExtractPluginCleanup {
apply (compiler) {
compiler.hooks.thisCompilation.tap('mini-css-extract-plugin-cleanup', (compilation) => {
compilation.hooks.finishModules.tap('mini-css-extract-plugin-cleanup', (modules) => {
const toRemoveMap = new SetMap();
for (const module of modules) {
if (module.type === 'css/mini-extract') {
for (const cssModuleReason of module.reasons) {
for (const reason of cssModuleReason.module.reasons) {
if (EMPTY_MODULES_CLEANUP_DEP_TYPES.has(reason.dependency.type)) {
toRemoveMap.add(
reason.module || cssModuleReason.module,
reason.dependency,
);
}
}
}
}
}
for (const [module, set] of toRemoveMap) {
// collapse transitive CSS module dependencies
module.dependencies = module.dependencies.flatMap(d => set.has(d) ? d.module.dependencies : [d]);
}
});
compilation.hooks.optimizeChunkAssets.tapAsync('mini-css-extract-plugin-cleanup', (chunks, callback) => {
for (const chunk of chunks) {
if (!chunk.getModules().some(module => /^javascript\/(auto|cjs|esm)$/.test(module.type))) {
// chunk doesn't contain actual JS code, remove the file
const chunkJs = chunk.files.find(file => /\.js$/.test(file));
if (!chunk.hasRuntime()) {
// this is a split chunk, merge it into the runtime chunks that depend on it
for (const group of compilation.chunkGroups) {
if (chunk.isInGroup(group)) {
const runtimeJs = group.runtimeChunk.files.find(file => /\.js$/.test(file));
compilation.assets[runtimeJs]._source.add(compilation.assets[chunkJs]);
}
}
}
chunk.files = chunk.files.filter(file => {
if (/\.js(\.map)?$/.test(file)) {
delete compilation.assets[file];
return false;
}
return true;
});
}
}
callback();
});
});
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment