Require.js是伤害我的大脑。 有关办法的一些基本问题,它加载脚本/模块(Require.

2019-07-29 22:12发布

让我们假设这是我的config.js或main.js:

require.config({
    // paths are analogous to old-school <script> tags, in order to reference js scripts
    paths: {
        jquery: "libs/jquery-1.7.2.min",
        underscore: "libs/underscore-min",
        backbone: "libs/backbone-min",
        jquerymobile: "libs/jquery.mobile-1.1.0.min",
        jquerymobilerouter: "libs/jquery.mobile.router.min"
    },
    // configure dependencies and export value aliases for old-school js scripts
    shim: {
        jquery: ["require"],
        underscore: {
            deps: ["jquery"],
            exports: "_"
        },
        backbone: {
            deps: ["underscore", "jquery"],
            exports: "Backbone"
        },
        jquerymobilerouter: ["jquery", "backbone", "underscore"],
        jquerymobile: ["jquery", "jquerymobilerouter", "backbone", "underscore"]
    }
});
require(["jquery", "backbone", "underscore", "app/app.min", "jquerymobilerouter", "jquerymobile"], function ($, Backbone, _, App) {
    console.log($);
    console.log(Backbone);
    console.log(_);
    $("body").fadeIn(function () {
        App.init();
    });
});
  1. 如果我理解正确的paths配置选项可以让你引用的脚本,一拉的<script> HTML标签内。 假如是这样的话,我还需要别名脚本像jQuery用$或用下划线_在我的实际需要下面的语句? 看来奇怪的是,我必须,因为如果引用的jQuery用标准<script>标记, $可以在整个脚本会自动使用。 使用它不应该是相同的paths

  2. 我是新来的shim配置选项,我的理解已经取代过时的order! 插入。 什么是exports属性实际上做什么? 它似乎并不创建一个脚本的别名; 例如,如果我设置exports为下划线"whatever" ,然后尝试console.log(whatever) ,这是不确定的。 那么,有什么意义呢?

  3. 怎么会像jQuery脚本可以正常使用“全球?” 也就是说,什么是正确的方法可以使用$我App.js模块内的别名,或任何其他模块在我的“应用程序”文件夹? 我必须每一个人模块和别名内需要的jQuery $每一次? 或者就是这样,我在这里做了正确的方法是什么?

我非常感谢这个特殊的脚本以及其他任何批评; 对于Require.js的文件,在我看来,叶不理想; 的事情,我真的很想知道更多关于似乎得到掩盖,让我抓我的头。

Answer 1:

  1. 路径告诉require.js就是当你需要依赖的样子。

    例如,我有事情可以这样来配置:

     "paths": { "jquery": "require_jquery" }, "shim": { "jquery-cookie" : ["jquery"], "bootstrap-tab" : ["jquery"], "bootstrap-modal": ["jquery"], "bootstrap-alert": ["jquery"] }, 

    这意味着,在一个模块中,每次我这样做

     define( ['jquery'] 

    requirejs加载文件require_jquery从主路径,而不是试图加载的jquery.js。 在你的情况下,它会加载jQuery的源文件,那么这将是全局可用。 我个人不喜欢这种做法,为此,在require_jquery.js文件我做的:

     define( ["jquery_1.7.2"], function() { // Raw jQuery does not return anything, so return it explicitly here. return jQuery.noConflict( true ); } ); 

    这意味着jQuery将仅在我的模块中定义。 (这是因为我写的WordPress插件,所以我可以有我自己的jQuery的版本不接触外界版)

  2. 出口(从文档阅读简单的应该是您正在使用,以便它可以加载,如果去正确地检测模块的名称。 这里解释。所以,如果你想设置一个出口的底线应该是_

  3. jQuery的应该是全球性的,我解释说,如果你只是导入它执行的文件和jQuery是全球性的

编辑 - 回答的意见。

  1. 是我的意思是,你必须导出$或jQuery的为jQuery和_骨干。 从我从这个只在一些边缘的情况下所需要的文档了,并为宣布自己在全局命名空间为jQuery的库就没有必要。

    我认为requirejs需要他们时,它已经从从CDN加载jQuery的退却。 我认为requirejs首先尝试从CDN加载jQuery的联系,然后进行检查,以验证它是通过检查“出口”变量存在正确加载,如果没有加载它形成了本地文件系统(如果你已经配置了回退,当然)。 这是什么时候requirejs无法看到404回来,它的需要。

  2. 因为它宣布全球jQuery是全球可用。 如果你只是加载并执行jQuery脚本,你最终将有两个全局变量, $jQuery (或者你可以做我做,避免)。 里面的define()函数,你可以jQuery的别名是任何你想要的。

     define( [ 'jquery' ], function( jq ) { // jq is jquery inside this function. if you declared it // globally it will be also available as $ and jQuery } ); 


Answer 2:

只是为了澄清周围任何混乱exports ,它假定任何垫片库附加一个属性,以全球范围内( windowroot ),或者修改已经存在的全局属性(如jQuery插件)。 当requireJS获取命令加载匀依赖,它会检查相匹配的属性在全球范围内exports是垫片配置的价值,如果它发现它,并将它作为该模块的价值。 如果没有找到它,然后它加载相关的脚本,等待它来执行,然后查找全局符号并将其返回。

记住一个重要的事实是,除非垫片配置包含exports值,任何init对配置方法不会被执行。 依赖装载机必须找到该模块的值(这是exports指定)之前,该模块可以被初始化,这就是为什么如果有一个垫片所需的属性init该模块。

更新:我还需要指出的是,如果有问题调用模块define的任何地方,任何垫片的配置你有该模块将被忽略。 这实际上使我有些头疼,因为我想用垫片配置调用jQuery的jQuery.noConflict(true)方法来未globify jQuery和保持它的作用域只需要它的模块,但不能设法得到它的工作。 (在底部在如何轻松地做到这一点使用地图配置,而不是垫片的配置信息,请参阅更新。)

更新2:在谷歌requireJS A组最近的问题使我意识到,我的解释可能会有些误导,所以我想澄清一下。 RequireJS只会重新使用匀依赖,如果它是通过requireJS加载至少一次 。 也就是说,如果你只是有一个<script>托管网页上的标签(比如说,例如,下划线),就像这样:

<script src='lib/underscore.js'></script>
<script src='lib/require.js' data-main='main.js'></script>

...你有你的requireJS的配置是这样的:

paths: {
    'underscore': 'lib/underscore'
},
shim: {
    'underscore': {
        exports: '_'
    }
}

然后在第一时间你define(['underscore'], function (_) {});var _ = require('underscore'); ,RequireJS将重新加载下划线库而不是重复使用先前定义window._ ,因为据requireJS知道,你从来没有加载下划线。 当然,它可以检查是否_已经在根范围内定义的,但它没有验证的方式_这已经有一样你定义的paths配置。 例如,两个prototypejquery分配自己window.$默认情况下,如果requireJS假设“窗口。$”是jQuery的时候它实际上是原型,你要在一个糟糕的情况。

所有这一切意味着,如果你混合和匹配脚本加载风格类似的,你的页面会风了这样的事情:

 <script src='lib/underscore.js'></script>
 <script src='lib/require.js' data-main='main.js'></script>
 <script src='lib/underscore.js'></script>

当第二个下划线实例是requireJS加载的一个。

基本上,图书馆通过requireJS将要加载requireJS有它的知识。 然而, 接下来你需要下划线时,requireJS会去“哎,我已经加载的,所以才交回无论exports值和不担心加载另一个剧本。”

这意味着你有两个真正的选择。 一个是我所认为的反模式:根本不使用requireJS表达对全球脚本的依赖。 也就是说,只要库附加一个全局的根上下文,你就可以,如果没有明确要求的依赖来访问它,事件。 你可以看到为什么这是一个反模式 - 你基本上只是消除了大部分的优点,使用AMD装载机(显式依赖上市和便携性)。

另外,更好的选择是使用requireJS加载一切,那唯一实际的脚本标签,你应该自己创建的程度是最初加载requireJS之一。 您可以使用垫片,但95%的时间它真的并不难AMD的包装增加了脚本,而不是。 它可能需要更多一点的工作转换所有非AMD库是AMD兼容,但一旦你做了一个或两个它变得轻松很多 - 我可以采取任何通用的jQuery插件,并将其转换为AMD模块在不到一分钟。 它通常只是一个加入的事情

define(['jquery'], function (jQuery) {

在顶部,

    return jQuery;
});

在底部。 我之所以有“jQuery的”映射到jQuery ,而不是$的是,我注意到大多数的插件,这些天被包裹在这样一个封闭:

(function ($) {
    // plugin code here
})(jQuery);

而且它关注的预期范围是一个好主意。 你可以“jQuery的”肯定映射到$直接不过,假设插件没有希望找到jQuery而不是$ 。 这仅仅是基本的AMD封装 - 更复杂的一般尝试检测什么样的装载机正在使用(CommonJS的VS AMD VS普通醇”全局),并根据对结果有不同的放置方式。 您可以在谷歌几秒钟找到这样的例子很容易。

更新:我曾经使用支持的解决方法jQuery.noConflict(true)与RequireJS的工作,但它需要一个非常小的修改jQuery的来源,因为我已经想出了一个更好的方法来完成同样的事情,而无需修改jQuery的。 幸运的是,这么有詹姆斯·伯克,RequireJS的作者,谁把它添加到RequireJS文档: http://requirejs.org/docs/jquery.html#noconflictmap



文章来源: Require.js is hurting my brain. Some fundamental questions about the way it loads scripts/modules