为什么串联的RequireJS AMD模块需要加载器?
我们喜欢RequireJS和AMD在开发过程中,我们可以编辑一个模块,在我们的浏览器中重新加载,并立即看到结果。 但是,当我们将模块连接成一个单独的文件进行生产部署时,显然必须有一个AMD加载器,无论该加载器是RequireJS本身,还是小型合作伙伴“杏仁”,如下所述:
http://requirejs.org/docs/faq-optimization.html#wrap
我的困惑是:为什么装载机是必要的? 除非你有非常不寻常的情况,使得你require()
在你的模块中进行require()
调用,否则看起来一系列的AMD模块可以在没有加载器的情况下连接在一起。 最简单的例子可能是像下面这样的一对模块。
ModA.js:
define([], function() { return {a: 1}; });
ModB.js:
define(['ModA'], function(A) { return {b : 2}; });
考虑到这两个模块,似乎一个连接器可以简单地生成以下文本,并且不会给生产服务器或浏览器带来RequireJS或Almond所需的额外带宽或计算负担。
我想象一个产生(我使用V形引号«,»来显示上面两个模块的代码片段已被插入的连接符):
(function() { var ModA = «function() { return {a: 1}; }»(); var ModB = «function(A) { return {b : 2}; }»(ModA); return ModB; })();
就我所知,这将正确地重现AMD的语义,并至less有一些额外的粘连JavaScript。 有没有这样的连接器? 如果不是的话,我是否会觉得自己应该写一个傻瓜 – 是否真的有很less的代码库,它们是用define()
编写的简单和干净的模块组成的,而且不需要进一步的require()
调用,代码提取?
AMD优化器的优化范围可以比要下载的文件数量多,也可以优化内存中加载的模块数量。
例如,如果您有10个模块,并且可以将它们优化为1个文件,那么您已经保存了9个下载。
如果Page1使用全部10个模块,那么这很好。 但是,如果Page2只使用1呢? AMD加载器可以延迟“工厂function”的执行,直到需要模块为止。 因此,Page2只会触发一个“工厂函数”来执行。
如果每个模块在被require
时消耗100kb的内存,那么一个运行时优化的AMD框架也将在页面2上节省900kb的内存。
这个例子可以是一个“关于盒子”风格的对话框。 那里的执行被推迟到最后一秒,因为在99%的情况下不会被访问。 例如(在松散的jQuery语法):
aboutBoxBtn.click(function () { require(['aboutBox'], function (aboutBox) { aboutBox.show(); } });
您可以节省创build与“关于Box”关联的JS对象和DOM的开销,直到您确定这是必要的。
有关更多信息,请参阅延迟执行定义,直到 requirejs 执行此操作为止 。
唯一真正的好处是如果你跨模块使用模块,所以独立地caching模块是有好处的。
我有同样的需要,所以我创build了一个简单的AMD“编译器”,就是这样做的。 你可以在https://github.com/amitayh/amd-compiler上find它;
请注意,它有许多function缺失,但它做的工作(至less对我而言)。 随意贡献给代码库。
如果您将require.js的代码编译成单个大文件进行生产,则可以使用almond.js来完全replacerequire。
杏仁只处理模块引用pipe理而不是不再需要的加载本身。
要小心杏仁施加的限制
没有理由为什么不能有像你所提议的那样的构build工具。
上一次*我查看了优化器的输出,它将模块转换为明确命名的模块,然后将它们连接在一起。 它依靠自己来确保工厂函数按照正确的顺序被调用,并且正确的模块对象被传递。 要想像你想要的那样构build一个工具,你必须明确地对这些模块进行线性化 – 这不是不可能的,而是要做更多的工作。 这可能是为什么它没有完成。
我相信**,优化器有一个function,自动包括要求自己(或杏仁)到build立的文件,所以你只需要有一个下载。 这将比你想要的构build工具的输出大,但其他方面相同。
如果有一个构build工具产生了你所要求的输出,那么在同步require
情况下,必须更加小心,使用exports
来取代return,以及其他的CommonJS兼容性特性。
*那是几年前。 2010年,我想。
**但现在似乎无法find它。