Skip to content

Instantly share code, notes, and snippets.

@bholloway
Created November 8, 2019 00:16
Show Gist options
  • Save bholloway/9feb2ca4adb8eb4b89b538882908d4e1 to your computer and use it in GitHub Desktop.
Save bholloway/9feb2ca4adb8eb4b89b538882908d4e1 to your computer and use it in GitHub Desktop.
const { basename } = require('path');
const { ConcatSource } = require('webpack-sources');
const ModuleFilenameHelpers = require('webpack/lib/ModuleFilenameHelpers');
/**
* Loosely based on wrapper-webpack-plugin
* https://www.npmjs.com/package/wrapper-webpack-plugin
*
* Chunk deletion based on webpack-remove-empty-js-chunks-plugin
* https://www.npmjs.com/package/webpack-remove-empty-js-chunks-plugin
*/
class ExtractAndWrapPlugin {
constructor(args) {
if (typeof args !== 'object') {
throw new TypeError('Argument "args" must be an object.');
}
this.test = args.test || '';
this.header = args.header || '';
this.footer = args.footer || '';
}
apply(compiler) {
const { header, footer, test } = this;
const wrapChunks = (compilation, chunks) => {
const extractChunk = chunkFilenameTest => {
const selectedChunks = chunks.filter(
({ name }) =>
chunkFilenameTest &&
typeof name === 'string' &&
ModuleFilenameHelpers.matchObject(
{ test: chunkFilenameTest },
basename(name),
),
);
if (selectedChunks.length) {
const files = selectedChunks.reduce((r, c) => r.concat(c.files), []);
const source = compilation.assets[files[0]].source();
// stop this chunk from outputting files
files.forEach(f => {
// eslint-disable-next-line no-param-reassign
delete compilation.assets[f];
});
// eslint-disable-next-line no-underscore-dangle
return source;
}
return null;
};
const headerSource = extractChunk(header);
const footerSource = extractChunk(footer);
if (headerSource || footerSource) {
chunks.forEach(chunk => {
chunk.files.forEach(fileName => {
if (ModuleFilenameHelpers.matchObject({ test }, fileName)) {
// eslint-disable-next-line no-param-reassign
compilation.assets[fileName] = new ConcatSource(
...[
headerSource,
compilation.assets[fileName],
footerSource,
].filter(Boolean),
);
}
});
});
}
};
compiler.hooks.compilation.tap('ExtractAndWrapPlugin', compilation => {
compilation.hooks.optimizeChunkAssets.tapAsync(
'ExtractAndWrapPlugin',
(chunks, done) => {
// eslint-disable-next-line no-use-before-define
wrapChunks(compilation, chunks);
done();
},
);
});
}
}
module.exports = ExtractAndWrapPlugin;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment