Configuration Diff Tool
Shakapacker includes a semantic configuration diff workflow for webpack/rspack configs via pack-config-diff.
This gives you structured, meaningful diffs instead of raw line-by-line file diffs.
Use this during webpack-to-Rspack migrations whenever you need to confirm that a generated or hand-rolled rspack config preserved the important behavior of the old webpack config. It is especially useful before deleting a custom webpack builder, changing SSR/client split configs, or replacing plugin chains.
Why use this instead of diff?
Traditional file diff tools are great for source code, but generated bundler configs are noisy and deeply nested.
Semantic diffing is better for this use case because it:
- Understands nested webpack/rspack configuration objects
- Supports filtering noisy sections with
--ignore-keysand--ignore-paths - Normalizes machine-specific absolute paths by default
- Supports summary, detailed, JSON, and YAML output formats
- Handles config-specific value types (functions, RegExp, Date)
Quick Start
Export configs, then diff them:
# Export all standard configs (dev/prod + client/server)
bin/shakapacker-config --doctor
# Compare development vs production client config
bin/diff-bundler-config \
--left=shakapacker-config-exports/webpack-development-client.yml \
--right=shakapacker-config-exports/webpack-production-client.yml
Common Workflows
1. Works in development, broken in production
bin/shakapacker-config --doctor
bin/diff-bundler-config \
--left=shakapacker-config-exports/webpack-development-client.yml \
--right=shakapacker-config-exports/webpack-production-client.yml \
--format=summary
2. Compare client vs server bundles
bin/shakapacker-config --doctor
bin/diff-bundler-config \
--left=shakapacker-config-exports/webpack-production-client.yml \
--right=shakapacker-config-exports/webpack-production-server.yml
3. Webpack to Rspack migration validation
# Export webpack state
bin/shakapacker-config --doctor
# Switch bundler
bundle exec rake shakapacker:switch_bundler rspack --install-deps
# Export rspack state
bin/shakapacker-config --doctor
# Compare two snapshots (rename or copy files as needed)
bin/diff-bundler-config \
--left=webpack-production-client.yml \
--right=rspack-production-client.yml \
--ignore-paths="plugins.*"
Run this comparison for each important build target, such as development client, production client, and SSR/server bundles. Start with --format=summary, then rerun without it for detailed paths when the summary shows a behavioral difference you did not expect.
4. Capture machine-readable report for CI or PR artifacts
bin/diff-bundler-config \
--left=baseline.yaml \
--right=current.yaml \
--format=json \
--output=config-diff.json
Output Formats
# Detailed (default)
bin/diff-bundler-config --left=a.yaml --right=b.yaml --format=detailed
# Summary
bin/diff-bundler-config --left=a.yaml --right=b.yaml --format=summary
# JSON
bin/diff-bundler-config --left=a.yaml --right=b.yaml --format=json
# YAML
bin/diff-bundler-config --left=a.yaml --right=b.yaml --format=yaml
Useful Options
# Include unchanged values
--include-unchanged
# Limit recursion depth
--max-depth=5
# Ignore keys globally
--ignore-keys=timestamp,version
# Ignore paths (supports wildcards)
--ignore-paths="plugins.*,output.path"
# Disable automatic path normalization
--no-normalize-paths
Supported Input Files
- JSON (
.json) - YAML (
.yaml,.yml) - JavaScript (
.js) - TypeScript (
.ts, requirests-node)
Exit Codes
0: no differences found1: differences found2: wrapper/runtime error (module load error, invalid return code)
For CI usage, treat 1 as "configs differ" and 2 as "tool/runtime failure".
Programmatic Usage
You can use the package directly in scripts:
const { DiffEngine, DiffFormatter } = require("pack-config-diff")
const engine = new DiffEngine({
ignorePaths: ["plugins.*"]
})
const result = engine.compare(leftConfig, rightConfig, {
leftFile: "webpack.dev.js",
rightFile: "webpack.prod.js"
})
const formatter = new DiffFormatter()
console.log(formatter.formatDetailed(result))