用Browserify-shimconfiguration一个通用的jQuery插件?
我正在使用browserify-shim,我想使用一个通用的jQuery插件。 我已经多次浏览过Browserify-shim文档,我似乎无法理解正在发生的事情和/或它如何知道在哪里放置插件,附加到jQuery对象等。下面是我的package.json文件的样子:
"browser": { "jquery": "./src/js/vendor/jquery.js", "caret": "./src/js/vendor/jquery.caret.js" }, "browserify-shim": { "caret": { "depends": ["jquery:$"] } }
根据browserify-shim文档中给出的例子,我不想指定一个输出,因为这个插件(以及大多数,如果不是全部的话,jQuery插件)将自己附加到jQuery对象上。 除非我在上面做错了,我不明白为什么它不起作用(我得到一个错误,告诉我函数是未定义的),当我使用它。 见下文:
$('#contenteditable').caret(5); // Uncaught TypeError: undefined is not a function
所以我的问题是,如何用browserify和browserify-shimconfiguration一个通用的jQuery插件(附加到jQuery对象)?
在重新审视这个并尝试了更多的事情之后,我终于围绕着什么是browserify-shim,以及如何使用它。 对于我来说,在我终于明白如何使用browserify-shim之前,我必须掌握一个关键原则。 对于两种不同的使用情况,基本上有两种使用browserify-shim的方式:公开和匀场。
背景
比方说,您只需要在标记中添加一个脚本标记(用于testing或性能原因,如caching,CDN等)。 通过在标记中包含一个脚本标记,浏览器将会打开脚本,运行它,并且很可能在窗口对象(也称为JS中的全局属性)上附加一个属性。 当然,这可以通过myGlobal
或window.myGlobal
来访问。 但是这两种语法都有问题。 它不遵循CommonJS规范,这意味着如果一个模块开始支持CommonJS语法( require()
),则无法利用它。
解决scheme
Browserify-shim允许你通过CommonJS require()
语法指定一个你想暴露的全局variables。 记住,你可以做var whatever = global;
或var whatever = window.global;
但是你不能做var whatever = require('global')
并期望它能给你正确的lib / module。 不要混淆variables的名称。 这可能是任意的。 你本质上是一个全局variables的局部variables。 这听起来很愚蠢,但它在浏览器中的JS的悲伤状态。 再次,希望是一旦lib支持CommonJS语法,它将永远不会通过窗口对象上的全局附加自身。 这意味着你必须使用require()
语法并将其分配给一个局部variables,然后在需要的地方使用它。
注意:在browserify-shim文档/例子中,我发现variables命名有些混乱。 请记住,关键是你想包括一个库,就好像它是一个正常运行的CommonJS模块。 所以你最终要做的是告诉browserify,当你需要myGlobal require('myGlobal')
你实际上只想给window.myGlobal
的window对象赋予全局属性。
事实上,如果你对需求函数实际上是什么感到好奇的话,那很简单。 以下是发生的情况:
var whatever = require('mygGlobal');
成为…
var whatever = window.mygGlobal;
曝光
所以在这个背景下,我们来看看我们如何在我们的browserify-shimconfiguration文件中公开一个模块/ lib。 基本上,你告诉browserify-shim两件事。 当你调用require()
和它应该期望在window对象上find的全局variables的时候,你希望它的名称可以被访问。 那么这里是global:*
语法的地方。让我们来看一个例子。 我想在jQuery中作为index.html中的脚本标记,所以我得到更好的性能。 这是我需要做的configuration(这将在package.json或外部configurationJS文件):
"browserify-shim": { "jquery": "global:$" }
所以这就是这个意思。 我把jQuery包含在其他地方(记住,browserify-shim不知道我们把标签放在哪里,但是不需要知道),但是我想要的只是当我需要的时候给窗口对象赋予$
属性带有string参数“jquery”的模块。 为了进一步说明。 我也可以做到这一点:
"browserify-shim": { "thingy": "global:$" }
在这种情况下,我必须将“thingy”作为parameter passing给require函数,以获取jQuery对象的实例(它只是从window.$
获取jQuery):
var $ = require('thingy');
是的,再次,variables名称可以是任何东西。 没有什么特别的,就像实际的jQuery库使用的全局属性$
一样。 尽pipe使用相同的名称是有道理的,以避免混淆。 这最终会引用窗口对象上的$
property,如package.json中的browserify-shim
对象中的global:$
值所选。
匀场
好吧,所以这几乎涵盖了暴露。 browserify-shim的另一个主要function是匀场。 那是什么? Shimming的function基本上与公开的相同,除了在HTML标记中包含像lib或模块的脚本标记之类的东西,您可以告诉browserify-shim在本地抓取JS文件的位置。 没有必要使用global:*
语法。 所以让我们回到我们的jQuery示例,但是这次假设我们不是从CDN加载jQuery,而是简单地将它与所有JS文件捆绑在一起。 所以这里是configuration的样子:
"browser": { "jquery": "./src/js/vendor/jquery.js", // Path to the local JS file relative to package.json or an external shim JS file }, "browserify-shim": { "jquery": "$" },
这个configuration告诉browserify-shim从指定的本地path加载jQuery,然后从窗口对象中获取$属性,并返回当你需要带有string参数的jQuery的require函数“jquery”。 同样,出于说明的目的,您也可以将其重命名为其他任何内容。
"browser": { "thingy": "./src/js/vendor/jquery.js", // Path to the local JS file relative to package.json or an external shim JS file }, "browserify-shim": { "thingy": "$" },
可能需要以下内容:
var whatever = require('thingy');
我build议查看browserify-shim文档,了解有关使用exports
属性的long-hand语法的更多信息,以及depends
属性,该属性允许您告诉browserify-shim,如果lib依赖于另一个lib /模块。 我在这里解释的适用于两者。 我希望这可以帮助其他人努力理解什么是浏览器垫片,以及如何使用它。
匿名匀场
匿名填充是--standalone
-shim的替代scheme,它可以让你使用--standalone
的--standalone
选项将像jQuery这样的libs转换成UMD模块。
$ browserify ./src/js/vendor/jquery.js -s thingy > ../dist/jquery-UMD.js
如果你把它放到脚本标记中,这个模块会把jQuery添加到窗口对象上。 当然,它也可以是$
或任何你喜欢的。
但是,如果require
join到您的browserify'd应用程序包中,请使用var $ = require("./dist/jquery-UMD.js");
,您将在应用程序内部提供jQuery,而无需将其添加到窗口对象。
这个方法并不需要browserify-shim,而是利用jQuery的CommonJS知识来查找module
对象,并将一个noGlobal
标志传递给它的工厂,告诉它不把它自己附加到窗口对象上。
对于每个人来说,谁在寻找一个具体的例子:
下面是jQuery插件的package.json
和app.js
文件的示例,该插件附加到jQuery
/ $
对象,例如: $('div').expose()
。 我不想让jQuery
成为全局variables( window.jQuery
),这就是为什么jQuery被设置为'exports': null
。 但是,因为插件需要一个全局jQuery
对象,所以它必须在文件名: ./jquery-2.1.3.js:jQuery
: ./jquery-2.1.3.js:jQuery
之后的依赖项中指定它。 此外,即使不想使用插件,也需要实际导出jQuery
全局插件,因为插件无法正常工作(至less是这个插件)。
的package.json
{ "name": "test", "version": "0.1.0", "description": "test", "browserify-shim": { "./jquery-2.1.3.js": { "exports": null }, "./jquery.expose.js": { "exports": "jQuery", "depends": [ "./jquery-2.1.3.js:jQuery" ] } }, "browserify": { "transform": [ "browserify-shim" ] } }
app.js
// copy and delete any previously defined jQuery objects if (window.jQuery) { window.original_jQuery = window.jQuery; delete window.jQuery; if (typeof window.$.fn.jquery === 'string') { window.original_$ = window.$; delete window.$; } } // exposes the jQuery global require('./jquery.expose.js'); // copy it to another variable of my choosing and delete the global one var my_jQuery = jQuery; delete window.jQuery; // re-setting the original jQuery object (if any) if (window.original_jQuery) { window.jQuery = window.original_jQuery; delete window.original_jQuery; } if (window.original_$) { window.$ = window.original_$; delete window.original_$; } my_jQuery(document).ready(function() { my_jQuery('button').click(function(){ my_jQuery(this).expose(); }); });
在上面的例子中,我不想让我的代码设置任何全局variables,但我暂时不得不这样做,以使插件工作。 如果你只需要jQuery,你可以做到这一点,并不需要任何解决方法: var my_jQuery = require('./jquery-2.1.3.js')
。 如果你的jQuery作为一个全局公开的,你可以修改上面的package.json
例子,如下所示:
"browserify-shim": { "./jquery-2.1.3.js": { "exports": "$" }, "./jquery.expose.js": { "exports": null, "depends": [ "./jquery-2.1.3.js" ] }
希望能帮助一些正在寻找具体例子的人(当我发现这个问题的时候,就像我一样)。
为了完整起见,这里是一个利用jQuery的CommonJS意识的方法,以避免不必担心污染window
对象,实际上不需要垫片。
特征
- 包中包含jQuery
- 包中包含的插件
- 没有污染的
window
对象
configuration
在./package.json中 ,添加一个browser
节点为资源位置创build别名。 这纯粹是为了方便,不需要实际填充任何东西,因为模块和全局空间(脚本标记)之间没有通信 。
{ "main": "app.cb.js", "scripts": { "build": "browserify ./app.cb.js > ./app.cb.bundle.js" }, "browser": { "jquery": "./node_modules/jquery/dist/jquery.js", "expose": "./js/jquery.expose.js", "app": "./app.cb.js" }, "author": "cool.blue", "license": "MIT", "dependencies": { "jquery": "^3.1.0" }, "devDependencies": { "browserify": "^13.0.1", "browserify-shim": "^3.8.12" } }
方法
- 因为jQuery现在已经被CommonJS感知了,所以它会检测到browserify提供的
module
对象的存在并返回一个实例,而不会将其添加到window
对象中。 - 在应用程序中,
require
jQuery并将其添加到module.exports
对象(以及任何其他需要共享的上下文)。 - 在插件的开始处添加一行,以要求应用程序访问其创build的jQuery实例。
- 在应用程序中,将jQuery实例复制到
$
并使用jQuery插件。 - 使用默认选项来浏览应用程序,然后将生成的包放入HTML中的脚本标记中。
码
app.cb.js
var $ = module.exports.jQuery = require("jquery"); require('expose'); $(document).ready(function() { $('body').append( $('<button name="button" >Click me</button>') .css({"position": "relative", "top": "100px", "left": "100px"}) .click(function() { $(this).expose(); }) ); });
在插件的顶部
var jQuery = require("app").jQuery;
在HTML中
<script type="text/javascript" src="app.cb.bundle.js"></script>
背景
jQuery使用的模式是,如果它感觉到CommonJS环境,就用noGlobal
标志调用它的工厂。 它不会将实例添加到window
对象,并将一如既往地返回实例。
CommonJS上下文是由browserify默认创build的。 以下是显示jQuery模块结构的一个简化的摘录。 为了清楚起见,我删除了处理window
对象的同构处理的代码。
3: [function(require, module, exports) { ( function( global, factory ) { "use strict"; if ( typeof module === "object" && typeof module.exports === "object" ) { module.exports = factory( global, true ); } else { factory( global ); } // Pass this if window is not defined yet } )( window, function( window, noGlobal ) { // ... if ( !noGlobal ) { window.jQuery = window.$ = jQuery; } return jQuery; }) ); }, {}]
我发现的最好的方法是让事情在节点模块系统中工作,然后每次浏览之后都会工作。
只需使用jsdom来填充window
对象,以便代码是同构的。 然后,专注于让它在节点中工作。 然后,填充模块和全局空间之间的任何stream量,并最终对其进行浏览并在浏览器中正常工作。
我正在使用wordpress。 因此,我不得不使用window
对象中的wordpress核心jQuery。
当我尝试从npm使用slick()
插件时,它生成了slick()
未定义的错误。 添加browserify-shim
没有多大帮助。
我做了一些挖掘,发现require('jquery')
始终不一致。
在我的主题JavaScript文件中,它调用了wordpress核心的jquery。
但是,在slick
jQuery插件它从节点模块调用最新的jQuery。
最后,我能够解决它。 所以,共享package.json
和gulpfile
configuration。
的package.json:
"browserify": { "transform": [ "browserify-shim" ] }, "browserify-shim": { "jquery": "global:jQuery" },
gulpfile.babel.js:
browserify({entries: 'main.js', extensions: ['js'], debug: true}) .transform(babelify.configure({ presets: ["es2015"] })) .transform('browserify-shim', {global: true})
改变“浏览器 – 填充”是至关重要的部分,我早就错过了。 没有它browserify-shim
是不一致的。