Replies: 2 comments 3 replies
-
Can you provide error stack or reproducible test repo? |
Beta Was this translation helpful? Give feedback.
-
I've spent few more hours with bard/gpt4 and found a solution. Below is almost fully working example, except I removed It can either generate multiple CSS assets for each processed JS file, or combine everything into single CSS (configured via 'emitSingleCSS') option. class FooBarPlugin {
static defaultOptions = {
outputFilename: 'css/extracted.css',
injectCssIntoChunkNamed: 'main',
cssInjectionTokenRegExp: new RegExp(`__INJECT_CSS\\((.*?)\\);`),
emitSingleCSS: true,
verbose: true,
};
constructor(options = {}) {
this.options = { ...FooBarPlugin.defaultOptions, ...options };
}
apply(compiler) {
const pluginName = FooBarPlugin.name;
const { webpack } = compiler;
const { Compilation } = webpack;
const { RawSource } = webpack.sources;
let assetsEmitted = 0;
let extractedCss = [];
let totalSize = 0;
const emitCSS = (name, source, compilation) => {
const size = Buffer.byteLength(source, 'utf8');
if (size === 0) {
return;
}
totalSize += size;
const filenameParts = name.split('.');
const filenamePrefix = this.options.outputFilename.replace('.css', '');
const filenamePostfix = this.options.emitSingleCSS
? ''
: `_${++assetsEmitted}_${filenameParts.slice(0, filenameParts.length - 1).join('_')}`;
const filename = `${filenamePrefix}${filenamePostfix}.css`;
compilation.emitAsset(filename, new RawSource(source), {
// prevents mini-css-extract-plugin from touching it
minimized: true,
});
this.options.verbose && console.log(` => Emitted CSS asset ${filename} size: ${size}`);
const mainChunk = compilation.namedChunks.get(this.options.injectCssIntoChunkNamed);
if (mainChunk) {
mainChunk.files.add(filename);
}
};
if (this.options.emitSingleCSS) {
compiler.hooks.compilation.tap(pluginName, (compilation) => {
compilation.hooks.processAssets.tap(
{
name: pluginName,
stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE,
additionalAssets: false,
},
() => {
emitCSS(this.options.outputFilename, extractedCss.join('\n'), compilation);
}
);
});
}
compiler.hooks.compilation.tap(pluginName, (compilation) => {
compilation.hooks.processAssets.tap(
{
name: pluginName,
stage: Compilation.PROCESS_ASSETS_STAGE_PRE_PROCESS,
additionalAssets: false,
},
(assets) => {
for (let i in assets) {
if (i.endsWith('.js')) {
const asset = compilation.getAsset(i);
const contents = asset.source.source();
if (this.options.cssInjectionTokenRegExp.test(contents)) {
const [updatedSrc, cleanCss] = this.extractInjectedCSS(contents);
compilation.updateAsset(i, new RawSource(updatedSrc));
if (this.options.emitSingleCSS) {
extractedCss.push(cleanCss);
} else {
emitCSS(i, cleanCss, compilation);
}
}
}
}
}
);
});
compiler.hooks.afterEmit.tap(pluginName, () => {
if (totalSize === 0) {
throw new Error("Couldn't find any embedded CSS");
}
});
}
}
module.exports = {
default: FooBarPlugin,
}; |
Beta Was this translation helpful? Give feedback.
-
So I have a JS library that has CSS bundled in JS (it used rollup and postCSS plugin to inline all the CSS in JS). So if I open JS code I could find things like this:
Where __INJECT_CSS is a function that would create a STYLE tag and insert it into HTML head. It works ok, but my task is to extract all those injected css from js into separate CSS asset.
Below is nearly complete of webpack 5 plugin that I made. Except for extractInjectedCSS function that actually extracts CSS from JS, but that's out of scope of my question.
t does work. Sort of. First of all it works only if stats option is disabled in webpack config. Otherwise if will crash when webpack tries to calculate size of that 'extracted.css' chunk. That's my first problem.
Second problem: that solution with 2 passes of compilation seems like a hack. I had to use renderManifest hook that is missing in webpack documentation and probably isn't supposed to be used like that.
I tried to use compilation.emitAsset() instead of compilation.hooks.renderManifest.tap hack. And while it does creates new asset, that asset isn't being added as dependency to main. Thus it never gets loaded. And I need that extracted CSS assets to be added as dependencies, so that generated JS would load them automatically.
So here's my main question: how to implement my task properly (maybe without 2 passes of compilation and crashes when stats option is on).
Beta Was this translation helpful? Give feedback.
All reactions