Security News
Input Validation Vulnerabilities Dominate MITRE's 2024 CWE Top 25 List
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
@alfred/merge-configs
Advanced tools
[![build status](https://secure.travis-ci.org/survivejs/webpack-merge.svg)](http://travis-ci.org/survivejs/webpack-merge) [![codecov](https://codecov.io/gh/survivejs/webpack-merge/branch/master/graph/badge.svg)](https://codecov.io/gh/survivejs/webpack-mer
webpack-merge provides a merge
function that concatenates arrays and merges objects creating a new object. If functions are encountered, it will execute them, run the results through the algorithm, and then wrap the returned values within a function again.
This behavior is particularly useful in configuring webpack although it has uses beyond it. Whenever you need to merge configuration objects, webpack-merge can come in handy.
There's also a webpack specific merge variant known as merge.smart
that's able to take webpack specifics into account (i.e., it can flatten loader definitions).
merge(...configuration | [...configuration])
merge
is the core, and the most important idea, of the API. Often this is all you need unless you want further customization.
// Default API
const output = merge(object1, object2, object3, ...objs);
// You can pass an array of objects directly.
// This works with all available functions.
const output = merge([object1, object2, object3]);
merge({ customizeArray, customizeObject })(...configuration | [...configuration])
merge
behavior can be customized per field through a curried customization API.
// Customizing array/object behavior
const output = merge({
customizeArray(a, b, key) {
if (key === "extensions") {
return _.uniq([...a, ...b]);
}
// Fall back to default merging
return undefined;
},
customizeObject(a, b, key) {
if (key === "module") {
// Custom merging
return _.merge({}, a, b);
}
// Fall back to default merging
return undefined;
}
})(object1, object2, object3, ...objs);
For example, if the previous code was invoked with only object1
and object2
with object1
as:
{
foo1: ['object1'],
foo2: ['object1'],
bar1: { 'object1': {} },
bar2: { 'object1': {} },
}
and object2
as:
{
foo1: ['object2'],
foo2: ['object2'],
bar1: { 'object2': {} },
bar2: { 'object2': {} },
}
then customizeArray
will be invoked for each property of Array
type, i.e:
customizeArray(["object1"], ["object2"], "foo1");
customizeArray(["object1"], ["object2"], "foo2");
and customizeObject
will be invoked for each property of Object
type, i.e:
customizeObject({ object1: {} }, { object2: {} }, bar1);
customizeObject({ object1: {} }, { object2: {} }, bar2);
merge.unique(<field>, <fields>, field => field)
const output = merge({
customizeArray: merge.unique(
"plugins",
["HotModuleReplacementPlugin"],
plugin => plugin.constructor && plugin.constructor.name
)
})(
{
plugins: [new webpack.HotModuleReplacementPlugin()]
},
{
plugins: [new webpack.HotModuleReplacementPlugin()]
}
);
// Output contains only single HotModuleReplacementPlugin now.
merge.strategy({ <field>: '<prepend|append|replace>''})(...configuration | [...configuration])
Given you may want to configure merging behavior per field, there's a strategy variant:
// Merging with a specific merge strategy
const output = merge.strategy({
entry: "prepend", // or 'replace', defaults to 'append'
"module.rules": "prepend"
})(object1, object2, object3, ...objs);
merge.smartStrategy({ <key>: '<prepend|append|replace>''})(...configuration | [...configuration])
The same idea works with smart merging too (described below in greater detail).
const output = merge.smartStrategy({
entry: "prepend", // or 'replace'
"module.rules": "prepend"
})(object1, object2, object3, ...objs);
merge.smart(...configuration | [...configuration])
webpack-merge tries to be smart about merging loaders when merge.smart
is used. Loaders with matching tests will be merged into a single loader value.
Note that the logic picks up webpack 2 rules
kind of syntax as well. The examples below have been written in webpack 1 syntax.
package.json
{
scripts: {
start: "webpack-dev-server",
build: "webpack"
}
// ...
}
webpack.config.js
const path = require("path");
const merge = require("webpack-merge");
const TARGET = process.env.npm_lifecycle_event;
const common = {
entry: path.join(__dirname, "app"),
module: {
loaders: [
{
test: /\.css$/,
loaders: ["style", "css"]
}
]
}
};
if (TARGET === "start") {
module.exports = merge(common, {
module: {
// loaders will get concatenated!
loaders: [
{
test: /\.jsx?$/,
loader: "babel?stage=1",
include: path.join(ROOT_PATH, "app")
}
]
},
...opts
});
}
if (TARGET === "build") {
module.exports = merge(common, {
...opts
});
}
// ...
Loader string values loader: 'babel'
override each other.
merge.smart(
{
loaders: [
{
test: /\.js$/,
loader: "babel"
}
]
},
{
loaders: [
{
test: /\.js$/,
loader: "coffee"
}
]
}
);
// will become
{
loaders: [
{
test: /\.js$/,
loader: "coffee"
}
];
}
Loader array values loaders: ['babel']
will be merged, without duplication.
merge.smart(
{
loaders: [
{
test: /\.js$/,
loaders: ["babel"]
}
]
},
{
loaders: [
{
test: /\.js$/,
loaders: ["coffee"]
}
]
}
);
// will become
{
loaders: [
{
test: /\.js$/,
// appended because Webpack evaluated these from right to left
// this way you can specialize behavior and build the loader chain
loaders: ["babel", "coffee"]
}
];
}
Loader array values loaders: ['babel']
can be reordered by including
original loaders.
merge.smart(
{
loaders: [
{
test: /\.js$/,
loaders: ["babel"]
}
]
},
{
loaders: [
{
test: /\.js$/,
loaders: ["react-hot", "babel"]
}
]
}
);
// will become
{
loaders: [
{
test: /\.js$/,
// order of second argument is respected
loaders: ["react-hot", "babel"]
}
];
}
This also works in reverse - the existing order will be maintained if possible:
merge.smart(
{
loaders: [
{
test: /\.css$/,
use: [
{ loader: "css-loader", options: { myOptions: true } },
{ loader: "style-loader" }
]
}
]
},
{
loaders: [
{
test: /\.css$/,
use: [{ loader: "style-loader", options: { someSetting: true } }]
}
]
}
);
// will become
{
loaders: [
{
test: /\.css$/,
use: [
{ loader: "css-loader", options: { myOptions: true } },
{ loader: "style-loader", options: { someSetting: true } }
]
}
];
}
In the case of an order conflict, the second order wins:
merge.smart(
{
loaders: [
{
test: /\.css$/,
use: [{ loader: "css-loader" }, { loader: "style-loader" }]
}
]
},
{
loaders: [
{
test: /\.css$/,
use: [{ loader: "style-loader" }, { loader: "css-loader" }]
}
]
}
);
// will become
{
loaders: [
{
test: /\.css$/,
use: [{ loader: "style-loader" }, { loader: "css-loader" }]
}
];
}
Loader query strings loaders: ['babel?plugins[]=object-assign']
will be overridden.
merge.smart(
{
loaders: [
{
test: /\.js$/,
loaders: ["babel?plugins[]=object-assign"]
}
]
},
{
loaders: [
{
test: /\.js$/,
loaders: ["babel", "coffee"]
}
]
}
);
// will become
{
loaders: [
{
test: /\.js$/,
loaders: ["babel", "coffee"]
}
];
}
Loader arrays in source values will have loader strings merged into them.
merge.smart(
{
loaders: [
{
test: /\.js$/,
loader: "babel"
}
]
},
{
loaders: [
{
test: /\.js$/,
loaders: ["coffee"]
}
]
}
);
// will become
{
loaders: [
{
test: /\.js$/,
// appended because Webpack evaluated these from right to left!
loaders: ["babel", "coffee"]
}
];
}
Loader strings in source values will always override.
merge.smart(
{
loaders: [
{
test: /\.js$/,
loaders: ["babel"]
}
]
},
{
loaders: [
{
test: /\.js$/,
loader: "coffee"
}
]
}
);
// will become
{
loaders: [
{
test: /\.js$/,
loader: "coffee"
}
];
}
merge.multiple(...configuration | [...configuration])
Sometimes you may need to support multiple targets, webpack-merge will accept an object where each key represents the target configuration. The output becomes an array of configurations where matching keys are merged and non-matching keys are added.
const path = require("path");
const baseConfig = {
server: {
target: "node",
output: {
path: path.resolve(__dirname, "dist"),
filename: "lib.node.js"
}
},
client: {
output: {
path: path.resolve(__dirname, "dist"),
filename: "lib.js"
}
}
};
// specialized configuration
const production = {
client: {
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].[hash].js"
}
}
};
module.exports = merge.multiple(baseConfig, production);
Check out SurviveJS - Webpack and React to dig deeper into the topic.
npm i
npm run build
npm run watch
Before contributing, please open an issue where to discuss.
webpack-merge is available under MIT. See LICENSE for more details.
FAQs
[![build status](https://secure.travis-ci.org/survivejs/webpack-merge.svg)](http://travis-ci.org/survivejs/webpack-merge) [![codecov](https://codecov.io/gh/survivejs/webpack-merge/branch/master/graph/badge.svg)](https://codecov.io/gh/survivejs/webpack-mer
The npm package @alfred/merge-configs receives a total of 2 weekly downloads. As such, @alfred/merge-configs popularity was classified as not popular.
We found that @alfred/merge-configs demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.