【问题标题】:best practices for cross commonjs/browser development跨 commonjs/浏览器开发的最佳实践
【发布时间】:2011-07-12 14:26:53
【问题描述】:

目前,我通过 Google Closure Compiler 使用 IS_CJSIS_BROWSER 的一些 defines,并且构建了不同的文件(browser.myproject.jscjs.myproject.js 等)。

这是标准的做事方式吗?如果不是,它是什么,有什么优势?

【问题讨论】:

    标签: javascript node.js cross-platform commonjs


    【解决方案1】:

    我在所有项目中都使用了以下序言,用于浏览器和服务器代码加载的库:

    if (define === undefined) {
        var define = function(f) {
                require.paths.unshift('.');
                f(require, exports, module);
            };
    }
    
    define(function(require, exports, module) {
        ...
        // main library here
        ...
        // use require to import dependencies
        var v = require(something);
        ...
        // use exports to return library functions
        exports.<stuff> = { some stuff };
        ...
    });
    

    这适用于通过在我的节点服务器上运行的require(&lt;library&gt;) 调用以及使用RequireJSrequire(&lt;library&gt;) 调用来加载库。在浏览器上,嵌套的 require 调用在库执行之前由 RequireJS 预取,在 Node 上,这些依赖项是同步加载的。由于我没有将我的库用作独立脚本(通过 html 中的脚本标记),并且仅作为通过脚本标记加载的脚本的依赖项,因此这对我来说很有效。


    但是,看看独立库,看起来下面的序言似乎是最灵活的。 (从 Q Promise 库中剪切和粘贴

    (function (definition, undefined) {
    
        // This file will function properly as a <script> tag, or a module
        // using CommonJS and NodeJS or RequireJS module formats.  In
        // Common/Node/RequireJS, the module exports the Q API and when
        // executed as a simple <script>, it creates a Q global instead.
    
        // The use of "undefined" in the arguments is a
        // micro-optmization for compression systems, permitting
        // every occurrence of the "undefined" variable to be
        // replaced with a single-character.
    
        // RequireJS
        if (typeof define === "function") {
            define(function (require, exports, module) {
                definition(require, exports, module);
            });
        // CommonJS
        } else if (typeof exports === "object") {
            definition(require, exports, module);
        // <script>
        } else {
            Q = definition(undefined, {}, {});
        }
    
    })(function (serverSideRequire, exports, module, undefined) {
    
        ...
        main library here
        ... 
    
    
    /*
     * In module systems that support ``module.exports`` assignment or exports
     * return, allow the ``ref`` function to be used as the ``Q`` constructor
     * exported by the "q" module.
     */
    for (var name in exports)
        ref[name] = exports[name];
    module.exports = ref;
    return ref;
    
    });
    

    虽然冗长,但非常灵活,并且操作简单,无论您的执行环境如何。

    【讨论】:

    • 我宁愿不使用 r.js RequireJS 适配器,我更希望人们能够使用我本地创建的库。我使用的基于 RequireJS 提供的用于手动转换现有 CommonJS 模块的功能,可在此处找到:requirejs.org/docs/commonjs.html#manualconversion 不同之处在于,我添加了一个在 CommonJS 中执行的函数,因此它可以在 CommonJS 环境和 RequireJS 中运行
    • 明白了。真的很遗憾,我们不得不使用这样的工具。 :(
    • 嗯,CommonJS 将转向一种对异步不友好的模块语法(允许您通过函数而不是在裸露的 exports 全局上定义模块导出。所以 wcross 环境图书馆在我们的掌握之中。
    【解决方案2】:

    您可以使用uRequire,通过模板系统将用 AMD 或 CommonJS 编写的模块转换为 AMD、CommonJS 或 UMD。

    uRequire 可以选择将您的整个捆绑包构建为combinedFile.js,它可以在使用 rjs 优化器和 almond 的所有环境(nodejs、AMD 或无模块浏览器 )中运行。

    uRequire 让您不必在每个模块中维护任何样板 - 只需编写普通的 AMD 或 CommonJS 模块(如 .js、.coffee、.coco、.ls 等),无需任何噱头。

    此外,您还可以以声明方式将标准功能(例如 exporting a module)添加到全局(例如 window.myModule)以及 noConflict() 方法,或者在构建、自动缩小、操作时使用 runtimeInfo (eg __isNode, __isAMD) selectively 或替换/删除/注入依赖项模块代码等等。

    所有这些configuration options 可以在每个捆绑包或每个模块中打开和关闭,并且您可以拥有相互派生(继承)的不同构建配置文件(开发、测试、生产等)。

    通过grunt-urequire 或独立的 grunt 可以很好地工作,并且它有一个很棒的watch 选项,只重建更改的文件。

    【讨论】:

      【解决方案3】:

      你试过这个:https://github.com/medikoo/modules-webmake#modules-webmake 吗?

      这是我正在采用的方法,而且效果非常好。代码中没有样板,您可以在服务器端和客户端运行相同的模块

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-18
        • 1970-01-01
        • 1970-01-01
        • 2011-08-26
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多