使用包装器使模块能够与AMD/CommonJs或脚本标签一起工作?

17

我刚尝试着对我们的一个模块进行包装,这个模块可以通过


1
一个想法:我不会测试 typeof window.requirejs == 'function'。你可能不关心 AMD 实现。相反,测试 window.define.amd。但这只是微调。 - Scott Sauyet
谢谢@ScottSauyet - 我想我在knockout.js源代码中看到过这个,不知道那是否更好。 - George Mauer
请注意,Require有一个选项可以使用仅少量配置相当好地加载非AMD模块。因此,尽管您的目标可能很有趣,但您可能不需要它。 - Scott Sauyet
@ScottSauyet - 是的,我知道这个 shim - 我的部分工作还是让我们的开发人员明确声明他们的依赖关系。 - George Mauer
3个回答

8
当你试图重新创建已经存在的东西时,我也做了完全相同的事情,在我的StackOverflow问题中提出了稍微不同的解决方案。
长话短说,你需要知道的名称是“通用模块定义”,在https://github.com/umdjs/umd上有各种不同的实现。

太棒了,谢谢 - 我知道肯定有类似的东西在周围。 - George Mauer

0

你是想为内部模块还是外部模块做这个?

如果你不需要引入其他模块,那么是否可能在假定 AMD 的情况下构建你的模块,然后在代码的其他地方将 define() 函数卸载掉?当然,你必须使用具名模块,但无论如何你都必须这样做...

如果你的所有模块都从 define() 函数返回它们的输出,那么就会比较简单,你的替代 define 函数可能看起来像这样:

//Whatever additional guards you want could be added, of course...
if (typeof(window.define) === undefined){
  window.define = function(name, deps, callback){
    window.myNamespace[name] = callback();
  };
}

这样至少你不必在每个模块中都加入样板文件...

如果您有一个大型的库,其中包含许多相互依赖的子模块,则可能需要全面使用Require或放弃使用,然后使用整个库周围的包装代码来处理AMD支持,就像Jquery和Knockout JS所做的那样。


这样不行 - 如果您正在执行define('blah',['jQuery', 'underscore'],function($,_){ ....}),则您的方法始终会导致 $ === _ === undefined。 这是我遇到的主要问题,也是我不得不以我所做的方式声明依赖关系的原因。 - George Mauer
是的,这就是为什么我说只有在不使用require来引入其他模块时才能这样做。但现在我有点困惑了。如果你正在通过require引入依赖项,那么为什么要费尽心思使require变成可选的呢? - Chris Jaynes
我们有一大批内部使用的脚本,这些脚本已经积累了多年。它们对其他库和彼此都有各种隐含的依赖关系假设。你知道怎么回事。这些库非常有用。我们仍然有很多项目不使用amd,也不会使用,但我想用amd来正确地完成某些其他项目。所以基本上它必须两种方式都能工作。现在看起来这似乎是许多公司应该遇到的情况(这篇文章的投票结果似乎证实了这一点)。 - George Mauer
1
这很有道理,也是一个棘手的问题。如果您假设Jquery已经存在,而不是尝试要求它会发生什么?我曾在一些项目上工作过,我们从依赖链中删除了Jquery和其他几个第三方库,部分原因是为了简化我们的代码,部分原因是因为我们想要将它们放在单独的捆绑包中。这实际上是一种相当合理的工作方式,它可能会简化您的问题。 - Chris Jaynes
是的,但是下一级依赖关系怎么办?它们依赖于我的核心文件,或者依赖于那个依赖关系呢? - George Mauer
对于像Jquery、Jquery UI、Underscore和其他低级第三方库之类的东西,这对我来说不是问题。可以安全地假设它们已经存在,或者如果需要的话可以添加它们。对于我的应用程序,管理自己模块的依赖关系比引入我使用的每个第三方库更重要。我同意你的观点,如果您的依赖链有几个层次,或者如果您正在跨多个团队共享模块,则这是一个更棘手的问题,但即使您一直使用Require,这些问题可能始终会更难解决。 - Chris Jaynes

0
在对此进行破解后,我设法想出了以下的方法,它似乎更好,并且甚至可以作为常规脚本标记中的一个 shim 包含进去:
有几点需要注意和缺点:
  • 您必须使用 exports 对象替换 window 对象上的任何显式设置
  • 它假定任何依赖项都存在于 window 对象上的同名属性中(尽管它还确保将该属性放置在那里)。在我的情况下,这通常足够安全,但您可以轻松地破解类似于 requirejs 路径配置的东西。
  • 实际上,我并不确定整个导出概念特别必要,或者至少不是所有情况下都必要。
(function () {
    var define, exports = {};
    if (window.define && window.define.amd) {
        define = window.define;
    } else {
        exports = window;
        define = function (name, dependencies, fn) {
            var deps = [];
            for (var i = 0; i < dependencies.length; i++)
                deps.push(window[dependencies[i]]);
            var module = fn.apply(undefined, deps);
            if (!window[name]) window[name] = module;
        };
    }

    define('mylib.interaction', ['jQuery', 'mylib.core', 'jQuery.UI'], function($, mylib) {
        return /*....blah...*/;
    })
})()

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