Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

browserify-shim not exporting implicit globals when they are var scoped

According to the browserify-shim docs, you can specify which globals browserify-shim needs to expose from your legacy modules by using the following syntax in your package.json:

{
    "browserify-shim": {
        "legacyModule": "myVar"
    }
}

I want the legacy module to be accessible via require('legacyModule') and window.myVar.

From my experience, if the non-commonjs module I am trying to shim uses window.myVar = x or just myVar = x, the module is exposed globally and is available via require() as expected.

However, when the legacy module uses var myVar = x, that is what causes the problem as the module is then only accessible via require('legacyModule') and not via window.myVar.

The browserify-shim documentation states that:

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 window object. Since the only way they will ever be run is in the global context — "ahem, ... NO?!"
like image 809
Brian FitzGerald Avatar asked Apr 16 '15 16:04

Brian FitzGerald


1 Answers

As @EvanDull suggested, I believe browserify-shim may not actually be designed to work that way and the documentation lacks clarity on that. In the debugging that I did, it did not appear that browserify-shim is designed to set a global variable when it "handles" var foo = .... Where the documentation says it handles that, I believe it means it handles it not already being set on the global object and it will still export the value of that variable for CommonJS, e.g. var foo = ...; module.exports = foo;, so that it can be require()'d. Whereas you would like it to do var foo = ...; window.foo = module.exports = foo; And of course since it doesn't do that and browserify wraps the legacy code in a function, var foo creates a local variable only.

There are a number of possible workarounds you may be able to use for now:

  • If you don't mind editing the legacy scripts you can just delete the var and that should take care of it.

  • You could pull the legacy scripts in via separate <script> tags instead of bundling them.

  • You could use a browserify transform to add an additional assignment global.myVar = myVar to the end of the legacy script. That would require tailoring the transform for each specific script you need it for.

  • You could make the first file in your bundle a script that does something like:

    [['legacyModule, 'myVar'], ...].forEach(function (mod) {
      window[mod[1]] = require(mod[0]);
    });
    
like image 179
JMM Avatar answered Nov 20 '22 20:11

JMM