Last active
February 10, 2020 19:03
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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