【问题标题】:Reusing a Require.js shim config between pages在页面之间重用 Require.js shim 配置
【发布时间】:2012-12-29 17:26:53
【问题描述】:

我有兴趣为我网站上的所有 JavaScript 代码创建一个配置对象。我找到了https://github.com/requirejs/example-multipage-shim,这是此设置的一个示例。

来自https://github.com/requirejs/example-multipage-shim(强调 我的):由于 shim 配置需要依赖项在页面中, 而不是对 page1.html 使用 data-main="js/page1",这个例子 在 HTML 页面中内联 require 调用。 如果使用了 data-main 相反,“js/page1”不能内联任何依赖项, 而是仍然依赖 'common' 和 'app/main1' 构建层 保留模块,由于 shim 配置对 构建。

我不明白加粗的句子。这是否意味着“js/page1”如果存在就不能声明依赖关系?内联依赖是什么意思?内联成什么? HTML 文件还是 JavaScript 文件?

我阅读了有关 shim 配置的 API 文档,但它对优化器的限制尚不清楚。

来自https://github.com/requirejs/example-multipage-shim/blob/master/www/page1.html

    <script src="js/lib/require.js"></script>
    <script>
        //Load common code that includes config, then load the app
        //logic for this page. Do the require calls here instead of
        //a separate file so after a build there are only 2 HTTP
        //requests instead of three.
        require(['./js/common'], function (common) {
            //js/common sets the baseUrl to be js/ so
            //can just ask for 'app/main1' here instead
            //of 'js/app/main1'
            require(['app/main1']);
        });
    </script> 

为什么以下错误?为什么“app/main1”必须与引导(数据主)代码位于单独的模块中?

    <script src="js/lib/require.js"></script>
    <script>
        require(['js/common'], function (common) {
            var underscore = require('underscore');
            // ...
        });
    </script> 

【问题讨论】:

    标签: requirejs


    【解决方案1】:

    我认为避免复制 shim 的唯一真正解决方案可能是结合使用服务器端模板和 grunt.js 等构建处理器。

    如果您想在优化的 require.js 加载和非优化模式之间切换(例如用于开发目的),您只需要服务器端模板部分。

    1. 定义一个包含共享 shim 的 JavaScript 文件。
    2. 如果使用 grunt.js,请使用 node export 语法导出您的 shim 和路径。
    3. 要求将其作为 grunt 配置的一部分。要么写 require.js 配置文件,要么依赖 在 grunt 插件上,您也许可以重用 require'ed 作为 require.js 构建的一部分在内存中配置。
    4. 作为 grunt 构建的一部分,编写后端使用的服务器模板文件 建筑学。例如,如果您使用 django,请编写一个部分 django 模板 未检入存储库。可能在您的 .gitignore 中包含输出路径 如果您使用的是 .git。
    5. 在您的 index.html 中或在您的 require.js 之前将部分加载为全局变量 不使用优化垫片时带有数据主的脚本标记。在您的requirejs 电话中 使用您从模板加载的数据设置或扩展您的 requirejs.config
      Javascript。

    一个不太理想但更简单的解决方案可能是简单地设置一个定义执行上下文的全局变量,然后加载一个共享条目requirejs 脚本,然后在您的上下文变量上使用switch 调用require运行时取决于上下文。这可能更难以优化。更糟糕的是,您可能总是需要所有页面所需的一切,并使用此上下文来确定要运行什么而不是需要什么,但显然您总是在加载所有 JavaScript。这可能在浏览器扩展的上下文中起作用,尽管在处理所有不必要的 JavaScript 时仍然可能会减慢速度。

    说了这么多,如果 requirejs 提供了一种方法来加载与 requirejsdefine 调用分开的配置,那将是很好的,只是为了避免在整个地方声明相同的垫片的情况.

    【讨论】:

    • 这就是我所做的。我通过将配置注入每个文件来构建我的 main.js 文件。然后,在我的 r.js 配置中,我为每个定义模块。
    【解决方案2】:

    在单独的 javascript 文件中定义(使用定义)每个模块是一种很好的做法。否则异步加载几个模块是没有意义的,因为它们位于相同的物理位置。在大多数情况下,您只需要使用函数定义。只有在您的引导模块中,您才需要使用函数 require。

    当我使用 require.js 时,我有 1 个模块 (bootstrap.js),其中包含我的 require.config 对象和初始引导。在 html 页面中,您只需要包含 1 个脚本:require.js,其中 bootstrap 作为 data-main 属性值:

    HTML:

    <script src="js/lib/require.js" data-main="bootstrap"></script>
    

    引导程序:

    require.config = {
       baseUrl: 'js',
       paths: {
         ...
       },
       shim: {
       }
       ...
    };
    
    // initial bootstrap
    require(['jquery', 'angular', 'app'], function($, angular) {
       // do bootstrap
    });
    

    模块:

    define(['jquery'], function($) {
       // do sth with app
    });
    

    编辑:有点误解了这个问题。

    使用 data-main 属性时不能在 html 页面中使用内联依赖项的原因是它可能无法加载它们。哪个代码块将首先执行?数据主引导 js 或内联代码?如果您的引导 js 文件将首先加载并将baseUrl 设置为'js',则内联代码应使用require('common') 而不是require('js/common')。但是如果内联代码首先加载,它必须是require('js/common')

    require('app/main1') 在另一个 require 块中的原因是一样的:模块 'common' 会将 baseUrl 更改为 'js''app/main' 也可能需要来自 'common' 的一些 shim 配置。这是确保公共模块(带有 shim 配置)首先加载的唯一方法。

    【讨论】:

    • 这不是我的问题的答案。我在询问使用 shim 配置选项对优化器的限制。具体来说,我想知道为什么在引导程序 require() 调用中需要 require(['app/main1']) 。见github.com/requirejs/example-multipage。在该项目中,没有使用 shim 配置选项,也没有使用嵌套的 require() 调用。问题是为什么。
    • 我在我的答案中添加了一个额外的部分。这就是我解释你第一个问题的答案的方式。
    • 我可以看到 2 个问题。第一个是您对baseUrl 和路径的编写方式的处理。我真的不明白为什么baseUrl 很好用,因为我更喜欢我的导入语句是绝对的,所以我选择不使用baseUrl
    • 第二个问题是优化器合并文件的方式。据我了解,优化器需要配置,因此它知道内联填充代码的最佳位置。当不使用优化器时,这无关紧要,并且不需要嵌套的 require() 调用,因为声明对 shim 的依赖会触发下载 shim 的代码。
    【解决方案3】:

    当您使用 shim 配置时,为您希望异步加载的每个 shim 添加匹配的 paths 配置属性:

    requirejs.config({
        paths: {
            backbone: 'lib/backbone',
            jquery: 'lib/jquery',
            underscore: 'lib/underscore'
        },
        shim: {
            backbone: {
                deps: ['jquery', 'underscore'],
                exports: 'Backbone'
            },
            underscore: {
                exports: '_'
            },
            jquery: {
                exports: '$'
            }
        }
    });
    

    shim 模块可以像任何其他真实模块一样用作define() 中的依赖项。 (至少这是我的经验!)

    【讨论】:

    • 这个答案没有解决我的任何问题。
    • Hekevintran,你让 RequireJS 变得比它需要的更复杂。这个答案显示了一个更简单的策略。
    • 我了解如何使用 shim 和路径配置选项。 如果您不使用 Require.js 优化器,这可以正常工作。您所写的内容并未说明如何保证在data-main 如果我使用优化器 中的代码之前加载已填充的代码。如果有,请解释。
    • 根据我使用这种 pathsshim 方法的经验,优化器确实正确排序了已填充的模块。它没有为您正确排序的原因是因为您在模块函数中使用require(),而不是使用define([dependencies]) 参数。 ...或者我误解了你的问题。
    • 示例来自Require.js的作者。他的配置和填充代码位于common。据我了解,如果您要编写类似define(['common', 'underscore'], ...) 的内容,则不能保证首先加载common(包含下划线)。尝试首先加载 underscore 是错误的,因为它在加载 common 之前没有定义。
    猜你喜欢
    • 2013-03-23
    • 1970-01-01
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-04
    • 1970-01-01
    • 2013-09-18
    相关资源
    最近更新 更多