As of Meteor 1.4 it handles npm packages itself. No need to use Browserify so no need to use this plugin.
Browserify npm dependencies in Meteor packages for client side use.
- Examples
- Use in a Meteor Package
- Use in a Meteor App
- Passing options to Browserify
- Caching Result
- Reporting an Issue
There are four examples for you to look at:
Standard Use:
- Example App using meteorhacks:npm to install npm modules
- Example Package using Meteor's Npm.depends() to install npm modules
Alternate use with manual calls to npm install
to install modules (requires 0.9+):
- Example App 2 using
npm install <module>
- Example Package 2 using
npm install <module>
Specify npm modules in your package and browserify them to the client. The variables may be package scoped or app (global) scoped.
For a quick start, copy my functional example package.
Use standard Meteor package create and add:
$ meteor create --package cosmos:browserify-example
Create a JavaScript file requiring the npm modules you want to browserify. The file name must end with browserify.js
.
NOTE: Due to Meteor Issue #3985 we must put something before the extension, like: client.browserify.js
.
Example content:
// without var it becomes a package scoped variable
uppercase = require('upper-case');
// Specify npm modules
Npm.depends({
'upper-case':'1.1.2'
});
Package.onUse(function(api) {
// add package
api.use(['cosmos:[email protected]'], 'client');
// add browserify file in step #2 with your package's client files
api.addFiles(['client.browserify.js', 'your/package/file.js'], 'client');
// OPTIONAL: make variable app (global) scoped:
api.export('uppercase', 'client');
});
As with all other variables in a package the browserified variables are limited to the package scope unless they are exported via api.export()
as shown above.
First, ensure your app is running without errors.
If you exported a variable to the app scope then you may use it in the browser's JavaScript console.
If your variable is package scoped you may still verify it was browserified.
A. Use View Source to see the script tags Meteor is sending to your client.
B. Find your package's script tag and click on it to view its source. For package someuser:somepackage
there will be a script tag like this:
<script type="text/javascript" src="/packages/someuser_somepackage.js?a5c324925e5f6e800a4"></script>
C. Find your package's browserify script. If your package was someuser:somepackage
and the file named client.browserify.js
then you'd look for a block like this:
////////////////////////////////////////////////////////
// packages/someuser:somepackage/client.browserify.js //
////////////////////////////////////////////////////////
D. Ensure the variable you want is in the package scoped area. If you're looking for a variable named uppercase
then you'd see this:
/* Package-scope variables */
var uppercase, __coffeescriptShare;
Note: I always use coffeescript, so there's always the __coffeescriptShare
there. I'm not sure if it's always there or not.
In your package's client scripts you have access to all package scoped variables, including those browserified. For example:
console.log("uppercase('some text') = ", uppercase('some text'));
Specify npm modules in your app and browserify them to the client. The variables will be app (global) scoped.
It is possible to make browserified variables app (global) scoped by exporting them from a package with api.export()
. Please see Exporting to App.
Meteor doesn't support npm modules at the app level. Fortunately, you can add the ability with the meteorhacks:npm package.
$ meteor add meteorhacks:npm
The first time your app runs (or if it's running when you add the package) it will create a packages.json
file in the root of your app. Specify the modules in packages.json
. For example:
{
"upper-case" : "1.1.2"
}
Create a JavaScript file requiring the npm modules you want to browserify. The name must end with browserify.js
.
Example content:
// without var it becomes an app (global) scoped variable
uppercase = require('upper-case');
NOTE:
- Due to Meteor Issue #3985 we must put something before the extension, like:
app.browserify.js
. - When the file is outside the
client
folder Meteor runs the browserify plugin twice, once for client and once for server. I recommend putting the file insideclient
. It is a client-only file anyway.
Add cosmos:browserify
:
$ meteor add cosmos:browserify
It will browserify your app.browserify.js
file and push it to the client.
In your browser's JavaScript console you can use the variable (uppercase
if you followed my example).
Browserify can be configured with additional options by adding a file with the same name as your .browserify.js
file, but with the extension .browserify.options.json
.
# example file structure:
- app.browserify.js # entry point
- app.browserify.options.json # options
You can use any options that you can pass to the API.
To use a Browserify transform from NPM, add its package to your packages.json
as described above; then pass it in the special transform
option. This option is an object where the keys are the transform names, and the values are the options that can be passed to that transform.
Below is an example of using the exposify
transform to use a global React variable with React Router instead of the React package from NPM.
{
"react-router": "0.13.3",
"exposify": "0.4.3"
}
ReactRouter = require("react-router");
{
"transforms": {
"exposify": {
"global": true,
"expose": {
"react": "React"
}
}
}
}
Make Meteor watch the options file for updates by adding it to the API:
// from example package in cosmos-browserify-example
api.addFiles([
'client/example.html', // show some example results
'client/example.coffee', // package's Meteor script
'client.browserify.js', // browserify file
'client.browserify.options.json' // browserify options file
],
'client'
);
What I'm calling "Special Options" are:
- ignore
- exclude
- external
- plugin
When you use those at the top level of the JSON options object cosmos:browserify will use them by explicitly calling their corresponding functions on the created Browserify object.
Specify their values using an array. Each element in the array will be passed to the corresponding function call.
Each element may be:
- string
- object
When it's a string it is passed to the function as the first argument.
When it's an object each top-level key of that object is used as the first argument to the function and its value is passed as the second argument.
For example:
{
"plugin" : [
"some-plugin",
{ "browserify-resolutions" : "*"}
{ "browserify-resolutions" : [ "*" ] }
]
}
Both browserify-resolutions
are equivalent. The second one allows specifying an array of values to it.
Also, you could specify multiple plugins with options in a single object element. The outer array allows ordering the plugins.
Their corresponding function calls look like this:
browserifyObject.plugin('some-plugin', {basedir:'the/basedir'})
browserifyObject.plugin('browserify-resolutions', '*')
// OR:
browserifyObject.plugin('browserify-resolutions', ['*'])
Where did the basedir
come from? Some of the functions look for the basedir
property. So, I'm setting it onto options objects from the basedir we're providing the Browserify object on creation.
As of 0.7.0 the Meteor Build API supports caching build plugin results. It will only redo a browserify operation when files it builds have changed.
When reporting an issue consider showing:
- the npm modules you're browserifying via the app's packages.json or package.js's Npm.depends() call
- the browserify.js file, at least the require calls portion
- the browserify.options.json file
- the error