Make CommonJS-Incompatible Files Browserifyable
browserify . -d -o bundle.js
Table of Contents generated with DocToc
- You Will Always
- You will sometimes
- a) Expose global variables via
- b) Use aliases
- c) Provide an external shim config
- d) Diagnose what browserify-shim is doing
- a) Expose global variables via
- Multi Shim Example including dependencies
- More Examples
npm install browserify browserify-shim
For a version compatible with email@example.com run
npm install firstname.lastname@example.org instead.
For a version compatible with the v2 API
npm install email@example.com instead.
The core features of browserify-shim are:
- Shims non-CommonJS modules in order for them to be browserified by specifying an alias, the path to the file,
and the identifier under which the module attaches itself to the global
dependsfor shimming libraries that depend on other libraries being in the global namespace.
- applies shims configured inside the dependencies of your package
Additionally, it handles the following real-world edge cases:
- Modules that just declare a
var foo = ...on the script level and assume it gets attached to the
windowobject. Since the only way they will ever be run is in the global context — "ahem, … NO?!"
undefined, in order to fix improperly-authored libraries that need shimming but try anyway to use AMD or CommonJS. For more info read the comment inside this fixture
- removes invalid requires, i.e.
'jquery'isn't installed due to the library being improperly published or installed incorrectly via a downloader like bower
browserify-shim is a proper
browserify transform you can publish packages with files that need to be shimmed,
granted that you specify the shim config inside the
browserify resolves your package it will run the
browserify-shim transform and thus shim what's necessary
when generating the bundle.
browserify-shim walks upwards from each source file and uses the first
"browserify-shim" configuration it finds in a
package.json file. You can't shim files outside your project from your project's package. You can add multiple
package.json files as long as browserify-shim can always find a package above each source file with the right configuration.
You Will Always
1. Install browserify-shim dependency
In most cases you want to install it as a devDependency via:
npm install -D browserify-shim
2. Register browserify-shim as a transform with browserify
Browserify transforms are run in order and may modify your source code along the way. You'll typically want to include browserify-shim last.
3. Provide browserify-shim config
The above includes
./js/vendor/jquery.js (relative to the
package.json) in the bundle and exports
Additionally it exposes
three, so you can
var three = require('three'). More info
Short Form vs. Long Form config
jquery does not depend on other shimmed modules and thus has no
depends field, we used the short form to
specify its exports, however the example above is equivalent to:
You will sometimes
a) Expose global variables via
In some cases the libraries you are using are very large and you'd prefer to add them via a script tag instead to get the following benefits:
- faster bundling times since the library is not included in the bundle
- pull libraries from a CDN which allows it to be pulled straight from the user's browser cache in case it was downloaded before
We'll show how this works by taking the rather huge yet awesome
THREE.js library as an example:
1. add script tag for library you want to expose
<!-- index.html -->
2. Add expose global config to
2.a. Add expose global config to external shim config
In case you are using an external shim config, you may achieve the same by specifying the global via an
moduleexports ='three': exports: 'global:THREE'
3. Require library by the name it was exposed as
var THREE = ;
Why not just
var THREE = window.THREE?
You want to avoid spreading the knowledge that
THREE is a global and stay consistent in how you resolve dependencies.
THREE would ever be published to npm and you decide to install it from there,
you don't have to change any of your code since it already is
requireing it properly.
b) Use aliases
You may expose files under a different name via the
browser field and refer to them under that alias in the shim config:
This also allows you to require this module under the alias, i.e.:
var $ = require('jquery').
c) Provide an external shim config
The external shim format is very similar to the way in which the shim is specified inside the
below for more details.
d) Diagnose what browserify-shim is doing
You may encounter problems when your shim config isn't properly setup. In that case you can diagnose them via the
Simply set the flag when building your bundle, i.e.:
BROWSERIFYSHIM_DIAGNOSTICS=1 browserify -d . -o js/bundle.js
or in a
build.js script add:
process.env.BROWSERIFYSHIM_DIAGNOSTICS=1 to the top.
Multi Shim Example including dependencies
Some libraries depend on other libraries to have attached their exports to the window for historical reasons :(. (Hopefully soon we can truly say that this bad design is history.)
In this contrived example we are shimming four libraries since none of them are commonJS compatible:
- x exports window.$
- x-ui exports nothing since it just attaches itself to x. Therefore x-ui depends on x.
- y exports window.Y and also depends on x expecting to find it on the window as $.
- z exports window.zorro and depends on x and y. It expects to find x on the window as $, but y on the window as YNOT, which is actually different than the name under which y exports itself.
We will be using the
depends field in order to ensure that a dependency is included and initialized before a library
that depends on it is initialized.
Below are three examples, each showing a way to properly shim the above mentioned modules.
a) Config inside
package.json without aliases
depends array consists of entries of the format
b) Config inside
package.json with aliases
depends entries make use of the aliases as well
c) Config inside
./config/shim.js without aliases
moduleexports ='../vendor/x.js' : 'exports': '$''../vendor/x-ui.js' : 'depends': '../vendor/x.js': null'../vendor/y.js' : 'exports': 'Y' 'depends': '../vendor/x.js': '$''../vendor/z.js' : 'exports': 'zorro' 'depends': '../vendor/x.js': '$' '../vendor/y.js': 'YNOT'
Note: all paths are relative to
./config/shim.js instead of the
The main difference to
a) is the
depends field specification. Instead it being an array of strings it expresses its dependencies as a hashmap:
- value: the name under which it is expected to be attached on the window