Reputation: 146
I have an expression require which should get resolved in runtime but I can’t get my head around the webpack config for this simple example:
import something from 'module';
import pkg from './package.json';
let a;
if (pkg.main) {
a = require(pkg.main);
}
The resulting build should contain the module
but also require ./package.json
and pkg.main
in runtime as commonjs modules — in other words, exclude them from the build.
My webpack.config.js
so far:
var webpack = require('webpack');
module.exports = {
entry: './src/main.js',
output: {
filename: '[name].js',
path: './build'
},
target: 'node-webkit',
plugins: [
new webpack.ExternalsPlugin('commonjs', './package.json')
],
module: {
noParse: /\.min\.js/,
exprContextRegExp: /$^/,
exprContextCritical: false,
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/
}
]
}
};
What happens now is the require for pkg.main
results in webpackMissingModule
exception and if I remove exprContextRegExp
, the require will use context.
Thanks for any help
Upvotes: 3
Views: 2098
Reputation: 2797
Install it: yarn add webpack-ignore-dynamic-require
Enable it
// webpack.config.js
const IgnoreDynamicRequire = require('webpack-ignore-dynamic-require');
module.exports = {
// ...
plugins: [
new IgnoreDynamicRequire()
]
}
In order to bundle a server application, I needed it, because it uses require
for loading local JSON files.
Based on self answer from Patrik Holčák, I was able to create a plugin for Webpack 4. It may work on Webpack 5.
class IgnoreDynamicRequire {
apply(compiler) {
compiler.hooks.normalModuleFactory.tap('IgnoreDynamicRequire', factory => {
factory.hooks.parser.for('javascript/auto').tap('IgnoreDynamicRequire', (parser, options) => {
parser.hooks.call.for('require').tap('IgnoreDynamicRequire', expression => {
// This is a SyncBailHook, so returning anything stops the parser, and nothing allows to continue
if (expression.arguments.length !== 1 || expression.arguments[0].type === 'Literal') {
return
}
const arg = parser.evaluateExpression(expression.arguments[0])
if (!arg.isString() && !arg.isConditional()) {
return true;
}
});
});
});
}
}
This is much more complicated than the previous answer, but we need to access the parser
object. After that, simply include it in your plugins
array:
plugins: [
new IgnoreDynamicRequire()
]
And all require
calls that does not resolve to a string are left as-is.
Upvotes: 2
Reputation: 146
For anyone wondering: you can solve it with this plugin:
function() {
this.parser.plugin('call require', function(expr) {
if (expr.arguments.length !== 1) {
return;
}
const param = this.evaluateExpression(expr.arguments[0]);
if (!param.isString() && !param.isConditional()) {
return true;
}
});
}
Anything that cannot be resolved by webpack will be left as is.
Upvotes: 3