博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
electron 使用 Node.js 原生模块
阅读量:6347 次
发布时间:2019-06-22

本文共 3657 字,大约阅读时间需要 12 分钟。

  • March 28, 2018

Node.js 原生模块是用 C++ 编写的 Node.js 扩展。C++ 源码通过 编译为 .node 后缀的二进制文件(类似于 .dll 和 .so)。在 Node.js 环境中可以直接用 require() 函数将 .node 文件初始化为动态链接库。一些 npm 包会包含 C++ 扩展,例如: 、、,但都是源码版本,在安装后需要编译后才能被 Node.js 调用。

Electron 同样也支持 Node 原生模块,但由于和官方的 Node 相比使用了不同的 V8 引擎,如果你想编译原生模块,则需要手动设置 Electron 的 headers 的位置。

环境准备

不管是 Node.js 环境或是 Electron 中使用原生模块,都需要准备一个编译工具 。我们这里使用的是 windows 环境开发,参考 node-gyp 的安装说明还需要安装 。

用管理员权限打开 CMD 或 PowerShell 窗口,运行以下命令:

npm i -g node-gypnpm i -g --production windows-build-tools复制代码

windows-build-tools 安装时间可能会长一点,要耐心等待。

项目配置

在安装 npm 模块之前还要设置一些环境变量,建议在项目目录下放一个 .npmrc 文件,内容如下:

registry=https://registry.npm.taobao.orgNODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/nodeELECTRON_MIRROR=https://npm.taobao.org/mirrors/electronarch=ia32target_arch=ia32msvs_version=2015disturl=https://atom.io/download/electronruntime=electrontarget=1.8.4build_from_source=true复制代码

参数说明:

registry - 配置 npm 包镜像
NODEJS_ORG_MIRROR - 配置 Node.js 头文件下载镜像
ELECTRON_MIRROR - Electron 下载镜像
disturl - Electron 头文件镜像(用了 electron-rebuild 模块才需要)
arch、target_arch - 根据目标环境定义为 ia32 或 x64

编译

通过以上配置不需要 ,直接用 npm 或 yarn 安装新原生包的时候,会自动编译为适用当前 electron 版本的原生模块到 {module_name}/build/Release/xxx.node。由于这个构建后的路径是动态的,node-ffi 等第三方模块会使用 去动态找到这个 .node 文件。bindings 的原理是,首先定位到当前包的目录,然后通过预设一些搜寻路径,一个个尝试读取,直到找到为止。

项目构建

问题:找不到 .node 文件

bindings 的搜寻方式在 js 源码未压缩的情况下当然没问题,但我们的项目中通常还使用了 webpack。

在开发模式下能够找到 node_modules 下的文件也没有问题,构建到生产环境后就没有 node_modules 了,而且 webpack 也不支持打包动态路径的文件。我想到两种解决方案:

方案一、将 node-ffi 拷贝一份修改 bindings 为写死路径,当然每个用到 bindings 的包都要修改。

// ffi 下的 bindings.jsmodule.exports = require('bindings')('ffi_bindings.node')// 改为module.exports = require('../build/Release/ffi_bindings.node')复制代码

方案二、自己实现一个 bindings 映射,并利用 webpack 的 alias 功能替换 bindings 模块。

  1. 增加 bindings.js
function bindings (name) {  if (name === 'ffi_bindings.node') {    return require('ffi/build/Release/ffi_bindings.node')  }  if (name === 'binding') {    return require('ref/build/Release/binding.node')  }}module.exports = bindings复制代码
  1. 配置 webpack 别名
// webpack.main.config.jsmodule.exports = {  ...,  resolve: {    extensions: ['.js', '.json', '.node'],    alias: {      // 如果用 bindings 包,就会找不到 .node 模块,这里替换成自己的实现      'bindings': path.resolve(__dirname, '../addons/bindings.js')    }  },  ...复制代码

显然方案二更好一点,只需要自己实现一个 bindings.js,而不用去动第三方包的源码,所以我们直接用了方案二。

问题:打包 asar 后,提取出 .node 文件

Electron 官方文档有说明,二进制文件不要在 asar 中执行,需要 unpack 出来。我们用了 可以通过 参数配置:

asar: {    unpack: '*.node'  }复制代码

这样,会把 .node 文件都提取到 app.asar.unpacked 目录。但是它只负责提取并不会自动更新 .node 文件的访问地址到新的路径。所以我想到了用 webpack 的 file-loader

// webpack.main.config.jsmodule: {  rules: [    {      test: /\.node$/,      loader: 'file-loader',      options: {        name: '[name].[ext]',        outputPath: 'addons',        publicPath: '../../app.asar.unpacked/addons'      }    }  ]}复制代码

我 app 打包后的项目结构是这样的

app.asar.unpackedapp---main---renderer---package.json复制代码

JS 是在 main 目录的主线程里面访问原生模块的,打包出来的路径也是这样。所以相对路径是要向上两级找到 app.asar.unpacked 目录。

运行一下 npm run build 打包。

文件按我预期那样生成好了!

好的,运行一下程序:

TypeError: Cannot read property 'int64' of undefined

程序跑不起来了!

bindings 也是直接 require('addon.node') 呀,Node.js 官网。怎么构建后就不行了呢?

后面,我在webpack 的 loader 中找到 ,里面说明

在 enhanced-require 中执行 node add-ons
所以,node-loader 是针对魔改过的
require(非 node 环境 require)的。这有可能是在 Electron 或是 webpack 发生的。

于是我对.node文件增加一个node-loader

module: {  rules: [    {      test: /\.node$/,      use: [        'node-loader',        {          loader: 'file-loader',          options: {            name: '[name].[ext]',            outputPath: 'addons',            publicPath: '../../app.asar.unpacked/addons'          }        }      ]    }  ]}复制代码

然后重新构建。

一切问题都解决了!

相关资料:

转载于:https://juejin.im/post/5c9cb1baf265da60e17d0f98

你可能感兴趣的文章
UTF-8 简史
查看>>
Keycloak 6.0.0 正式发布,身份和访问管理系统
查看>>
spring boot2 整合(二)JPA(特别完整!)
查看>>
阿里云MVP张杰:互联网金融行业异地容灾方案实战分享
查看>>
PageTransformer实现一个层叠的卡片
查看>>
swagger-bootstrap-ui 1.8.5 发布,Swagger增强UI实现
查看>>
开发笔记5 | 阿里云Eclipse插件安装与使用(视频演示)
查看>>
QML学习笔记(七)-如何查看帮助手册中的控件例子
查看>>
旧手机的新玩法:postmarketOS 已适配上百款安卓手机
查看>>
InitAdmin 201904 更新,首创云后台概念
查看>>
jvm系列文章
查看>>
Countly 19.02.1 发布,实时移动和 web 分析报告平台
查看>>
自定义 标签
查看>>
百度贴吧发贴回贴POST接口
查看>>
【Recorder.js+百度语音识别】全栈方案技术细节
查看>>
PS背后的神秘AI力量 是Adobe憋了十年的神功
查看>>
加速Web自动化测试
查看>>
8月分享与总结
查看>>
Kotlin学习探索-前言
查看>>
《Learning Scrapy》(中文版)第9章 使用Pipelines
查看>>