Imagine you're in a mono-repo and you want a majority of node_modules
in a vendor
bundle but all local repo modules to remain
in the app
bundle.
// get a collection of local packages so they don't end up in `vendor`
const packages = path.resolve(__dirname, '../packages');
const repoModules = glob
.sync(`${packages}/**/package.json`, { ignore: ['**/node_modules/**'] })
.map((packageJSON) => require(packageJSON).name);
const repoModulesRegex = new RegExp(`(${repoModules.join('/es|')})`);
const conf = {
entry: {
app: './src/index.js',
},
...
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: ({ resource }) => (
resource
&& resource.includes('node_modules')
&& !repoModulesRegex.test(resource)
),
}),
],
...
}
There may be a time when you'll need to roll your own loader for your repo. In the WP module.rules
section of your config you'd add
something like
module: {
rules: [
{
test: /\.js$/,
loader: require.resolve('./loaders/customLoader'), // local path to your loader
options: { // custom loader options
searchFor: /token/g,
transformer: (source, val) => source.replace(val, 'New Token'),
},
}
]
}
Then in the ./loaders/customLoader.js
file you'd have
const { getOptions } = require('loader-utils');
function mySuperCoolLoader(source, map) {
const {
searchFor,
transformer,
} = getOptions(this);
if(!searchFor || !transformer) throw Error('The `searchFor & transformer` options are required');
const matches = source.match(opt.search);
if(matches && matches.length){
matches.forEach((match) = {
source = transformer(source, match);
});
}
return source;
}
module.exports = mySuperCoolLoader;
Notice that the loader is called with a Webpack context that exposes data in regards to the current process. For example if you need
to get the path of the current file being processed you'd access this.resourcePath
. This post goes over a lot of info, like what
needs to be returned from a loader, caching results, etc https://webpack.js.org/contribute/writing-a-loader/.