Browserify: Provide a way to build standalone bundles without UMD

Created on 16 Jan 2015  路  10Comments  路  Source: browserify/browserify

Currently the --standalone flag wraps the whole code in a silly UMD wrapper. This isn't really helpful if you just want the standalone to register it self always as global. There should be away to turn UMD off, or provide your own template instead.

Most helpful comment

Hey @jstayton - sure thing.

All Browserify bundles are defined within a wrapping closure so nothing in your bundle will leak out. The issue is that JavaScript doesn't currently provide a good way to keep global variables from "leaking in". In other words, your code and bundled dependencies can reference global variables that someone else defined.

Imagine that your script is deployed to a site that's already using AMD. AMD defines a global define function. No problem - that shouldn't affect your code. Now imagine that your code includes a UMD dependency that goes looking for the existence of define to decide whether it should behave as an AMD or CommonJS script. Now you have a problem, since your dependency will convert itself to AMD in this environment.

Ideally JavaScript would provide a way for a closure to "whitelist" which global variables it could access - window for example. Since this feature doesn't exist, we instead need to blacklist the global variables the closure doesn't want access to by redefining them within the closure.

When (and only when) you use the --standalone flag, Browserify does exactly this for define, module, and exports.

All 10 comments

+1

The --standalone flag has the benefit of redefining define, module, and exports to prevent leakage. This is critical when scripts are being deployed to 3rd party sites.

_Side Note: Looks like documentation is lacking on this point._

Sealing the bundle environment (as accomplished by --standalone) should be possible without the requirement that the script be enclosed in a UMD wrapper.

I suggest:

  1. Seal the environment by default
  2. Rename the --standalone option to --umd

@substack - thoughts?

@aldendaniels Curious about this part of your comment:

The --standalone flag has the benefit of redefining define, module, and exports to prevent leakage. This is critical when scripts are being deployed to 3rd party sites.

I'm _not_ using the --standalone flag, and I'm not seeing any of those three variables being leaked. Nor am I seeing any problems if they're already defined beforehand.

I'm working on a third party script, so I want to make sure I'm not misunderstanding your comment and the purpose of this issue. Thanks! :smile:

Hey @jstayton - sure thing.

All Browserify bundles are defined within a wrapping closure so nothing in your bundle will leak out. The issue is that JavaScript doesn't currently provide a good way to keep global variables from "leaking in". In other words, your code and bundled dependencies can reference global variables that someone else defined.

Imagine that your script is deployed to a site that's already using AMD. AMD defines a global define function. No problem - that shouldn't affect your code. Now imagine that your code includes a UMD dependency that goes looking for the existence of define to decide whether it should behave as an AMD or CommonJS script. Now you have a problem, since your dependency will convert itself to AMD in this environment.

Ideally JavaScript would provide a way for a closure to "whitelist" which global variables it could access - window for example. Since this feature doesn't exist, we instead need to blacklist the global variables the closure doesn't want access to by redefining them within the closure.

When (and only when) you use the --standalone flag, Browserify does exactly this for define, module, and exports.

Thanks for the great explanation, @aldendaniels! Makes sense. I am very much for this change as well.

@3rd-Eden, you can achieve your desired behavior today using the https://github.com/primus/deumdify plugin. It's a hack, but a useful and well-maintained one. :)

@aldendaniels I'm the author of primus ;-) deumdify is hack we had to pull off in order get this horrible stuff to work.

@3rd-Eden - Thanks for sharing your hack with the rest of us! I'm it now to very good purpose. :)

In case anyone wants to submit a PR with a less hacky solution, I think this is the code you'd want to change: browser-pack/index.js#L46

@3rd-Eden - To clarify, "hack" was not meant here as a criticism. It's more like subversive praise for the ingenious nature of your solution. Still, it would be great for Browserify to offer built-in support for this.

@aldendaniels there is also global-wrap which is what we used in Primus before our build scripts became complex enough to require a more feasible solution.

With some other "hacks" (postprocessing) it is also possible to provide custom UMD wrappers or "seal" bundles generated without the --standalone option.

Anyway these workarounds are fragile and a minimal change in the code of Browserify or its dependencies can break their functionality.

For this reason I agree that Browserify should offer built-in support for this.

Not sure if this is the right location for this issue, it's similar/related.

Currently --standalone only works on the first build. If using browserify with watch: true and keepAlive: true, subsequent builds after the first one ignores --standalone altogether, thereby preventing all of the modules from being exposed.

The only workaround right now is to build without keepAlive with lengthens the build time dramatically.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ericmorand picture ericmorand  路  6Comments

ghost picture ghost  路  4Comments

esamattis picture esamattis  路  11Comments

saeedseyfi picture saeedseyfi  路  6Comments

jankuca picture jankuca  路  3Comments