如何编写适用于Node.js,RequireJS以及不使用它们的模块

Lexicore

我正在使用JavaScript库进行JSON / XML处理我的库可以在浏览器以及Node.js(带有xmldomxmlhttprequest模块)中使用。

最近有一位用户要求RequireJS支持。我看过RequireJS / AMD的东西,并认为这是一个很好的方法,所以我想提供这一点。

但是,我想保留可移植性:我的库必须在浏览器(带有和不带有RequireJS)以及Node.js中都可以工作。在浏览器环境中,我不依赖xmldomxmlhttprequest因为这些东西是由浏览器本身提供的。

我的问题是:如何实现我的库,以便它在没有RequireJS的情况下在浏览器以及Node.js中都能正常工作?

一点历史和我当前的解决方案

我最初是为浏览器编写库的。因此,它只是创建了一个全局对象并将所有内容放入其中:

var Jsonix = { ... };

后来,用户要求Node.js支持。所以我补充说:

if(typeof require === 'function'){
    module.exports.Jsonix = Jsonix;
}

我还必须导入上面提到的几个模块。我有条件地执行了此操作,具体取决于该require功能是否可用:

if (typeof require === 'function')
{
    var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
    return new XMLHttpRequest();
}

现在有了RequireJS的故事。如果存在RequireJS,则require函数也将存在。但是模块加载的工作方式不同,我必须使用define函数等。require由于requireRequireJS中有一个异步API,所以我也不能只做一些事情而且,如果我的库是通过RequireJS加载的,require('something')即使我有条件地这样做,它似乎也会处理源代码并进行检测

if (typeof require === 'function' && typeof require.specified !== 'function) ...

RequireJS仍然检测到require('xmlhttprequest')尝试加载相应的JS文件。

目前,我要使用以下解决方案。

// Module factory function, AMD style
var _jsonix = function(_jsonix_xmldom, _jsonix_xmlhttprequest, _jsonix_fs)
{
    // Complete Jsonix script is included below 
    var Jsonix = { ... };
    // Complete Jsonix script is included above
    return { Jsonix: Jsonix };
};

// If require function exists ...
if (typeof require === 'function') {
    // ... but define function does not exists, assume we're in the Node.js environment
    // In this case, load the define function via amdefine
    if (typeof define !== 'function') {
        var define = require('amdefine')(module);
        define(["xmldom", "xmlhttprequest", "fs"], _jsonix);
    }
    else {
        // Otherwise assume we're in the RequireJS environment
        define([], _jsonix);
    }
}
// Since require function does not exists,
// assume we're neither in Node.js nor in RequireJS environment
// This is probably a browser environment
else
{
    // Call the module factory directly
    var Jsonix = _jsonix();
}

这就是我现在检查依赖项的方式:

if (typeof _jsonix_xmlhttprequest !== 'undefined')
{
    var XMLHttpRequest = _jsonix_xmlhttprequest.XMLHttpRequest;
    return new XMLHttpRequest();
}

如果我有require但没有,define那么我认为这是一个Node.js环境。amdefine用来定义模块并传递所需的依赖关系。

如果有requiredefine我假设这是RequireJS环境,因此我只使用该define函数。目前,我还假设这是一个浏览器环境,因此类似xmldom和的依赖项xmlhttprequest不可用,不需要它们。(这可能也不正确。)

如果我没有此require功能,那么我认为这是一个没有RequireJS / AMD支持的浏览器环境,因此我_jsonix直接调用模块工厂并将结果导出为全局对象。

因此,到目前为止,这是我的方法。对于我来说似乎有点尴尬,作为RequireJS / AMD的新手,我正在寻求建议。这是正确的方法吗?有没有更好的方法来解决该问题?谢谢您的帮助。

蒂莫西·斯特拉普(Timothy Strimple)

看一看underscore.js如何处理它。

// Export the Underscore object for **Node.js**, with
// backwards-compatibility for the old `require()` API. If we're in
// the browser, add `_` as a global object.
if (typeof exports !== 'undefined') {
  if (typeof module !== 'undefined' && module.exports) {
    exports = module.exports = _;
  }
  exports._ = _;
} else {
  root._ = _;
}

...

// AMD registration happens at the end for compatibility with AMD loaders
// that may not enforce next-turn semantics on modules. Even though general
// practice for AMD registration is to be anonymous, underscore registers
// as a named module because, like jQuery, it is a base library that is
// popular enough to be bundled in a third party lib, but not be part of
// an AMD load request. Those cases could generate an error when an
// anonymous define() is called outside of a loader request.
if (typeof define === 'function' && define.amd) {
  define('underscore', [], function() {
    return _;
  });
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章