Skip to content

Instantly share code, notes, and snippets.

@dccampbell
Last active February 10, 2020 19:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dccampbell/8ca0da4923ac6c07c9ec6ed101399052 to your computer and use it in GitHub Desktop.
Save dccampbell/8ca0da4923ac6c07c9ec6ed101399052 to your computer and use it in GitHub Desktop.
ExtractJS for Laravel Mix - Extension for code splitting custom JS modules similar to extract() for vendor ones.
let glob = require('glob');
let mix = require('laravel-mix');
let webpackMerge = require('webpack-merge');
/**
* Laravel Mix extension for code splitting custom JS similar to extract() for vendor modules.
* @author @dccampbell
* @example mix.extractJs('/resources/js/api.js', 'public/js')
* @example mix.extractJs('/resources/js/store/*', 'public/js/store.js')
* @example mix.extractJs(['/js/lib.js', '/js/lib.*.js'], 'public/js/lib.js')
*/
class ExtractJs {
constructor() {
this.entry = null;
this.groups = [];
}
/**
* @param {string|Array} source
* @param {string} output
*/
register(source, output) {
let sources = this.expandSources(source);
let inputFiles = sources.map(src => new File(src));
let outputFile = new File(output);
if(inputFiles.length) {
this.groups.push({ inputFiles, outputFile });
}
}
/** @param {Entry} entry */
webpackEntry(entry) {
this.groups.forEach(group => {
group.outputName = entry.createName(entry.normalizePath(group.outputFile, group.inputFiles[0]));
entry.add(group.outputName, group.inputFiles.map(file => file.path()));
});
this.entry = entry;
}
/** @param {Object} config */
webpackConfig(config) {
config.optimization = webpackMerge.smart(config.optimization, {
runtimeChunk: {
name: path.join(this.entry.base, 'manifest').replace(/\\/g, '/')
},
splitChunks: this.createSplitChunks()
});
}
createSplitChunks() {
let config = { cacheGroups: {} };
for (const [index, group] of this.groups.entries()) {
let filesPattern = group.inputFiles.map(file => file.relativePath()).join('|');
config.cacheGroups[`js${index}`] = {
test: new RegExp(`.*(${filesPattern}).*`, 'i'),
name: group.outputName,
chunks: 'all',
enforce: true
};
}
return config;
}
expandSources(source) {
if (typeof source === 'string' && source.includes('*')) {
return glob.sync(source, { nodir: true });
}
if (Array.isArray(source)) {
let sources = source.map(src => this.expandSources(src));
return [].concat(...sources);
}
return [source];
}
}
mix.extend('extractJs', new ExtractJs());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment