javascript 使用Browserify-shim配置通用jQuery插件?

42fyovps  于 2022-12-25  发布在  Java
关注(0)|答案(4)|浏览(89)

我正在使用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-shim配置一个通用jQuery插件(它将自己附加到jQuery对象)?

jv2fixgn

jv2fixgn1#

在重新审视这个问题并尝试了更多的东西之后,我终于明白了browserify-shim在做什么以及如何使用它。对我来说,在我最终理解如何使用browserify-shim之前,我必须掌握一个关键原则。基本上有两种方法可以在两种不同的用例中使用browserify-shim:曝光和填隙。
背景
假设您只想在标记中放入一个script标记(出于测试或性能原因,如缓存、CDN等)通过在标记中包含脚本标签,浏览器将命中脚本,运行它,并且很可能在窗口对象上附加一个属性(在JS中也称为全局变量)。当然,这可以通过myGlobalwindow.myGlobal来访问。但是这两种语法都有问题。不要遵循CommonJS规范,这意味着如果一个模块开始支持CommonJS语法(require()),你就不能利用它。

解决方案

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

注意:我发现browserify-shim docs/examples中的变量命名有点混乱。记住,关键是你想包含一个lib就好像它是一个正常运行的CommonJS模块一样。所以你最终要做的是告诉browserify当你需要myGlobal require('myGlobal')时,你实际上只想得到窗口对象的全局属性window.myGlobal

事实上,如果你想知道require函数的作用,其实很简单,下面是它的内部情况:

var whatever = require('mygGlobal');

变成了...

var whatever = window.mygGlobal;

暴露

在此背景下,让我们看看如何在browserify-shim配置中公开模块/库。基本上,你告诉browserify-shim两件事。当你调用require()时你希望它可以访问的名字和它应该期望在窗口对象上找到的全局变量。所以这里是global:*语法的用武之地。让我们看一个例子。我想把jquery作为脚本标签放到index.html中,这样我可以获得更好的性能。下面是我需要在我的配置文件中做的事情(这可能是在package.json或外部配置JS文件中):

"browserify-shim": {
  "jquery": "global:$"
}

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

"browserify-shim": {
  "thingy": "global:$"
}

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

var $ = require('thingy');

当然,变量名可以是任何名称。$与实际jQuery库使用的全局属性$相同并没有什么特别之处。尽管使用相同的名称以避免混淆是有意义的。这最终会引用窗口对象上的$属性。由package.json中browserify-shim对象中的global:$值选择。

匀场

好了,以上内容基本上涵盖了公开。browserify-shim的另一个主要特性是shimming。那是什么呢?Shimming本质上和公开做的是一样的事情,除了在HTML标记中包含库或模块,而不是像script标记一样。你告诉browserify-shim在哪里本地获取JS文件,不需要使用global:*语法,所以让我们回头看看jQuery示例,但这次假设我们不是从CDN加载jQuery,而是简单地将其与所有JS文件绑定在一起。

"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,然后从窗口对象中获取$属性,并在需要jQuery的require函数的string参数时返回该属性。同样,为了便于说明,您也可以将其重命名为其他任何名称。

"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');

我建议查看browserify-shim文档,了解使用exports属性的详细语法信息,还有depends属性,它允许你告诉browserify-shim一个库是否依赖于另一个库/模块。

匿名垫片

匿名shimming是browserify-shim的一种替代方案,它允许您使用browserify的--standalone选项将jQuery等库转换为UMD模块。

$ browserify ./src/js/vendor/jquery.js -s thingy > ../dist/jquery-UMD.js

如果把它放到一个script标记中,这个模块会把jQuery作为thingy添加到窗口对象中,当然它也可以是$或任何你喜欢的东西。
然而,如果它是x1m25 n1艾德您的browserify的应用程序包var $ = require("./dist/jquery-UMD.js");中,您将在应用程序中使用jQuery,而无需将其添加到窗口对象中。
此方法不需要browserify-shim,并利用jQuery的CommonJS感知功能,查找module对象,并将noGlobal标志传递到其工厂,告知其不要将自身附加到窗口对象。

lstz6jyr

lstz6jyr2#

对于每个人,谁正在寻找一个具体的例子:
以下是jQuery插件的package.jsonapp.js文件示例,该插件将自身附加到jQuery/$对象,例如:$('div').expose()。我不希望jQuery在我需要它的时候成为一个全局变量(window.jQuery),这就是为什么jQuery被设置为'exports': null。但是,因为插件需要一个全局jQuery对象,它可以将自己附加到这个对象上,所以你必须在依赖项中的文件名后面指定它:此外,在使用插件时,即使你不想导出,你也需要导出jQuery全局文件,因为如果不这样的话,插件将无法工作(至少这个插件是这样的)。

    • 包. 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"
    ]
  }
}
    • 应用程序. 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();
  });
});

在上面的例子中,我不希望我的代码设置任何全局变量,但为了让插件工作,我暂时不得不这样做。如果你只需要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" ] }

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

bkhjykvo

bkhjykvo3#

为了完整起见,这里有一个方法,它利用jQuery的CommonJS感知来避免担心污染window对象,而实际上并不需要shim。

功能

  1. jQuery包含在包中
    1.套件中包含的插件
  2. window物体无污染

配置

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

{
  "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

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 * 创建。下面是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对象,使代码同构,然后,只需关注如何使其在节点中工作,然后,填充模块和全局空间之间的任何流量,最后浏览器化它,它将只在浏览器中工作。

1cklez4t

1cklez4t4#

我使用的是wordpress,因此,我被迫使用wordpress核心的jQuery,它在window对象中可用。
当我尝试使用npm中的slick()插件时,它产生了slick()未定义错误。添加browserify-shim没有多大帮助。
我做了一些调查,发现require('jquery')并不总是一致的。
在我的主题javascript文件中,它调用的是wordpress core的jquery。
但是,在slick jquery插件中,它从节点模块调用最新的jquery。
最后,我能够解决它。所以,共享package.jsongulpfile配置。

    • 包. json:**

"browserify": { "transform": [ "browserify-shim" ] }, "browserify-shim": { "jquery": "global:jQuery" },

    • 巴别塔文件,js:**

browserify({entries: 'main.js', extensions: ['js'], debug: true}) .transform(babelify.configure({ presets: ["es2015"] })) .transform('browserify-shim', {global: true})
转换"browserify-shim"是很重要的部分,我之前忽略了。没有它,browserify-shim就不一致了。

相关问题