在电子应用程序中运行时加载 Nodejs 模块

Posted

技术标签:

【中文标题】在电子应用程序中运行时加载 Nodejs 模块【英文标题】:Loading Nodejs Module at runtime in electron app 【发布时间】:2020-10-05 21:41:04 【问题描述】:

目前我正在使用vue-cli-plugin-electron-builder 和一个简单的vue 项目一起玩electron。这是https://github.com/nklayman/vue-cli-plugin-electron-builder 项目。

   vue create my-project
   cd my-project
   vue add electron-builder
   npm run electron:serve

我的目标是添加一个简单的类似插件的架构。该应用程序仅提供基本功能,但可以使用“插件”进行扩展。因此,这些插件不包含在构建中,但会在运行时由电子加载。当这些插件表现得像节点模块(module.exports =)时,我更喜欢它自己的依赖项(可能在里面有一个 package.json 文件)。我会在app.getPath('userData') + '/Plugins 找到这些插件。

我研究了一些解决这个问题的方法:


1。使用 Nodejs vm 模块

首先,我尝试使用 Nodejs vm 模块在运行时从外部文件读取和执行脚本。到目前为止它工作得很好,尽管我无法在那些加载的脚本中使用外部依赖项。如果我想在插件脚本中使用外部依赖项,这些依赖项必须事先包含在电子构建中。不知何故违背了拥有插件的全部目的......只有 vanilla js + nodejs 基本模块是可能的。


2。使用global.require

我在另一个 SO 答案中看到了这个解决方案。

Using node require with Electron and Webpack Webpack/electron require dynamic module

他们说要使用global.require,但它会抛出一个错误,说global.require is not a function。该解决方案首先看起来很有希望,但不知何故我无法让它发挥作用。


3。只需使用require

当然,我必须尝试一下。当我尝试从非项目位置require 外部模块时,即使路径正确,它也找不到该模块。同样,我试图定位模块的路径应该在app.getPath("userData"),而不是在项目根目录中。但是,当我在项目的根目录中找到插件时,它会包含在构建中。这再次违背了拥有插件的目的。


目标

到目前为止,我还没有找到可行的解决方案。我只是希望我的电子应用程序可以在运行时使用基本节点模块进行扩展(遵循预定义的模式来简化)。当然还有atom,用electron 制作,使用他们自己的apm 管理器来安装和加载插件,但这似乎有点过于强大了。对我来说,只有本地的插件文件就足够了,拥有一个公共的“市场”不是目标。此外,如果应用程序必须重新加载/重新启动以加载插件,也可以。

有什么想法吗?

【问题讨论】:

【参考方案1】:

经过越来越多的研究,我偶然发现了 2 个包:

https://www.npmjs.com/package/live-plugin-manager https://github.com/getstation/electron-package-manager

两者都集成了npm 以在运行时以编程方式处理包安装。我现在选择live-plugin-manager,因为它有更好的文档记录,甚至允许从本地文件系统安装包。

专业版

我能够将系统开箱即用地集成到香草电子应用程序中。奇迹般有效。

缺点

。我无法在 vue electron 样板文件中使用它(就像我说我在 OP 中使用的样板文件),因为 webpack 干扰了 require 环境。但肯定有办法解决这个问题。

更新:我最终能够让它在 webpack 捆绑的电子 vue 样板中工作。我不小心混合了 importrequire 。以下代码适用于我使用live-plugin-manager

// plugin-loader.js
const path = require('path');
const  PluginManager  = require('live-plugin-manager');
const pluginInstallFolder = path.resolve(app.getPath('userData'), '.plugins');
const pluginManager = new PluginManager();

module.exports = async (pkg) => 
  // installs pkg from npm
  await pluginManager.install(pkg);
  const package = pluginManager.require(pkg);
  return package

// main.js
const pluginLoader = require('./plugin-loader');
pluginLoader("moment").then((moment) => 
   console.log(moment().format());
)

这将在运行时从 npm 安装“moment”包到本地目录并将其加载到应用程序中,而不会将其捆绑到可执行文件中。

【讨论】:

感谢您分享您的作品!经过一个小时的谷歌搜索,我很高兴找到你的帖子!祝你的应用好运。 很高兴我能帮上忙 :) 我对我的发现也很满意

以上是关于在电子应用程序中运行时加载 Nodejs 模块的主要内容,如果未能解决你的问题,请参考以下文章

在ember中运行时创建模型属性

找出python程序中运行时最耗时间的部分

应用程序在模拟器中运行时卡在启动画面上

在模拟器中运行时从应用程序获取工作目录

应用程序正在模拟器中定位,但在实际的 android 设备中运行时没有

当应用程序在权限处理中运行时,颤振蓝牙给出错误