40

I'm considering adopting browserify for some of my projects, but would like to make sure that others don't have to use browserify if they want to use the (bundled) code. The obvious way to do this is to both expose the modules exports through module.exports as well as through a window. global. However, I'd rather not pollute the global namespace for those who are requireing the script.

Is it possible to detect if a script is being required? If it is, then I could do something like:

var mymodule = (function() { ... })();
if (isRequired()) {
  module.exports = mymodule;
} else {
  window.mymodule = mymodule;
}

Note that no matter what, this will be bundled beforehand, so the var mymodule won't be exposing a global. Also, currently I'm using the revealing module pattern, but would be willing to switch to something more appropriate for browserify.

What's the best way to make a module both requireable and <script src=able? Is it best to just expose a global in both circumstances?

Mingwei Samuel
  • 2,917
  • 1
  • 30
  • 40
Bryan Head
  • 12,360
  • 5
  • 32
  • 50

4 Answers4

44

There is a good article from Forbes Lindesay explaining how to do standalone builds: http://www.forbeslindesay.co.uk/post/46324645400/standalone-browserify-builds

The short version, use the standalone option:

browserify beep.js --standalone beep-boop > bundle.js
karellm
  • 1,843
  • 1
  • 20
  • 23
  • 2
    Link uses deprecated code. Can't pass options to bundle() anymore. Also link doesn't explain where it got beep-boop from and if the name is significant, and what to replace it with in the real world. – Trevor Jun 29 '18 at 14:03
  • 1
    I'm not sure of the correct terminology but "beep-boop" in this example is the 'namespace' you want to contain the standalone functions within. So if I browserify'd a function `byteLength (...){...}` with `browserify infile --standalone myspace -o outfile`, I would access the function by calling `myspace.byteLength(...)` from within the JS file that has included `outfile` via `require()`. – parttimeturtle Sep 02 '20 at 03:05
  • 1
    Just to clarify; Using browserify version 17.0.0 with the above gives me the working bundle and correctly exposes a camel cased global 'beepBoop". – KellyCode Dec 24 '20 at 23:01
21

I'm dealing with the same problem building a library and here is a rought opinion. I think we need to separate first the audiences for a library in few categories:

  1. those who use browserify and NPM
  2. those who will just download a mylib.min.js and use one way or another
  3. AMD (with bower?), might be the third category.

So, for 1 it is easy, you will have a your index.js module:

module.exports = function () { /* code */ }

and your package.json will have a main

"main": "index.js"

Notice I haven't add any window.xx code to index.js.

For 2 I think the best idea is to create a standalone.js

var mylib = require('./index.js');
global.window.mylib = mylib;

This is what browserify should build.

For 3 (if you care about) you can tweak standalone.js as follows:

var mylib = require('./index.js');
if (typeof global.window.define == 'function' && global.window.define.amd) {
  global.window.define('mylib', function () { return mylib; });
} else {
  global.window.mylib = mylib;
}
José F. Romaniello
  • 13,866
  • 3
  • 36
  • 38
  • 2
    Isn't "global" the same as "window"? If so, shouldn't it be "global.mylib = mylib" rather than "global.window.mylib = ..."? – Duncan Jan 03 '19 at 14:17
2

Assuming another library hasn't created a global module.exports object, you can simply check for the existence of module.exports

var mymodule = (function() { ... })();
if (module && module.exports) {
  module.exports = mymodule;
} else {
  window.mymodule = mymodule;
}
RomainMF
  • 66
  • 3
  • Browserify make `module`, `module.exports`, and `require` available to all bundled files. So, just my bundling makes those available. Thanks for the response. – Bryan Head Apr 28 '13 at 16:28
0

Why not just wrap the entire thing with a closure and pass exports as a parameter?

(function (exports) {
    // code here
    // ...
    exports.foo = bar;
})(exports || this);

This way it will also export it to WebWorker scope and other 'windowless' environments.

YemSalat
  • 19,986
  • 13
  • 44
  • 51