node编写C++扩展文件并引入到项目方案总结

插入模块

  • 通过Addon实现可扩展接口(可以将C++插入到前端项目中)
    • 编写扩展文件
    • 编译扩展
    • 调用扩展
    • 参考
  • 在项目中引入本地模块
    • 1. 使用 npm install ../module1
    • 2. 直接修改 package.json 字段,增加依赖
    • 3. 使用 install-local
    • 4. 使用 npm link
    • 5. 使用 require-rewrite
    • 6. 使用 postinstall 钩子手动创建软链接
  • 参考

通过Addon实现可扩展接口(可以将C++插入到前端项目中)

electron API
node c++插件官方文档

编写扩展文件

我们可以编写一个node扩展,按照官方文档一样编辑一个hello.cc

#include 

// 实际暴露的方法,这里只是简单返回一个字符串
napi_value HelloMethod (napi_env env, napi_callback_info info) {
    napi_value world;
    napi_create_string_utf8(env, "world", 5, &world);
    return world;
}

// 扩展的初始化方法,其中 
// env:环境变量
// exports、module:node模块中对外暴露的对象
void Init (napi_env env, napi_value exports, napi_value module, void* priv) {
    // napi_property_descriptor 为结构体,作用是描述扩展暴露的 属性/方法 的描述
    napi_property_descriptor desc = { "hello", 0, HelloMethod, 0, 0, 0, napi_default, 0 };
    napi_define_properties(env, exports, 1, &desc);  // 定义暴露的方法
}

NAPI_MODULE(hello, Init);  // 注册扩展,扩展名叫做hello,Init为扩展的初始化方法

编译扩展

使用binding.gyp完成项目描述

{
  "targets": [
    {
      "target_name": "hello",
      "sources": [ "./src/hello.cc" ]
    }
  ]
}

调用扩展

  1. 未方便调用扩展,先安装bindings。npm install --save bindings

  2. 然后,创建app.js,调用刚编译的扩展。

var addon = require('bindings')('hello');
console.log( addon.hello() );  // world
  1. 运行代码,由于N-API当前尚处于Experimental阶段,记得加上–napi-modules标记。
    node --napi-modules app.js

参考

通过Addon(n-api)实现可扩展接口

n-api入门


在项目中引入本地模块

对于某些比较大的项目,我们可能会希望将其划分成多个模块, 或是要将上面编写的插件模块引入主项目:

- module1
	- package.json
	- libs
		- file1.js
- module2
	- package.json
	- index.js

假如我们要在 module2/index.js 中直接引用 file1.js,可能就会写成这样 require('../module1/libs/file1')。这样写并不好,因为:

有时候引用方的文件处在很深的路径下,那么引用地址就得写成 …/…/…/module1/libs/file1,体验很不好。
既然我们将项目划分成了多个模块,肯定是想要降低模块之间的偶合度。这样直接引用文件的做法相当于直接深入到了模块的内部,没有将模块之间隔离出来,低耦合更无从谈起了。
解决 2 号问题最好的做法是提供一个单独的文件作为模块的接口。

module1/index.js 中把我们希望在本模块中暴露出来的函数或类 export 出来,这样的话就相当于给模块提供了一个接口。其他模块只能通过 index.js 提供的内容来访问。
假如以后需要重构 module1,将 file1.js 拆成两个文件,只需要改动一下 module1/index.js即可,不需要修改其他的模块。

现在我们的引用可以写成 require(‘…/module1’) 了,本文章的剩余内容就来讨论一下怎样解决 1 号问题——去掉前面的…。

1. 使用 npm install …/module1

我们可以把 module1 作为依赖安装给 module2。
这样的话,module2 在运行的时候就可以把 module1 当成一个普通的依赖,使用 require(‘module1’) 来引入了。
这个方法的问题在于要安装的 module1 必须在 package.json 文件中有 version 字段,否则无法安装成功。

对于一个应用程序(而不是类库)而言,每次修改都需要更新版本会比较麻烦,而且 npm5 的安装会直接创建一个软链接,会引发更多的问题。

2. 直接修改 package.json 字段,增加依赖

我们可以直接在 module2/package.json 的 dependencies 中增加一个 “module1”: “file:…/module1” 。
这样 npm5 在安装依赖的时候会自动创建相应的软链接,自动给 module1 安装依赖,而且不需要版本号。
但这个特性跟 npm5 的 package-lock 结合起来就出问题了。

对于进行过这些修改的 module2,在安装依赖的时候会把 module1 的 package-lock 也合并进 module2/package-lock.json,再一次使用 npm install 的时候就会提示 enoent ENOENT: no such file or directory

3. 使用 install-local

https://www.npmjs.com/package/install-local

这玩意跟解决方法 1 类似,只不过在 npm5 里面也能直接拷贝文件夹而不是创建软链接。这么做的话还是需要 version 字段,而且对于 module1 的改动不会直接反应到 module2 上,还需要像更新其他模块那样手动更新。

4. 使用 npm link

这个比较神奇。我们可以在 module1 目录下运行 npm link,然后在module2目录下运行npm link module1。这样的话,npm 就会自动在 module2 的 node_modules 目录下创建一个软链接,我们拥有了类似于方法 2 的效果,并且不会修改 package-lock。

但是它也不会修改 package.json。也就是说我们拿到项目源代码之后不能直接用 npm i 来安装所有依赖,还必须得加一步 npm link 才行,还是太麻烦了。

5. 使用 require-rewrite

https://www.npmjs.com/package/require-rewrite
这个方法解决了上述的所有问题。我们只需要配置一下 module2 的 package.json,加入 module1 的路径,这样就能使用require(‘module1’)来引入模块了。

不过,这个方法又引入了两个新的问题:

  1. 引入的时候得多写一步。
    我们必须要在 require(‘module1’) 前面写上 require(‘require-rewrite’)(__dirname) 才能在本文件中引入此模块。
  2. 静态代码分析失效了。
    如果你用 webstorm 的话,它显然是没法通过重写过的路径来找到 module1 的实际路径的,那基于此的代码补全也就失效了。

6. 使用 postinstall 钩子手动创建软链接

我们可以在 module2 的 package.json 的 script 字段中新建一个:

"postinstall": "node -e "
var s='../module1',
d='./node_modules/module1',
fs=require('fs'), 
r=require('path').resolve;
fs.exists(d,function(e){e||fs.symlinkSync(r(s),r(d),'junction')});""

它的命令名称为 postinstall,使得这个命令会在 npm install 安装结束之后自动执行。
它执行一段 node 脚本来自动创建链接,起到了跟 npm link 相似的效果。
只要把其中的 module1 更换成你自己的模块路径即可。
注意其中的 junction,这个参数只在 windows 下才有效果,*Unix 下这个参数是什么都没有关系。junction 代表创建目录链接。

其实这个解决办法还是有两个小问题:

  1. 不会自动安装依赖的依赖
    在 module2 下执行 npm install 并不会自动给 module1 安装依赖。

  2. 在 root 权限下执行会有问题
    默认情况下,在 root 权限下执行 npm install 会阻止 postinstall 脚本运行。我们可以使用普通权限来安装或者使用 npm install --unsafe-perm 来安装。


参考

https://juejin.cn/post/6844903582337237006
https://www.dazhuanlan.com/michael_chengzi/topics/1353246
https://blog.csdn.net/allen8612433/article/details/106937163
https://blog.csdn.net/fanweilin0123/article/details/106458861

你可能感兴趣的:(前端,c++,javascript,前端)