I have a module that looks like this:
let Info = {};
Info.VALUE_ONE = 123;
Info.VALUE_TWO = 456;
Info.VALUE_THREE = 789;
module.exports = Info;
I'd like this module to disappear completely from the code after it's compiled and just have the values 123, 456 and 789 inlined where applicable- how would one do this with Webpack?
It sounds like you may want to use the webpack.DefinePlugin
, which allows you to inline global values at compile time.
webpack.config.js
plugins: [
new webpack.DefinePlugin({
Info: require('./info.js'),
}),
//...
]
As an example, your source code would be transformed as below:
source
let value = null;
switch (value) {
case Info.VALUE_ONE:
//...
case Info.VALUE_TWO:
//...
case Info.VALUE_THREE:
//...
default:
//...
}
output
let value = null;
switch (value) {
case 123: //...
case 456: //...
case 789: //...
default: //...
}
One solution is to use string-replace-loader to inline Info.<key>
to <value>
. Then to remove the module itself you have two options.
option 1: keep your commonjs syntax and use null-loader to transform the module into an empty object. The caveat with this approach is I don't see any way to remove references to the module because webpack safely assumes the require
statement itself may produce a side-effect1
option 2: start using es6 import and export and make use of webpack's module-concatenation-plugin. This will place info.js in the same scope as its consumers, allowing the minifier to remove its code (because there will be no references to the Info
object). You will also need to use esm to load the webpack configuration file via npx webpack -r esm
so given a directory structure of:
- index.js
- info.js
- webpack.config.js
This code should give you what you're looking for (I used the code-snippet syntax to make them collapsable - the code is not runnable)
code for option 1
// info.js
module.exports {
VALUE_ONE: 123,
VALUE_TWO: 456,
VALUE_THREE: 789,
}
// index.js
const Info = require('./info')
console.log(Info.VALUE_ONE)
// webpack.config.js
const Info = require('./info')
const searchAndReplaceInfo = createSearchAndReplaceInfo(Info)
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: __dirname
},
module: {
rules: [
{
test: path.resolve(__dirname, 'info.js'),
use: 'null-loader'
}, {
exclude: /\/node_modules\//,
loader: 'string-replace-loader',
options: {
multiple: searchAndReplaceInfo
}
}
]
}
}
function createSearchAndReplaceInfo(Info) {
return Object.keys(Info).map(key => [key, Info[key]]).map(toSearchAndReplace)
}
function toSearchAndReplace([key, value]) {
return {
search: 'Info.' + key,
replace: '' + value
}
}
code for option 2
// info.js
export default {
VALUE_ONE: 123,
VALUE_TWO: 456,
VALUE_THREE: 789,
}
// index.js
import Info from './info'
console.log(Info.VALUE_ONE)
// webpack.config.js
import Info from './info'
import webpack from 'webpack'
const searchAndReplaceInfo = createSearchAndReplaceInfo(Info)
export default {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: __dirname
},
plugins: [ new webpack.optimize.ModuleConcatenationPlugin() ],
module: {
rules: [
{
exclude: /\/node_modules\//,
loader: 'string-replace-loader',
options: {
multiple: searchAndReplaceInfo
}
}
]
}
}
function createSearchAndReplaceInfo(Info) {
return Object.keys(Info).map(key => [key, Info[key]]).map(toSearchAndReplace)
}
function toSearchAndReplace([key, value]) {
return {
search: 'Info.' + key,
replace: '' + value
}
}
side-effect1
A "side effect" is defined as code that performs a special behavior when imported, other than exposing one or more exports. An example of this are polyfills, which affect the global scope and usually do not provide an export.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With