【问题标题】:browserify-shim not exporting implicit globals when they are var scopedbrowserify-shim 在 var 范围内不导出隐式全局变量
【发布时间】:2015-04-16 16:10:16
【问题描述】:

根据browserify-shim 文档,您可以通过在package.json 中使用以下语法来指定browserify-shim 需要从旧模块中公开哪些全局变量:

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

我希望通过require('legacyModule')window.myVar 访问旧模块。

根据我的经验,如果我尝试填充的非commonjs 模块使用window.myVar = x 或仅使用myVar = x,则该模块将在全球范围内公开,并且可以通过require() 按预期使用。

然而,当旧模块使用var myVar = x 时,这就是导致问题的原因,因为该模块只能通过require('legacyModule') 访问,而不能通过window.myVar 访问。

browserify-shim documentation 声明:

此外,它还处理以下现实世界的边缘情况:

  • 仅在脚本级别声明var foo = ... 并假定它附加到window 对象的模块。因为它们唯一的运行方式是在全局环境中运行——“咳咳,……不?!”

【问题讨论】:

  • 您是否将那些遗留模块与 browserify 捆绑在一起?如果没有,它们是如何合并到您的页面中的?
  • 是的,它们与 Browserify 捆绑在一起。
  • 您到底希望做什么?:A) 可以在您的浏览器模块中使用require('legacyModule'),或者B) 也可以访问window.myVar
  • 也希望访问 window.myVar 以便大量遗留代码继续按预期工作。
  • 对。感谢您的反馈。我真的很感谢你和我一起解决这个问题。我同意你的观点,browserify-shim 并不打算这样做。我的同事@EvanDull 和我(以及我猜的许多其他人)对此感到困惑了一段时间,因为根据文档的编写方式,browserify-shim 似乎确实可以完成暴露全局变量的工作我们的遗留代码依赖。如果您想根据我们都发现的内容编辑您的答案,我会将其标记为已解决,并可能在 browserify-shim 文档上提交拉取请求,或者更好的是,提交功能请求。

标签: javascript node.js browserify browserify-shim


【解决方案1】:

正如@EvanDull 所建议的那样,我相信 browserify-shim 可能实际上并未设计为以这种方式工作,并且文档对此缺乏明确性。在我所做的调试中,browserify-shim 似乎没有被设计为在“处理”var foo = ...设置一个全局变量。在文档说它处理的地方,我相信这意味着它处理它尚未在全局对象上设置,并且它仍会为 CommonJS 导出该变量的值,例如var foo = ...; module.exports = foo;,所以它可以是require()'d。而您希望它这样做 var foo = ...; window.foo = module.exports = foo; 当然因为它不这样做并且 browserify 将遗留代码包装在一个函数中,var foo 只创建一个局部变量。

您现在可以使用多种可能的解决方法:

  • 如果您不介意编辑旧版脚本,您可以删除 var,这样就可以解决问题。

  • 您可以通过单独的 <script> 标签提取旧脚本,而不是捆绑它们。

  • 您可以使用 browserify 转换在旧脚本的末尾添加额外的分配 global.myVar = myVar。这将需要为您需要的每个特定脚本定制转换。

  • 您可以将捆绑包中的第一个文件设为执行以下操作的脚本:

    [['legacyModule, 'myVar'], ...].forEach(function (mod) {
      window[mod[1]] = require(mod[0]);
    });
    

【讨论】:

  • 感谢您的回复。我意识到所有浏览器化的模块都包含在函数中,但我的理解是解决从遗留库中导出全局变量(并定义它们的依赖项)的问题是 browserify-shim 存在的唯一原因。我知道有一些解决这个问题的 hacky 方法(即通过删除 var 语句或显式添加到窗口),但对我来说,这似乎在很大程度上违背了 browserify-shim 库的目的。
  • 此外,来自 browserify-shim 文档的注释:“此外,browserify-shim 处理以下现实世界的边缘情况:仅在脚本级别声明 var foo = ... 并假设的模块它被附加到窗口对象。因为它们运行的​​唯一方式是在全局上下文中——“咳咳,……不?!” ...”(来自文档的结束引用)。在他们的示例中,他们引用了一个使用 var 关键字定义的变量:var foo = ...;
  • @Brian 啊,好点。你能在plnkr.co 或 GitHub 之类的地方发布一个最小的复制品吗?遗留脚本存储在文件系统中的什么位置?
  • 我创建了一个简单的 github repo 试图演示这个问题。 browserify-shim-test 如您所见,试图“导出”旧版全局变量,但经过浏览器化后它并未出现在全局范围内。
  • 谢谢@Evan,我去看看。