经过重新审视和尝试了一些方法后,我最终理解了browserify-shim是做什么以及如何使用它。对我来说,在我最终理解如何使用browserify-shim之前,有一个关键原则我必须掌握。基本上有两种使用browserify-shim的方式:暴露和shimming,它们适用于不同的用例。
背景
假设您只想在标记中放置一个脚本标签(出于测试或性能原因,如缓存、CDN等)。通过在标记中包含脚本标签,浏览器将命中该脚本,运行它,并很可能在window对象上附加一个属性(也称为JS中的全局变量)。当然,可以通过执行myGlobal
或window.myGlobal
来访问它。但是这两种语法都存在问题。它们不遵循CommonJS规范,这意味着如果模块开始支持CommonJS语法(require()
),您将无法利用它。
解决方案
Browserify-shim允许您指定一个希望通过CommonJS require()
语法“公开”的全局变量。请记住,您可以执行var whatever = global;
或var whatever = window.global;
,但是您不能执行var whatever = require('global')
并期望它给您提供正确的库/模块。不要对变量名称感到困惑。它可以是任意的任意命名。实际上,您将全局变量变为一个局部变量。听起来很愚蠢,但这是JS在浏览器中处于悲惨状态的表现形式。再次强调,希望一旦库支持CommonJS语法,它就永远不会通过window对象上的全局变量自身附加自己。这意味着您必须使用require()
语法将其分配给本地变量,然后在需要时使用它。
注意:我发现browserify-shim文档/示例中变量命名略微令人困惑。请记住,关键是您希望包含一个库,并像一个行为正常的CommonJS模块一样使用。因此,您实际上告诉browserify,当您需要myGlobal require('myGlobal')
时,您实际上只想得到window对象上的全局属性window.myGlobal
。
实际上,如果您对require函数的实际操作感到好奇,那么它非常简单。以下是其背后发生的事情:
var whatever = require('mygGlobal');
变成...
var whatever = window.mygGlobal;
暴露模块
有了这个背景,让我们看看如何在browserify-shim配置中暴露一个模块/库。基本上,你需要告诉browserify-shim两件事情。当你调用require()
时想要访问的名称和它应该在window对象上找到的全局变量。这就是global:*
语法发挥作用的地方。让我们看一个例子。我想将jquery作为脚本标记放入index.html中,以获得更好的性能。这就是我在配置文件中需要做的事情(这将在package.json或外部配置JS文件中):
"browserify-shim": {
"jquery": "global:$"
}
所以这就是它的意思。我已经在其他地方包含了jQuery(记住,browserify-shim不知道我们放置了哪个标签,但它不需要知道),但我想要的只是当我使用字符串参数“jquery”请求模块时,在window对象上给出
$
属性。为了进一步说明。我也可以这样做:
"browserify-shim": {
"thingy": "global:$"
}
在这种情况下,我需要将“thingy”作为参数传递给require函数,以便获取jQuery对象的实例(它只是从
window.$
获取jQuery):
var $ = require('thingy');
是的,变量名可以是任何东西,$
与jQuery库使用的全局属性$
没有什么特别之处。尽管使用相同的名称很有意义,可以避免混淆。这最终会引用在package.json
中的browserify-shim
对象中选择的global:$
值来选定window对象上的$
属性。
Shimming
好的,那基本上涵盖了曝光。 browserify-shim 的另一个主要功能是 shimming。那是什么? Shimming 本质上与 exposing 做的事情相同,但不同的是,您告诉 browserify-shim 在哪里本地抓取 JS 文件,而不是像使用 script 标记一样在 HTML 标记中包含 lib 或模块。无需使用 global:*
语法。因此,让我们回到我们的 jQuery 示例,但这次假设我们不是从 CDN 加载 jQuery,而只是将其与所有 JS 文件捆绑在一起。所以配置看起来像:
"browser": {
"jquery": "./src/js/vendor/jquery.js",
},
"browserify-shim": {
"jquery": "$"
},
这个配置告诉browserify-shim从指定的本地路径加载jQuery,然后从window对象中获取$属性,并在需要使用require函数的字符串参数来要求jQuery时返回它。同样举例说明,您也可以将此重命名为任何其他名称。
"browser": {
"thingy": "./src/js/vendor/jquery.js",
},
"browserify-shim": {
"thingy": "$"
},
这可能需要:
var whatever = require('thingy');
我建议查看browserify-shim文档,了解使用exports
属性和depends
属性的长写法的更多信息。其中depends
属性允许您告诉browserify-shim一个库是否依赖于另一个库/模块。我在这里解释的适用于两者。
匿名Shimming
匿名shimming是browserify-shim 的替代方案,它可以让您使用browserify的--standalone
选项将类库(如jQuery)转换为UMD模块。
$ browserify ./src/js/vendor/jquery.js -s thingy > ../dist/jquery-UMD.js
如果将它放在脚本标签中,该模块会将jQuery添加到窗口对象中作为thingy。当然也可以是$或其他你喜欢的名称。
然而,如果它是在您的browserify应用程序包中通过require引入的,就像这样:
var $ = require("./dist/jquery-UMD.js");
,则可以在应用程序中使用jQuery而无需将其添加到窗口对象中。
这种方法不需要使用browserify-shim,并利用了jQuery对CommonJS的支持,其中它寻找一个模块对象并将noGlobal标志传递给其工厂,告诉它不要将自己附加到窗口对象上。