Replacing packages in a Browserify bundle
As a developer on a large Backbone application built with Browserify, there are a number of occasions where I want to replace one dependency with another. In this specific case, I wanted to swap underscore
for lodash
.
Browserify already supports this with the “browser field” in package.json
.
There is a special “browser” field you can set in your package.json on a per-module basis to override file resolution for browser-specific versions of files.
As a developer on a large Backbone application built with Browserify, there are a number of occasions where I want to replace one dependency with another. In this specific case, I wanted to swap underscore
for lodash
.
Browserify already supports this with the “browser field” in package.json
.
There is a special “browser” field you can set in your package.json on a per-module basis to override file resolution for browser-specific versions of files.
This only works for resolution within your package, if any of your dependency packages require Underscore they’ll get Underscore. This is to help ensure your replacements don’t break your dependencies.
However, it’s suboptimal to ship both Lo-Dash and Underscore, as is maintaining a fork simply to replace the dependency. In these edge cases, it’s useful to replace files or packages even within dependencies.
Luckily, the Browserify transform browserify-swap allows you swap dependencies in certain packages, as defined via the @packages
key, while generating the output bundle.
As I want to replace Underscore in Backbone, Marionnette and related packages, the configuration seemed pretty straight-forward.
/* package.json */
{
"browserify": {
"transform": [
"browserify-swap"
]
},
"browserify-swap": {
"@packages": [
"backbone",
"marionette",
"backbone.babysitter",
"backbone.wreqr"
],
"all": {
"underscore.js$": "lodash"
}
}
}
I was a bit discouraged to find that Underscore was still present in the output bundle. After triple-checking that my configuration was valid, I broke out the node debugger to find what was wrong.
I believed browserify-swap
to swap files while resolving the require calls. The transform actually checks if the current file path matches a RegEx defined in the package.json
file and replaces the contents to require the swapped in file.
The Solution
With this information in hand, it became clear that we needed to swap in the underscore
package.
/* package.json */
{
"browserify": {
"transform": [
"browserify-swap"
]
},
"browserify-swap": {
"@packages": [
"underscore"
],
"all": {
"underscore.js$": "lodash"
}
}
}
This causes the swap to happen for each instance of Underscore in the bundle, but only the one instance of Lo-Dash would be included.
I believe that the transform should also allow swapping packages for other packages, as the folder structure of a package is usually not part of the public API. I’ve opened an issue against the project.