我维护a JS library我希望进入Node模块,并与Node一起使用。
我的库扩展了Canvas上下文API并需要getImageData()
,所以从包含所有代码的防御线开始:
if (window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype.getImageData){
CanvasRenderingContext2D.prototype.blendOnto = /* … */;
}
使用Node,我正在使用Node Canvas。为了使我现有的代码能够工作,我需要编写这样的Node代码:
var Canvas = require('canvas');
GLOBAL.CanvasRenderingContext2D = Canvas.Context2d;
GLOBAL.window = GLOBAL;
require('context_blender');
然而,这似乎明显地与Node的模块模式作斗争。我怎样才能最好地重写我的库并将其打包为节点模块,以便它(a)继续在Web浏览器中工作,但(b)干净地使用Node Canvas,而不必通过全局变量传递数据?有没有办法将Canvas.Context2d
传递给我的模块进行变异?
答案 0 :(得分:5)
我建议将代码放在模块工厂函数中:
var context_blender_factory = function(CanvasRenderingContext2D)
{
var defaultOffsets = {
// ...
};
// Applies to the parameter passed to the module factory function
CanvasRenderingContext2D.prototype.blendOnto = // ...
// ...
}
这基本上抽象了,你得到了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);
}
此模式还允许支持AMD样式的模块环境 RequireJS或amdefine。
<强>背景故事强>
我与my JS library有类似的情况(参见下面的背景故事集)。
我最初为浏览器实现了我的库。
然后人们开始询问它是否可以在NodeJS中运行。这并不难,因为Node拥有模仿/实现功能的所有相关模块,就像在浏览器中一样。所以我为NodeJS添加了require
/ export
构造。
然后其他一些人开始询问RequireJS / AMD - 样式模块支持。我问过周围:
How to write a module that works with Node.js, RequireJS as well as without them
最后到达following solution以支持浏览器,NodeJS,RequiredJS / AMD / amdefine。
答案 1 :(得分:1)
为节点和浏览器提供单独的构建是一种常见做法。为什么在浏览器中需要与节点相关的代码,反之亦然?
所以我建议您在
之前添加代码var RenderingContext2d = require('Canvas').Context2d
然后使用RenderingContext2d
获取您需要的所有内容,当您为浏览器创建构建时,将require('Canvas').Context2d
替换为window.CanvasRenderingContext2D
(可以使用sed和许多其他工具轻松实现自动化)。< / p>
结果你得到
答案 2 :(得分:0)
我会像lexicore那样做,但有一些不同之处。整个事情应该是一个匿名函数(就像现在的库一样),我会以不同的方式执行测试。根据JS库中已经存在的代码,我做了:
(function () {
var defaultOffsets = {
// ....
};
function addBlendMethod(object) {
// This should not need to change from that it is now.
}
function blendOnto(...
// ... etc ...
// At the end of the anonymous function, test the environment
// and act accordingly.
if (typeof require === 'function' &&
!(typeof define === 'function' && define.amd)) {
// Node...
addBlendMethod(require('canvas').Context2d.prototype);
}
else {
addBlendMethod(window.CanvasRenderingContext2D &&
window.CanvasRenderingContext2D.prototype);
}
})();
检查!(typeof define === 'function' && define.amd)
是必要的,以避免在节点检查中出现误报。如果有人试图在浏览器中加载您的代码,和 RequireJS(或其他兼容AMD的加载程序)已经存在,并且检查仅针对require
,您的代码将尝试{ {1}}并且会失败。这是因为RequireJS也定义了require('canvas')
。 require
检查会阻止此误报。 AMD兼容的加载器应该定义define
函数并在其上设置define
属性。没有检查可能导致的问题不仅仅是假设。偶尔会有人发布一个关于库某某是如何无法使用RequireJS加载的RequireJS问题而我必须回答库中的环境检测代码是错误的,因为它认为它在Node中运行。
与目前库中的代码相反,我使用amd
而不是window
。我宁愿不依赖于将this
设置为this
的非严格代码的行为,否则将其指定为window
。它可能会导致某些条件下的破损,并且我从未遇到过依赖此行为必需的情况。