【问题标题】:Wrapper to allow a module to work with AMD/CommonJs or script tags?允许模块使用 AMD/CommonJs 或脚本标签的包装器?
【发布时间】:2013-02-06 18:58:35
【问题描述】:

我刚刚尝试包装我们的一个模块,该模块打算通过 <script> 标记包含在一些样板文件中,以允许使用 requirejs 加载可选的 AMD。

这很痛苦,我能想到的最好办法是:

(function(){
var exports, jQuery;
if (typeof window.define === 'function' && typeof window.requirejs === 'function') {
    exports     = {};
    define(['jquery'], function (jq) {
        jQuery = jq;
        return thisModule();
    });
} else {
    exports     = window;
    jQuery      = window.jQuery;
    thisModule();
}


function thisModule() {
}

})();

注意这是

  • 大量样板文件
  • 要求您在变量中声明依赖项(谢天谢地,只有 jQuery)和 amd
  • 如果我想获得 CommonJs 支持,还需要更多代码。

我主要关心的是第二点,因为当我超出包装我们的核心文件时,它会变得很糟糕。我确定那里有一些整洁的(呃)包装器实现,但我找不到。

有人有什么建议吗?

【问题讨论】:

  • 一个想法:我不会测试typeof window.requirejs == 'function'。您可能不关心 AMD 的实现。而是测试window.define.amd。但这只是一个调整。
  • 感谢@ScottSauyet - 我想我在 knockout.js 源代码的某个地方看到了这一点,想知道这是否是更好的方法。
  • 还请注意,Require 可以选择仅使用small amount of configuration 就可以很好地加载非 AMD 模块。因此,尽管您的目标可能是一个有趣的目标,但如果没有它,您也可以侥幸成功。
  • @ScottSauyet - 是的,我知道 shim - 我的部分也是让我们的开发人员明确声明其依赖关系的练习。

标签: javascript amd boilerplate commonjs dynamic-script-loading


【解决方案1】:

您试图重新创建已经存在的东西,我做了完全相同的事情,在my StackOverflow question 中提出了一个稍微不同的解决方案。

长话短说,您需要知道的名称是“通用模块定义”,并且有一个位于 https://github.com/umdjs/umd 的 GitHub,其中包含各种不同的实现。

【讨论】:

  • 太棒了,谢谢 - 我知道周围一定有类似的东西。
【解决方案2】:

您是要为内部模块还是外部模块执行此操作?

如果您不需要额外的模块,是否可以假设 AMD 构建您的模块,然后在代码中的其他地方填充 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。这是我遇到的主要问题,也是为什么我必须以我的方式声明依赖项的原因。
  • 是的,这就是为什么我说只有在不使用 require 来拉入其他模块时才能这样做。但现在我有点困惑。如果您通过 require 引入依赖项,那么您为什么要如此努力地使 require 成为可选?
  • 我们有大量内部使用的脚本,这些脚本是多年来积累的。它们对其他库和彼此有各种隐式依赖假设。你知道它是怎么回事。这些库非常有用。我们仍然有很多项目不使用 amd 并且不会使用,某些其他项目我想用 amd 正确完成。所以基本上它必须双向工作。这似乎是很多商店现在应该发现的那种情况(这篇帖子的投票似乎证实了这一点)。
  • 这很有意义,但这是一个棘手的问题。如果您只是假设 Jquery 就在身边,而不是试图要求它,会发生什么?我参与了一些项目,我们将 Jquery 和其他一些 3rd 方库从我们的依赖链中拉出来,部分是为了简化我们的代码,部分是因为我们无论如何都希望将它们放在一个单独的包中。这实际上是一种非常合理的工作方式,并且可能会稍微简化您的问题。
  • 是的,但是依赖于我的核心文件的下一级依赖关系,或者依赖它的依赖关系呢?
【解决方案3】:

在破解了这个之后,我设法想出了以下内容,这似乎要好得多,甚至可以作为 shim 包含在常规脚本标签中:

一些注意事项和缺点。

  • 您必须将窗口对象上的任何显式设置替换为导出对象
  • 它假定任何依赖项都作为窗口对象上类似命名的属性存在(尽管它也确保将该属性放置在那里)。在我的情况下,这通常足够安全,但您可以轻松破解诸如 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...*/;
    })
})()

【讨论】:

    猜你喜欢
    • 2020-09-13
    • 1970-01-01
    • 2015-04-22
    • 2014-09-09
    • 1970-01-01
    • 1970-01-01
    • 2015-09-07
    • 2015-08-08
    • 2012-08-14
    相关资源
    最近更新 更多