javascript - 在带有 Webpack 的 Electron 渲染器中使用 Node.js 插件
问题描述
我有以下渲染器:
import SerialPort from "serialport";
new SerialPort("/dev/tty-usbserial1", { baudRate: 57600 });
它由 Webpack 构建,具有以下配置(为简洁起见):
const config = {
entry: { renderer: ["./src/renderer"] }
output: {
path: `${__dirname}/dist`,
filename: "[name].js",
},
target: "electron-renderer",
node: false, // Disables __dirname mocking and such
};
它由开发服务器和 , 一起提供服务,index.html
并由主进程作为网页加载(这是开发期间热模块更换所必需的)。
主进程由 Webpack 构建并发送到dist
。Webpack 插件还会生成以下内容dist/package.json
:
{
"name": "my-app",
"main": "main.js"
}
当我运行electron dist
时,渲染器进程崩溃并出现以下错误:
Uncaught TypeError: Path must be a string. Received undefined
at assertPath (path.js:28)
at dirname (path.js:1364)
at Function.getRoot (bindings.js?dfc1:151)
at bindings (bindings.js?dfc1:60)
at eval (linux.js?d488:2)
at Object../node_modules/serialport/lib/bindings/linux.js (renderer.js:12686)
at __webpack_require__ (renderer.js:712)
at fn (renderer.js:95)
at eval (auto-detect.js?3cc7:16)
at Object../node_modules/serialport/lib/bindings/auto-detect.js (renderer.js:12638)
我该如何解决?
解决方案
问题
第一个问题是node-bindings
,它node-serialport
依赖于解析其 Node.js 插件的路径,在 Electron 中根本不起作用。这有一个未解决的问题,我认为相关的 PR 甚至不是一个完整的修复,因为我已经进行了一些调试,并且似乎在fileName
整个.undefined
getFileName
第二个问题:即使它以某种方式找到了serialport.node
某个地方,在打包应用程序以进行分发后它也无法工作,因为插件本身不在dist
目录中,并且 Webpack 不能将它与主 JS 文件捆绑在一起。
人们可以尝试用 . 来解决这个问题node-loader
,node-bindings
如果. Webpack 可以做的唯一安全的事情是包含整个项目,“以防万一”,显然,这是绝对不行的,所以只是不复制任何东西。node-bindings
require
node-loader
所以,我们需要手动替换node-bindings
和复制。serialport.node
解决方案
首先,我们必须抓住插件并将其放入dist
. 这需要在 main 的 Webpack 构建中完成,因为渲染器作为网页提供,可能来自内存中的文件系统(因此*.node
文件可能不会发送到磁盘,Electron 永远不会看到它)。就是这样:
import CopyWebpackPlugin from "copy-webpack-plugin";
const config = {
// ...
plugins: [
new CopyWebpackPlugin([
"node_modules/serialport/build/Release/serialport.node",
]),
],
// ...
};
不幸的是,硬编码,但如果发生变化,很容易修复。
其次,我们必须node-bindings
用我们自己的垫片替换src/bindings.js
:
module.exports = x =>
__non_webpack_require__(
`${require("electron").remote.app.getAppPath()}/${x}`
);
__non_webpack_require__
是不言自明的(是的,plainrequire
不会工作,没有一些技巧,因为它是由 Webpack 处理的),并且require("electron").remote.app.getAppPath()
是必要的,因为__dirname
它实际上并没有解决人们所期望的 - 一个绝对路径dist
- 而是某个目录深埋在电子内部。
以下是在渲染器的 Webpack 配置中完成替换的方式:
import { NormalModuleReplacementPlugin } from "webpack";
const config = {
// ...
plugins: [
new NormalModuleReplacementPlugin(
/^bindings$/,
`${__dirname}/src/bindings`
),
],
// ...
};
就是这样!完成上述操作后,某些服务器(或任何您的方法)正在为index.html
+提供服务,看起来像这样:renderer.js
dist
dist/
main.js
package.json
serialport.node
electron dist
应该“正常工作”。
备择方案
可能会node-serialport
在生成的依赖项中添加依赖项并将其安装在其中,dist/package.json
并在 Webpacknpm i
中标记serialport
为外部项,但这感觉更脏(包版本不匹配等)。
另一种方法是将所有内容都声明为外部,然后electron-packager
将整个生产部分复制node_modules
到dist
您,但这基本上是一大堆兆字节。
推荐阅读
- c# - 使用反射调用泛型方法
- python - 将 txt 中的值添加到 csv 新列
- c - 预处理器在声明 unsigned int x 并使用二进制常量初始化时进行编译
- javascript - 从 html 脚本加载 .js 文件时出现 404 错误
- mysql - 为什么在 MySQL 5.6 中,int 字段自动递增跳过“2147483646”?
- docker - 给 docker 分配多少资源
- c++ - std::find() 返回的迭代器不可解引用
- python - 如何将函数应用于集合中的所有元素 namedtuple
- git - 我如何验证 git fetch upstream master 是否确实拉取了更改?
- c# - “无法将'ConcreteTypeMapping'类型的对象转换为在macos上键入'Microsoft.EntityFrameworkCore.Storage.RelationalTypeMapping”WebApi