Beyond basic key-by-key diffing, pack-config-diff has three features that reduce noise and make comparisons more meaningful.
Flag: --plugin-aware
Webpack plugins are class instances. When two configs each instantiate the same plugin with the same options, a naive comparison sees them as different objects:
// left.js
module.exports = { plugins: [new MiniCssExtractPlugin({ filename: "style.css" })] };
// right.js
module.exports = { plugins: [new MiniCssExtractPlugin({ filename: "style.css" })] };Without --plugin-aware:
1 changes: +0 -0 ~1
The tool reports a change even though both plugins are functionally identical.
With --plugin-aware, the tool compares plugin instances by:
- Checking that the constructor is the same class
- Comparing all instance properties recursively (serializing functions, RegExps, etc.)
pack-config-diff --left=left.js --right=right.js --plugin-aware✅ No differences found
- When comparing JS/TS configs that use
new Plugin(...)instances - When debugging plugin option differences across environments
- Not needed for JSON/YAML configs (they can't contain class instances)
If the options are different, the diff surfaces the actual property changes:
// left.js — development
module.exports = {
plugins: [new MiniCssExtractPlugin({ filename: "[name].css" })],
};
// right.js — production
module.exports = {
plugins: [new MiniCssExtractPlugin({ filename: "[name]-[contenthash].css" })],
};pack-config-diff --left=left.js --right=right.js --plugin-aware1. [~] plugins.[0]
What it does:
Array of plugins to extend webpack functionality (HTML generation, env vars, compression, etc.).
Affects: Build process, output, and optimizations
Values:
left: [Instance: MiniCssExtractPlugin]
right: [Instance: MiniCssExtractPlugin]
Documentation: https://webpack.js.org/configuration/plugins/
Note: Plugin-aware mode determines equality by comparing all instance properties, but when plugins differ the change is reported at the instance level (e.g.,
plugins.[0]), not at individual property paths.
Flag: --match-rules-by-test
module.rules is an array, so by default rules are compared by index position. If you reorder rules without changing their content, you get false positives:
left.json:
{
"module": {
"rules": [
{ "test": "\\.js$", "use": "babel-loader" },
{ "test": "\\.css$", "use": "css-loader" }
]
}
}right.json (same rules, swapped order):
{
"module": {
"rules": [
{ "test": "\\.css$", "use": "css-loader" },
{ "test": "\\.js$", "use": "babel-loader" }
]
}
}Without --match-rules-by-test:
4 changes: +0 -0 ~4
Four spurious changes because rules[0] and rules[1] swapped positions.
With --match-rules-by-test, rules are matched by their test pattern instead of array index. Rules with the same test value are paired together for comparison:
pack-config-diff --left=left.json --right=right.json --match-rules-by-test✅ No differences found
- Each rule's
testproperty (string or RegExp) is used as its identity - Rules without a
testproperty fall back to index-based matching - Duplicate
testvalues are handled with occurrence counters
- When comparing configs that may have reordered rules
- When you only care about the content of each rule, not its position
- Particularly useful during refactoring or when merging config fragments from different sources
Enabled by default. Disable with --no-normalize-paths.
Webpack configs often contain absolute filesystem paths (e.g., output.path). When comparing configs generated on different machines, these paths differ even though the project structure is identical:
left.json (Alice's machine):
{ "output": { "path": "/Users/alice/project/public/packs" } }right.json (Bob's machine):
{ "output": { "path": "/home/bob/project/public/packs" } }Without normalization:
1 changes: +0 -0 ~1
Path normalization automatically detects absolute paths in the config, finds the common project root, and converts paths to relative form before comparing:
pack-config-diff --left=left.json --right=right.json✅ No differences found
Both paths resolve to ./public/packs relative to their respective project roots.
If you specifically care about absolute path differences:
pack-config-diff --left=left.json --right=right.json --no-normalize-paths1 changes: +0 -0 ~1
1. [~] output.path
left: "/Users/alice/project/public/packs"
right: "/home/bob/project/public/packs"