thlorenz / browserify-shim

📩 Makes CommonJS incompatible files browserifyable.
MIT License
933 stars 87 forks source link

Shim and prevent attaching to global window #137

Closed jmullo closed 9 years ago

jmullo commented 9 years ago

My understanding is that currently it's not possible to shim a non-CommonJS library so that it can be required in the code but also prevent it from attaching itself to global window?

Would that be possible to implement? Like this:

var SomeLib = require("SomeLib");

--> SomeLib == SomeLib --> window.SomeLib == undefined

bendrucker commented 9 years ago

Correct. Why do you want this?

jmullo commented 9 years ago

Then I would be able to create bundles without the risk of potential conflicts between different versions of those non-CommonJS libraries. The hosting web page has version 2 and the bundle contains version 3.

hiquest commented 9 years ago

+1 for this.

This is the kind of behaviour I expected to find out-of-the-box. And what's more, when we use nodejs jquery module and using it with browserify, it doesn't expose itself on window. But if we add some jquery plugin and shim it with browserify-shim, after that we find jQuery (or whatever the dependency called) to be on window and that's browserify-shim to be blamed for that behaviour.

For example after compilation there's the following line:

; jQuery = global.jQuery = require("jquery");

Why do you have to expose this on global (which is window in that case)? Can't that just be

; var jQuery = require("jquery");

?

thlorenz commented 9 years ago

browserify-shim does not and will not remove globals. The main reason is that other libraries that depend on it being global (i.e. jquery plugins) would break once we'd mess with globals.

Feel free to remove the global if it is such a big deal to you.

If you get version conflict and are frustrated by that please stop using non-commonJS libs. Even if we would remove the global that wouldn't completely fix those conflicts in most cases.

FWIW deglobalify exists, hopefully that will fix your problem.

Closing as won't fix.

hiquest commented 9 years ago

Ok, thank you @thlorenz, guess that's just me getting that wrong and trying to solve my problems with the wrong tool.

And just to make sure you get my point. browserify-shim should not remove globals, that's totally fine. But what it does, it actually adds globals by itself. Like when you use jquery (which is commonJS ready) with browserify window.jQuery is undefined. But if you add some jquery plugin and shim it, then you get jQuery exposed on window as a side effect (and this is what browserify-shim does, not the plugin itself).

I'm just wondering whether this side-effect can be eliminated or is this the only way we can do that.

thlorenz commented 9 years ago

Like when you use jquery (which is commonJS ready)

In that case don't shim jquery ;) as only non-commonJS ready libs should be shimmed.

if you add some jquery plugin and shim it

That's an example of where the jq plugin would fail if it wouldn't find jquery globally and no that mess can not be fixed until all these plugins get fixed to work with non-globals.

hiquest commented 9 years ago

I do not shim jquery. There's no point doing that, I understand. I have to shim the plugins, though.

Most of the plugins look like this:

(function($) {
    // do stuff with $
})(jQuery)

and what you do with broserify-shim is wrap that with something like

(function() {

// Here is where you put jQuery on window !!!
jQuery = global.jQuery = require('jquery')

(function($) {
    // do stuff with $
})(jQuery)
} ()

But if you would just do

(function() {

// Here is where you put jQuery on window !!!
var jQuery = require('jquery')

(function($) {
    // do stuff with $
})(jQuery)
} (...)

that would solve it all. Although I do understand that for some plugins that approach may not work at all.

thlorenz commented 9 years ago

that would solve it all

no, it wouldn't cause you cannot be sure where the plugins are looking for jquery, some may do global.$, some window.jQuery or this.jQuery, you never know believe me I encountered all those cases.

Your solution would work exactly for those that just look for jQuery in the execution context.

ebertech commented 9 years ago

what about a noConflict type of deal where the shimmed global would be restored after the call as it pops up the stack? Presumably once the non-cjs file is evaluated it will be using the jQuery or $ that was in the closure... or am I missing something?

so basically,

var oldGlobal = global.jQuery; ; jQuery = global.jQuery = require("jquery"); --- shim() --- global.jQuery = oldGlobal;

hiquest commented 9 years ago

As a general solution that also would not work. Cause there may be some inner function that use window.jQuery in a closure. So by the time such function get invoked window.jQuery won't be there.

ebertech commented 9 years ago

Yeah, I thought of that after. I mean... at some point if a library is doing something that stupid it'll need workarounds regardless... do you think it could be like a "strict" mode that can be enabled on browserify-shim as a flag that would do the global restoration? It'd be disabled by default to maximize compatibility but if people wanted to turn it on then the shim would inject that clean up code. I understand that this project is trying to work with as many libraries as possible, I'm just trying to see if there's a compromise.

art-solopov commented 8 years ago

The problem I have with this is that it causes some problems with strict mode.

Can we at least have var jQuery = global.jQuery = require("jquery")?

P. S. I tried fixing it myself, but some tests fail, and I don't know enough JS to fix it.