开发者

best practices for cross commonjs/browser development

开发者 https://www.devze.com 2023-03-19 11:57 出处:网络
Currently, I use a few defines via the Google Closure Compiler along the lines of IS_CJS and IS_BROWSER, and just have different files that get built (browser.myproject.js, cjs.myproject.js, etc).

Currently, I use a few defines via the Google Closure Compiler along the lines of IS_CJS and IS_BROWSER, and just have different files that get built (browser.myproject.js, cjs.myproject.js, etc).

Is this the standard way of开发者_Python百科 doing things? If not, what is it and what are the advantages?


I've been using the following preamble in all my projects, for libraries that are loaded by both browser and server code:

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 };
    ...
});

This works to load the library with a require(<library>) call running on my node server, as well as with a require(<library>) call with RequireJS. On the browser, nested require calls are pre-fetched by RequireJS prior to library execution, on Node these dependencies are loaded synchronously. Since I'm not using my libraries as stand-alone scripts (via a script tag in the html), and only as dependencies for scripts loaded via the script tag, this works well for me.


However, looking at stand-alone libraries, it looks like the following preamble seems to be the most flexible. (cut and paste from the Q promise library

(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;

});

While wordy, it's impressively flexible, and simply works, no matter what your execution environment is.


You can use uRequire that converts modules written in either AMD or CommonJS to either AMD, CommonJS or UMD through a template system.

Optionally uRequire builds your whole bundle as a combinedFile.js that runs in ALL environments (nodejs, AMD or module-less browser < script/>) thats using rjs optimizer and almond under the hood.

uRequire saves you from having to maintain any boilerplate in each module - just write plain AMD or CommonJS modules (as .js, .coffee, .coco, .ls etc) without gimmicks.

Plus you can declaratively add standard functionality such as exporting a module to global such as window.myModule along with a noConflict() method, or have runtimeInfo (eg __isNode, __isAMD) selectively or replace/remove/inject a dependency while building, automatically minify, manipulate module code and much more.

All of these configuration options can be turned on and off per bundle OR per module, and you can have different build profiles (development, test, production etc) that derive(inherit) from each other.

It works great with grunt through grunt-urequire or standalone and it has a great watch option that rebuilds ONLY changed files.


Have you tried this: https://github.com/medikoo/modules-webmake#modules-webmake ?

It's the approach I'm taking, and it works really well. No boilerplate in a code and you can run same modules on both server and client side

0

精彩评论

暂无评论...
验证码 换一张
取 消