Node.js 提供了使用 C++ addon 方案作为扩展的能力。我们可以编写 C++ 的代码来扩展 Node.js 或封装自己产品相关的能力接口为 Node.js 接口提供用户或者开发者使用。将编写好的源代码上传至 npm publish 平台,开发者通过 npm install 就可以使用你的扩展包了。但使用的前提是引入方必须要具备编译 C++ 代码的环境,比如在 Windows 下需要安装 MSVC 的编译工具链。而正常的前端开发者并不会将这些组件安装到系统里面,他们更关注的是前端业务逻辑。

由于 npm 平台不允许上传太大的文件或二进制文件,所以在用户执行 npm install 时自动下载已经预编译好的二进制文件包就映入我们的眼帘了。node-pre-gyp 就是来做这个用的。它包含了打包上传、根据版本自动下载等一系列流程。这些步骤只需要你对工程做一些简单的配置就可以实现。node-sqlite3 就是通过该插件来实现下载预编译的二进制包的:https://github.com/mapbox/node-sqlite3 针对一些不依赖三方 SDK 的 C++ 插件来说,只需导出一份 .node 文件即可让开发者导入使用。将二进制包打包为 .tar.gz,将打包后的压缩文件上传到外网可以访问的服务器中,接下来配置一下 node-pre-gyp 就可以了。首先安装 node-pre-gyp

1
npm install --save @mapbox/node-pre-gyp

创建一个新的 target action_after_build 用来在你主工程编译完成后自动拷贝 .node 文件到准备上传的目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
'target_name': 'action_after_build',
'type': 'none',
'dependencies': ['<(module_name)'],
'copies': [
{
'conditions': [
[
'OS=="win"',
{
'files': [
'<(PRODUCT_DIR)/<(module_name).node'
],
'destination': '<(module_path)'
}
],
[
'OS=="mac"',
{
'files': [
'<(PRODUCT_DIR)/<(module_name).node'
],
'destination': '<(module_path)'
}
]
]
}
]
}

配置 package.json,让 node-pre-gyp 知道编译后的包保存到什么位置,在 package.json 中新增如下字段:

1
2
3
4
5
6
7
"binary": {
"module_name": "node_nim",
"module_path": "./lib/binding/{node_abi}-{platform}-{arch}/",
"remote_path": "./package/",
"package_name": "{module_name}-v{version}-{node_abi}-{platform}-{arch}.tar.gz",
"host": "https://your-download-host"
}

这里的 module_path 就是告诉 node-pre-gyp 编译后要保存到当前目录下的 ./lib/binding/{node_abi}-{platform}-{arch}/ 目录。目录名是根据当前环境来自动创建的。除了保存,上面的配置还告诉 node-pre-gyp 第三方程序引入这个包时,node-pre-gyp 会尝试从 ${host}/${remote_path}/${package_name} 去下载这个包。如果下载到了这个包,那么自动解压到 module_path 路径下,就不会再尝试编译了。 配置基本就绪,还差最重要的一步,替换默认的 npm install 流程:

1
2
3
"scripts": {
"install": "node-pre-gyp install --fallback-to-build"
}

在你的 package.json 中,scripts 字段下添加 install 配置,让默认的 install 行为变为 node-pre-gyp install –fallback-to-build。这样在三方应用引入我们的包时会调用 node-pre-gyp install 首先到 package.json 中指定的 host 去尝试下载已经编译好的二进制包,如果没有下载到则调用本地的 node-gyp(注意这里不是 node-pre-gyp)根据外部传递的参数来从本地代码编译,这样也就串通了整个流程。 同时 node-pre-gyp 其实支持二进制包自动上传的能力,需要你单独配置 AWS3 的 token 等信息,由于国内访问 S3 资源很困难,这一步我们并没有做进一步验证,有兴趣的同学可以参考官方文档来尝试。