如何在生产环境中动态加载多个经过优化的RequireJS模块?

7
我已经开始在一个虚拟项目中尝试使用require js。现在,我想使用r.js脚本来构建我的项目以用于生产环境。
上下文如下:
  • Main file called start.js is:

    require([/* some stuff */], function (){ /* app logic */ });
    

    which has an if that decides what I should require based on some condition.

  • The required files are either ModuleA or ModuleB

  • Both ModuleA and ModuleB have dependencies.

    define([/*some deps*/], function(dep1, dep2...) { 
        /* app logic */ 
        return { /* interface */
    }
    
  • Everything works fine in development mode, before optimization and module concatenation.

  • When building with r.js I specify as module targets the following : modules : [ { name : "start" }, { name : "ModuleA" }, { name : "ModuleB" } ]

问题在于我的ModuleA变成了:
 define(dep1 ..);
 define(dep2 ..);
 define(ModuleA ..);

但是ModuleA中没有加载任何内容。在开发时,ModuleA的代码可以加载和执行,但构建后的代码无法运行。
我该如何解决这个问题?
更新 http://pastebin.com/p1xUcY0A --> start.js http://pastebin.com/dXa6PtpX --> ModuleA js-animation.js http://pastebin.com/xcCvhLrT --> ModuleB css-animation.js无依赖项。 http://pastebin.com/j51V5kMt --> 运行优化器时使用的r.js配置文件。

http://pastebin.com/UVkWjwe9 --> 运行 r.js 后的 js-animation.js 文件。这个文件存在问题。我没有从这个文件中获取到 js-animation 模块。require 不会返回我的 js-animation 对象。

编辑:

在模块定义和开始 js 中去掉末尾的 .js 后,优化后的 start.js 是 http://pastebin.com/LfaLkJaT,js-animations 模块是 http://pastebin.com/qwnpkCC6。在 Chrome 中,我的控制台显示了这个错误http://pastebin.com/Hq7HGcmm


我可以粘贴虚拟项目的整个代码,但它大约有300行。 - Vlad Nicula
请将您的代码放在pastebin.com上,然后编辑您的问题并附上pastebin的URL :) - Andrei Sfat
不确定Pastebin是否是一个好的选项。该项目有4个JS文件在开发中,应该在生产中有3个。 :| - Vlad Nicula
澄清一下:你的“start”模块除了生成依赖项数组的require之外还有其他逻辑吗?如果是这样,这个数组会包含依赖项名称“ModuleA”或“ModuleB”吗?也许你可以添加start.js的代码... - rharper
感谢您的评论@rharper。我的start.js模块内有两个requires。根据条件,只有其中一个内部require调用会被执行。这样解释清楚了我的情况吗? - Vlad Nicula
显示剩余2条评论
2个回答

1

目前的require.js实现似乎存在问题。解决方法是创建一个全局中介者或中介者模块,并让所有动态加载的模块调用中介者并通过事件宣布自己。这对我很有效。


我有一个类似的问题,但是与包有关。当我尝试加载一个压缩的包时,我的main.js不会执行。 - chchrist

1

我认为你的设置问题在于你在模块依赖名称中以.js结尾。根据文档:

RequireJS默认也假定所有依赖项都是脚本,因此不希望在模块ID上看到尾随的“.js”后缀。当将模块ID转换为路径时,RequireJS会自动添加它。

如果RequireJS看到模块名称以.js结尾,则假定模块名称是相对于文档的路径。通过在模块依赖名称中以.js结尾,它在开发模式下可以正常工作,因为RequireJS将加载指定为依赖项的文件。在你的情况下,它将加载文件js/js-animation.js,看到匿名define并正确加载模块。

在生产环境中,您的start.js模块仍需要"js/js-animation.js"。RequireJS将在路径js/js-animation.js加载您优化的模块,但现在优化器已将您的匿名模块转换为命名模块(在本例中为"js/js-animation")。结果是文件将被加载,但文件中没有与"js/js-animation.js"匹配的名称为define的模块,因此从某种意义上说,您的动画模块丢失了。 解决方案/TL;DR:从所有模块依赖项名称(以及r.js配置中的模块定义)中删除尾随的.js,然后您就可以正常运行了。因此,您的start.js应该变成以下内容(第4行更改):
require([], function () {
  var $html = $("html"),
    animationModule = localStorage['cssanimations'] == 'true' ? 
    'js/css-animation' : 'js/js-animation',
    $doc = $html.find("body");

  console.debug("loading ", animationModule);
  require([animationModule], function( animationModule ) {
    animationModule.run({
      target : $("div.flex")
    });
  } );
} );

请注意,您可能希望在RequireJS配置中使用baseUrlpaths来清理模块名称(例如,您可以删除js/前缀)。

你好,感谢详细的回复。我很感激。我已经从模块名称中删除了“.js”,现在构建脚本声明的模块名称末尾没有“.js”。问题仍然存在。第二个生产模块“js-animation”仍然有两个定义,第一个是插件,第二个是它自己,但是启动JS仍然无法从中获取内容。 :| - Vlad Nicula
@VladNicula 看起来你在编辑start.js的时候出了错。你从模块名的末尾删除了.js(很好),但是也将前面的js/删除了(需要保留)。你的require.js js-animation模块实际上被称为 'js/js-animation',正如优化输出中所看到的那样。如果有这个错误,我很惊讶你的代码是否能够在开发模式下工作... 在start.js中重新添加js/到你的模块名称中并尝试一下。 - rharper
start.js模块位于js文件夹中。如果我在我的模块名称之前添加/js,我会得到一个"未捕获的错误:脚本错误",并且URL中有/js/js/module-name,这是错误的... - Vlad Nicula

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接