使用节点和窗口使JS库满意

Phr*_*ogz 0 javascript canvas node.js npm

我维护一个JS库,我想把它放到Node模块中,并与Node一起使用.

我的库扩展了Canvas上下文API并且需要getImageData(),因此从包含所有代码的防御线开始:

if (window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype.getImageData){
  CanvasRenderingContext2D.prototype.blendOnto = /* … */;
}
Run Code Online (Sandbox Code Playgroud)

使用Node,我使用Node Canvas.为了使我现有的代码能够工作,我需要编写如下的Node代码:

var Canvas = require('canvas');
GLOBAL.CanvasRenderingContext2D = Canvas.Context2d;
GLOBAL.window = GLOBAL;
require('context_blender');
Run Code Online (Sandbox Code Playgroud)

然而,这似乎明显地打击了Node的模块模式.我怎样才能最好地重写我的库并将其打包为节点模块,以便它(a)继续在Web浏览器中工作,但(b)干净地使用Node Canvas,而不必通过全局变量传递数据?有没有办法将Canvas.Context2d我的模块传递给mutate?

lex*_*ore 5

我建议将您的代码放在模块工厂函数中,如下所示:

var context_blender_factory = function(CanvasRenderingContext2D)
{
    var defaultOffsets = {
        // ...
    };
    // Applies to the parameter passed to the module factory function  
    CanvasRenderingContext2D.prototype.blendOnto = // ...
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这基本上抽象了你从哪里得到你的CanvasRenderingContext2D.

然后,在声明您的功能之后,您可以编写初始化例程,在该例程中检查环境并相应地调用模块工厂.

如果你只想考虑纯NodeJS,这将是这样的:

if (typeof require === 'function') {
    // Assume NodeJS environment
    context_blender_factory(require('canvas').Context2d);
}
else if (window &&
         window.CanvasRenderingContext2D &&
         window.CanvasRenderingContext2D.prototype.getImageData)
{
    // Assume browser environment
    context_blender_factory(window.CanvasRenderingContext2D);
}
Run Code Online (Sandbox Code Playgroud)

此模式还允许支持AMD风格的模块环境,如 RequireJSamdefine.


背景故事

我的JS库有类似的情况(参见下面的背景故事).

我最初为浏览器实现了我的库.

然后人们开始询问它是否可以在NodeJS中运行.这并不难,因为Node拥有模仿/实现功能的所有相关模块,就像在浏览器中一样.所以我为NodeJS 添加了require/ export构造.

然后其他人开始询问RequireJS/AMD风格的模块支持.我问过四处:

如何编写一个适用于Node.js,RequireJS以及没有它们的模块

最后到达以下解决方案,支持浏览器,NodeJS,RequiredJS/AMD/amdefine.