首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Browserify-shim配置一个通用的jQuery插件?

用Browserify-shim配置一个通用的jQuery插件?
EN

Stack Overflow用户
提问于 2014-07-19 01:41:02
回答 4查看 13.8K关注 0票数 41

我使用的是browserify-shim,我想使用一个通用的jQuery插件。我已经多次查看Browserify-shim文档,我只是不知道发生了什么和/或它如何知道在哪里放置插件、附加到jQuery对象等。下面是我的package.json文件的样子:

代码语言:javascript
复制
"browser": {
  "jquery": "./src/js/vendor/jquery.js",
  "caret": "./src/js/vendor/jquery.caret.js"
},

"browserify-shim": {
  "caret": {
     "depends": ["jquery:$"]
  }
}

根据浏览器文档中给出的示例,我不想指定导出,因为这个插件(如果不是所有的jQuery插件)都会自己附加到jQuery对象上。除非我上面做错了什么,否则我不明白为什么它不能工作(我收到一个错误,告诉我函数是未定义的)。见下文:

代码语言:javascript
复制
$('#contenteditable').caret(5);  // Uncaught TypeError: undefined is not a function

所以我的问题是,如何用浏览器化和浏览器化-shim来配置一个通用的jQuery插件(它自己连接到jQuery对象)?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-08-30 18:59:17

在重新审视了这个问题并尝试了更多的事情之后,我终于把我的头集中在了褐化-shim正在做的事情以及如何使用它。对我来说,在我最终理解如何使用browserify-shim之前,我必须掌握一个关键的原则。对于两个不同的用例,基本上有两种方法可以使用浏览器化- shimming :公开和shimming。

背景

假设您只想在标记中插入一个脚本标记(因为测试或性能方面的原因,比如缓存、CDN等)。通过在标记中包含一个脚本标记,浏览器将命中脚本,运行它,并且很可能在窗口对象上附加一个属性(在JS中也称为全局属性)。当然,这可以通过执行myGlobalwindow.myGlobal来访问。但这两种语法都有问题。它不遵循CommonJS规范,这意味着如果一个模块开始支持CommonJS语法(require()),您就无法利用它。

解决方案

Browserify-shim允许您通过CommonJS require()语法指定希望“公开”的全局。请记住,您可以执行var whatever = global;var whatever = window.global;,但不能执行var whatever = require('global'),并期望它为您提供正确的lib/模块。不要对变量的名称感到困惑。这可能是任意的。本质上是使全局变量成为局部变量。这听起来很愚蠢,但这是浏览器中JS的可悲状态。同样,希望库一旦支持CommonJS语法,就永远不会通过窗口对象上的全局附加。这意味着您必须使用require()语法并将其赋值给局部变量,然后在需要的地方使用它。

注意:我发现变量命名在browserify-shim /示例中有些混乱。记住,关键是您希望包含一个lib ,就好像是一个行为正常的CommonJS模块一样。因此,您最终要做的是告诉browserify,当您需要myGlobal require('myGlobal')时,您实际上只想获得窗口对象(即window.myGlobal )上的全局属性。

事实上,如果您对require函数的实际功能感到好奇,这是非常简单的。下面是引擎盖下面发生的事情:

代码语言:javascript
复制
var whatever = require('mygGlobal');

变成..。

代码语言:javascript
复制
var whatever = window.mygGlobal;

曝光

因此,在这种背景下,让我们看看如何在浏览器化-shim中公开一个模块/lib。基本上,你告诉布朗-希姆两件事。调用require()时希望用它访问的名称以及它应该在窗口对象上找到的全局名称。因此,这就是global:*语法的来源。让我们看一个例子。我希望在index.html中使用jquery作为脚本标记,这样我就可以获得更好的性能。下面是我在配置中需要做的事情(在package.json或外部配置JS文件中):

代码语言:javascript
复制
"browserify-shim": {
  "jquery": "global:$"
}

所以这是什么意思。我在其他地方包括了jQuery (记住,browserify-shim不知道我们把标记放在哪里,但它不需要知道),但是当我需要具有字符串参数"jquery“的模块时,我只想得到窗口对象上的$属性。以进一步说明。我也可以这样做:

代码语言:javascript
复制
"browserify-shim": {
  "thingy": "global:$"
}

在本例中,我必须将"thingy“作为参数传递给require函数,以便返回jQuery对象的实例(它只是从window.$获取jQuery ):

代码语言:javascript
复制
var $ = require('thingy');

是的,再说一遍,变量名可以是任何东西。$与实际jQuery库使用的全局属性$没有什么特别之处。尽管使用相同的名称来避免混淆是有意义的。这将最终引用窗口对象上的$属性,如global:$值在package.json中的browserify-shim对象中所选择的那样。

闪鸣

好吧,那就包括曝光了。褐化的另一个主要特征那那是什么?Shimming与公开本质上是一样的,除了将lib或模块包含在HTML标记中(比如脚本标记)之外,您可以告诉browserify-shim本地抓取JS文件的位置。没有必要使用global:*语法。让我们回到我们的jQuery示例,但这一次假设我们不是从CDN加载jQuery,而是将它与所有的JS文件捆绑在一起。下面是配置的样子:

代码语言:javascript
复制
"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": "$"
},

此配置告诉browserify-shim从指定的本地路径加载jQuery,然后从window对象获取$属性,并在需要具有字符串参数的jQuery时将其返回给require函数"jquery“。同样,为了说明起见,您也可以将其重命名为任何其他内容。

代码语言:javascript
复制
"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": "$"
},

这可能需要以下方面:

代码语言:javascript
复制
var whatever = require('thingy');

我建议使用exports属性和depends属性查看browserify-shim文档,以获得更多关于长手语法的信息,如果库依赖于另一个lib /模块,则可以告诉您browserify-shim。我在这里所解释的都适用于两者。我希望这能帮助其他人理解浏览器化-shim实际上在做什么,以及如何使用它。

匿名闪现

匿名shimming是浏览器化-shim的另一种选择,它允许您使用browserify的--standalone选项将lib(如jQuery )转换为UMD模块。

代码语言:javascript
复制
$ browserify ./src/js/vendor/jquery.js -s thingy > ../dist/jquery-UMD.js

如果将其放入脚本标记中,则此模块将以thingy的形式将jQuery添加到窗口对象中。当然,它也可以是$或者你喜欢的任何东西。

然而,如果它是require编辑到您的浏览器化的应用程序包,var $ = require("./dist/jquery-UMD.js");,您可以在应用程序中使用jQuery,而无需将它添加到窗口对象中。

该方法不需要浏览器化-shim,并且利用jQuery的CommonJS感知,它查找一个module对象并将一个noGlobal标志传递到它的工厂,工厂告诉它不要将自己附加到该窗口对象。

票数 98
EN

Stack Overflow用户

发布于 2015-01-11 11:09:51

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

下面是连接到package.json /$对象的jQuery插件的jQuery和app.js文件的示例,例如:$('div').expose()。我不希望jQuery在需要时成为全局变量(window.jQuery),这就是为什么jQuery设置为'exports': null的原因。但是,由于插件需要一个全局jQuery对象,它可以将自己附加到该对象,因此必须在文件名:./jquery-2.1.3.js:jQuery之后的依赖项中指定它。此外,在使用插件时,您需要实际导出jQuery全局,即使您不想这样做,因为插件不能正常工作(至少这个插件是这样的)。

package.json

代码语言:javascript
复制
{
  "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

代码语言:javascript
复制
// 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();
  });
});

在上面的例子中,我不希望我的代码设置任何全局,但为了使插件工作,我不得不暂时这样做。如果您只需要jQuery,就可以这样做,而不需要任何解决办法:var my_jQuery = require('./jquery-2.1.3.js')。如果您可以将jQuery公开为全局的,那么您可以修改上面的package.json示例,如下所示:

代码语言:javascript
复制
  "browserify-shim": {
    "./jquery-2.1.3.js": { "exports": "$" },
    "./jquery.expose.js": { "exports": null, "depends": [ "./jquery-2.1.3.js" ] }

希望这能帮助一些人,他们正在寻找具体的例子(就像我发现这个问题时一样)。

票数 13
EN

Stack Overflow用户

发布于 2016-07-17 14:09:13

为了完整起见,这里有一种方法可以利用jQuery的CommonJS感知来避免担心会污染window对象而不需要实际使用。

特性

  1. 包中包含的jQuery
  2. 包中包含的插件
  3. window对象无污染

配置

在./pacage.json中,添加一个browser节点来为资源位置创建别名。--这纯粹是为了方便起见,没有必要实际移除任何东西,因为模块和全局空间(脚本标记)之间没有通信。

代码语言:javascript
复制
{
  "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对象中(以及需要共享的任何其他上下文)。
  • 在插件的开头添加一行,要求应用程序访问它创建的jQuery实例。
  • 在应用程序中,将jQuery实例复制到$,并在插件中使用jQuery。
  • 使用默认选项浏览应用程序,并将结果包放到HTML中的脚本标记中。

代码

app.cb.js

代码语言:javascript
复制
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();
            })
    );
});

在插件顶部

代码语言:javascript
复制
var jQuery = require("app").jQuery;

在HTML中

代码语言:javascript
复制
<script type="text/javascript" src="app.cb.bundle.js"></script>

背景

jQuery使用的模式是使用noGlobal标志调用它的工厂,如果它感觉到CommonJS环境。它不会向window对象添加一个实例,并将一如既往地返回一个实例。

默认情况下,CommonJS上下文是由浏览器创建的。下面是显示jQuery模块结构的捆绑包的简化摘录。为了清晰起见,我删除了处理window对象同构处理的代码。

代码语言:javascript
复制
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对象进行平移,以便代码是同构的。然后,专注于让它在节点中工作。然后,移除模块与全局空间之间的任何通信量,并最终将其浏览,它将只在浏览器中工作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24835954

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档