用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中的全局属性)上附加一个属性。 当然,这可以通过myGlobalwindow.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添加到窗口对象上。 当然,它也可以是$或任何你喜欢的。

但是,如果requirejoin到您的browserify'd应用程序包中,请使用var $ = require("./dist/jquery-UMD.js"); ,您将在应用程序内部提供jQuery,而无需将其添加到窗口对象。

这个方法并不需要browserify-shim,而是利用jQuery的CommonJS知识来查找module对象,并将一个noGlobal标志传递给它的工厂,告诉它不把它自己附加到窗口对象上。

对于每个人来说,谁在寻找一个具体的例子:

下面是jQuery插件的package.jsonapp.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对象,实际上不需要垫片。

特征

  1. 包中包含jQuery
  2. 包中包含的插件
  3. 没有污染的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.jsongulpfileconfiguration。

的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是不一致的。