6

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?!"
Brian FitzGerald
  • 3,041
  • 3
  • 28
  • 38
  • Are you bundling those legacy modules with browserify? If not, how are they incorporated into your page? – JMM Apr 16 '15 at 17:05
  • Yes, they are being bundled with Browserify. – Brian FitzGerald Apr 16 '15 at 17:17
  • what exactly are you hoping to do?: A) Just be able to `require('legacyModule')` in your browserified modules, or B) also be able to access `window.myVar`? – JMM Apr 24 '15 at 21:27
  • Also hoping to access window.myVar so that tons of legacy code continues to work as expected. – Brian FitzGerald Apr 27 '15 at 15:10
  • Ok, and that's the part that's not working right now, right? – JMM Apr 27 '15 at 15:46
  • Ok, thanks. Based on the debugging I did last week I got the impression that @EvanDull is correct that it doesn't do or claim to do that, but the docs can easily be read to think they mean that when the "`var foo = ...`...ahem, … NO?!" part you quoted really just means it'll handle exporting (as in `module.exports`) those without them already being on the global object. I'll see if I can look into it further. – JMM Apr 27 '15 at 16:11
  • 1
    Right. Thanks for the feedback. I really appreciate you working through this with me. I agree with you that browserify-shim isn't intending that after-all. My co-worker @EvanDull and I (along with many others I would guess) were rather confused by that for a while as, based on the way the docs are written, it seemed browserify-shim would indeed do the job of exposing the globals our legacy code relies on. If you want to edit your answer based on what we've all discovered I will mark it as solved and perhaps submit a pull request on the browserify-shim docs or, better yet, a feature request. – Brian FitzGerald Apr 28 '15 at 14:44
  • thanks. I edited my answer, and also the question to highlight the part that isn't working as you expected. Sounds good -- if you open an issue there and you think of it, please post a link to it here. – JMM Apr 28 '15 at 15:40
  • @BrianFitzGerald did you ever get a working solution for this? Having the same issue. – YPCrumble Sep 23 '15 at 17:14
  • @YPCrumble, you basically just have to manually set your global (window.myvar) somewhere in your code before the code depending on it needs it. It seems that the browserify docs are indeed ambiguous here and it does not handle this situation as expected. Please see Evan Dull's comments below for additional clarification. – Brian FitzGerald Sep 23 '15 at 18:38

1 Answers1

5

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]);
    });
    
JMM
  • 26,019
  • 3
  • 50
  • 55
  • 1
    Thanks for your response. I realize all browserified modules get wrapped in functions, but my understanding is that addressing the issue of exporting globals from legacy libraries (and defining their dependencies) is the sole reason why browserify-shim exists. I know there are hacky ways to address this issue (i.e. by removing var statement or adding to window explicitly), but to me that seems to largely defeat the purpose of the browserify-shim library. – Brian FitzGerald Apr 16 '15 at 17:46
  • Also, note from the browserify-shim docs: "Additionally, browserify-shim 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?!' ... " (end quote from docs). In their example, they reference a variable defined with the var keyword: var foo = ...; – Brian FitzGerald Apr 16 '15 at 17:50
  • @Brian ah, good point. Can you post a minimal reproduction somewhere like http://plnkr.co/ or GitHub? Where are the legacy scripts stored in the file system? – JMM Apr 16 '15 at 18:08
  • I created a simple github repo trying to demonstrate the issue. [browserify-shim-test](https://github.com/edull24/browserify-shim-test) As you can see, a legacy global variable is attempted to be "exported", but it does not appear in the global scope after being browserify'd. – Evan Dull Apr 16 '15 at 18:42
  • It seems to me either the docs are incorrect or ambiguous. The legacy code IS shimmed and can now be required, however it will no longer work alongside other legacy code still expecting the exported value to be in the global scope. As stated before, you can get around this issue by manually setting window.exportedVal = exportedVal; somewhere in your code, but it seems like either A) based on the docs, browserify-shim is supposed to do this or B) browserify-shim should provide an option to make this happen automatically. I updated the repo to demonstrate manually addressing the issue. – Evan Dull Apr 16 '15 at 19:27
  • @Evan I'm thinking you might be right about it being an ambiguity in the docs. And if that's the case, maybe you're right that handling that case would be a desirable option. – JMM Apr 24 '15 at 21:28