如何在 vue.js 中导入 ipcRenderer? __dirname 未定义
Posted
技术标签:
【中文标题】如何在 vue.js 中导入 ipcRenderer? __dirname 未定义【英文标题】:How to import ipcRenderer in vue.js ? __dirname is not defined 【发布时间】:2020-12-16 07:11:58 【问题描述】:我很难理解如何在 .vue 文件中正确导入 ipcRenderer。
我放入 /src/background.js 文件:
webPreferences:
nodeIntegration:false,
contextIsolation: true, // protects against prototype pollution
preload: path.join(__dirname, "../dist_electron/preload.js"),
并且,基于https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration,我输入了 preload.js :
window.ipcRenderer = ipcRenderer
webpack.config.js:
module.exports =
entry: './src/background.js',
target: 'node',
output:
path: path.join(__dirname, 'build'),
filename: 'background.js'
为了方便调试,我创建了一个github repo。 你可以从这里 git clone 仓库:https://github.com/raphael10-collab/ElectronVueTypeScriptScaffolding.git
执行yarn后->yarn electron:serve 你会得到正确的页面。
但是当在 /src/views/Home.vue 中激活这一行时:
//从“电子”导入 ipcRenderer
你会得到这个错误:
__dirname is not defined
Environment Info:
System:
OS: Linux 5.4 Ubuntu 18.04.5 LTS (Bionic Beaver)
CPU: (8) x64 Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz
Binaries:
Node: 14.5.0 - ~/.nvm/versions/node/v14.5.0/bin/node
Yarn: 1.22.4 - /usr/bin/yarn
npm: 6.14.5 - ~/.nvm/versions/node/v14.5.0/bin/npm
Browsers:
Chrome: 85.0.4183.83
Firefox: 79.0
npmPackages:
@vue/babel-helper-vue-jsx-merge-props: 1.0.0
@vue/babel-plugin-transform-vue-jsx: 1.1.2
@vue/babel-preset-app: 4.4.6
@vue/babel-preset-jsx: 1.1.2
@vue/babel-sugar-functional-vue: 1.1.2
@vue/babel-sugar-inject-h: 1.1.2
@vue/babel-sugar-v-model: 1.1.2
@vue/babel-sugar-v-on: 1.1.2
@vue/cli-overlay: 4.4.6
@vue/cli-plugin-babel: ~4.4.0 => 4.4.6
@vue/cli-plugin-e2e-cypress: ~4.4.0 => 4.4.6
@vue/cli-plugin-router: ~4.4.0 => 4.4.6
@vue/cli-plugin-typescript: ~4.4.0 => 4.4.6
@vue/cli-plugin-unit-mocha: ~4.4.0 => 4.4.6
@vue/cli-plugin-vuex: ~4.4.0 => 4.4.6
@vue/cli-service: ~4.4.0 => 4.4.6
@vue/cli-shared-utils: 4.4.6
@vue/component-compiler-utils: 3.2.0
@vue/preload-webpack-plugin: 1.1.2
@vue/test-utils: ^1.0.3 => 1.0.3
@vue/web-component-wrapper: 1.2.0
babel-helper-vue-jsx-merge-props: 2.0.3
typescript: ^3.9.7 => 3.9.7
vue: ^2.6.11 => 2.6.11
vue-class-component: ^7.2.5 => 7.2.5
vue-cli-plugin-electron-builder: ~2.0.0-rc.4 => 2.0.0-rc.4
vue-hot-reload-api: 2.3.4
vue-i18n: ^8.20.0 => 8.20.0
vue-loader: 15.9.3
vue-property-decorator: ^9.0.0 => 9.0.0
vue-router: ^3.2.0 => 3.3.4
vue-style-loader: 4.1.2
vue-template-compiler: ^2.6.11 => 2.6.11
vue-template-es2015-compiler: 1.9.1
vuex: ^3.5.1 => 3.5.1
vuex-class: ^0.3.2 => 0.3.2
npmGlobalPackages:
@vue/cli: 4.4.6
node version: v14.5.0
更新 1)
我尝试将 webPreferences 设置如下(使用 nodeIntegration: true):
webPreferences:
nodeIntegration: true,
//contextIsolation: true, // protects against prototype pollution
//preload: path.join(__dirname, "../dist_electron/preload.js"),
,
得到了这个错误:
fs.existsSync is not a function
四处搜索有关此类问题的信息,我发现了这篇文章: How to resolve fs.existsSync is not a function 通过此链接:https://webpack.js.org/concepts/targets/
但我已经在 webpack.config.js 中指定了目标“节点”:
在 webpack.config.js 中:
module.exports =
entry: './src/background.js',
target: 'node',
output:
path: path.join(__dirname, 'build'),
filename: 'background.js'
那么...如何解决这个新问题?
顺便说一句, 为什么一定要放
webPreferences:
nodeIntegration: true,
如果出于安全原因,更安全的是:
webPreferences:
nodeIntegration:false,
contextIsolation: true, // protects against prototype pollution
preload: path.join(__dirname, "../dist_electron/preload.js"),
dist_electron/preload.js :
const
contextBridge,
ipcRenderer
= require("electron");
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
"api",
send: (channel, data) =>
// whitelist channels
let validChannels = ["toMain"];
if (validChannels.includes(channel))
ipcRenderer.send(channel, data);
,
receive: (channel, func) =>
let validChannels = ["fromMain"];
if (validChannels.includes(channel))
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) =>
func(...args));
);
window.ipcRenderer = ipcRenderer
https://www.electronjs.org/docs/tutorial/security#electron-security-warnings
更新 2)
在 vue.config.js 我放了:
module.exports =
pluginOptions:
electronBuilder:
preload: 'dist_electron/preload.js',
// Or, for multiple preload files:
//preload: preload: 'src/preload.js', otherPreload:
//'src/preload2.js'
但是当我这样做时,我得到了同样的错误
yarn electron:serve
UncaughtReferenceError: __dirname is not defined
在设置 nodeIntegration: true 时(但我更愿意将其设置为 false,并使用 preload.js 文件),我得到另一个错误(如上):
Uncaught TypeError: fs.existsSync is not a function
Uncaught TypeError: fs.existsSync is not a function
如何解决问题? 期待您的帮助
【问题讨论】:
【参考方案1】:更新答案 - 禁用 Nodeintegration 并启用 contextIsolation
为了将 ipcRenderer 与 Vue CLI 插件 Electron Builder 一起使用,您需要首先设置 electron 以使用 preload.js 文件。
在您的vue.config.js
文件中,您需要像这样添加preload.js
路径:
// vue.config.js - project root
module.exports =
pluginOptions:
electronBuilder:
preload: 'src/preload.js',
// Or, for multiple preload files:
preload: preload: 'src/preload.js', otherPreload: 'src/preload2.js'
接下来,您需要更新您的background.js
文件以在网络首选项中使用preload.js
,如下所示:
// src/background.js
const win = new BrowserWindow(
width: 800,
height: 600,
webPreferences:
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
enableRemoteModule: true,
preload: path.join(__dirname, 'preload.js'),
,
)
注意:
nodeIntegration
默认禁用,contextIsolation
默认启用
完成后,您可以在 src 目录中创建 preload.js
文件。
启用contextIsolation
后,您需要导入contextBridge
和ipcRenderer
。然后您可以将ipcRenderer
公开给您的客户。
然后将其添加到文件中:
// src/preload.js
import contextBridge, ipcRenderer from 'electron'
// Expose ipcRenderer to the client
contextBridge.exposeInMainWorld('ipcRenderer',
send: (channel, data) =>
let validChannels = ['nameOfClientChannel'] // <-- Array of all ipcRenderer Channels used in the client
if (validChannels.includes(channel))
ipcRenderer.send(channel, data)
,
receive: (channel, func) =>
let validChannels = ['nameOfElectronChannel'] // <-- Array of all ipcMain Channels used in the electron
if (validChannels.includes(channel))
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args))
)
注意:您需要确保您的
preload.js
文件位于src
文件夹中,而不是dist_electron
中
要测试并确保预加载文件正常工作,您还可以在 preload.js
文件中创建警报
// src/preload.js
import contextBridge, ipcRenderer from 'electron'
// Expose ipcRenderer to the client
contextBridge.exposeInMainWorld('ipcRenderer',
send: (channel, data) =>
let validChannels = ['nameOfClientChannel'] // <-- Array of all ipcRenderer Channels used in the client
if (validChannels.includes(channel))
ipcRenderer.send(channel, data)
,
receive: (channel, func) =>
let validChannels = ['nameOfElectronChannel'] // <-- Array of all ipcMain Channels used in the electron
if (validChannels.includes(channel))
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args))
)
alert("It Worked!") // Remove this line once you confirm it worked
当您验证您的预加载脚本工作正常后,您可以从您的 vue 应用访问ipcRenderer
。
像这样:
// src/App.vue
<template>
\\ Some html
</template>
<script>
export default
name: "App",
methods:
test()
window.ipcRenderer.send(channel, args...) // or any other ipcRenderer method you want to invoke
;
</script>
在电子中你可以监听这些事件
// background.js
ipcMain.on(channel, (event, args) =>
// Do stuff
);
来源:https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/guide.html#preload-files https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration With contextIsolation = true, is it possible to use ipcRenderer?
原答案
为了将 ipcRenderer 与 Vue CLI 插件 Electron Builder 一起使用,您需要首先设置 electron 以使用 preload.js 文件。
在您的vue.config.js
文件中,您需要像这样添加preload.js
路径:
// vue.config.js - project root
module.exports =
pluginOptions:
electronBuilder:
preload: 'src/preload.js',
// Or, for multiple preload files:
preload: preload: 'src/preload.js', otherPreload: 'src/preload2.js'
接下来,您需要更新您的background.js
文件以在网络首选项中使用preload.js
,如下所示:
// src/background.js
const win = new BrowserWindow(
width: 800,
height: 600,
webPreferences:
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/configuration.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
+ preload: path.join(__dirname, 'preload.js')
)
完成后,您可以在 src 目录中创建 preload.js
文件
然后将其添加到文件中:
// src/preload.js
import ipcRenderer from 'electron'
window.ipcRenderer = ipcRenderer
注意:您需要确保您的
preload.js
文件位于src
文件夹中,而不是dist_electron
中
要测试并确保预加载文件正常工作,您还可以在 preload.js
文件中创建警报
// src/preload.js
import ipcRenderer from 'electron'
window.ipcRenderer = ipcRenderer
alert("It Worked!") // Remove this line once you confirm it worked
当您确认您的预加载脚本工作正常后,您可以从您的 vue 应用访问 ipcRenderer。
像这样:
// src/App.vue
<template>
\\ Some html
</template>
<script>
export default
name: "App",
methods:
test()
window.ipcRenderer.send(channel, args...) // or any other ipcRenderer method you want to invoke
;
</script>
来源:https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/guide.html#preload-files https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration
【讨论】:
为我工作,但这是一些疯狂的样板...... 此解决方案来自 Vue CLI Plugin Electron Builder 文档。 nklayman.github.io/vue-cli-plugin-electron-builder/guide/…读了好久,不过看了几遍还是挺直接的。 谢谢,是的,该文档很有帮助,我希望他们能像您一样展示一个使用共享窗口对象的示例,这在 IMO 部分中有点差距。 不起作用console.log( window.ipcRenderer)
= 未定义:|
@A1Gard 您能否针对您遇到的问题提出一个新问题并将其链接到此处。我会尽力提供帮助。【参考方案2】:
对我有用的是将电子窗口的contextIsolation
设置为false
。
所以在您的main.js
中,无论您创建BrowserWindow
,它都会如下所示:
const win = new BrowserWindow(
webPreferences:
contextIsolation: false,
preload: path.join(__dirname, 'preload.js'),
,
)
然后在preload.js
你可以简单地做
const ipcRenderer = require('electron')
window.ipcRenderer = ipcRenderer
然后你就可以在你的 vue 代码的任何地方访问ipcRenderer
。
似乎在当前版本的电子contextIsolation
中默认为true
,这使得preload.js
看到的window
与您的vue 应用看到的不同。
【讨论】:
不要这样做,您正在关闭安全措施并使用不推荐的方法来考虑 IPC 用于 Renderer 进程,而它应该能够使用之前定义的相同 IPC名字。【参考方案3】:您需要将nodeIntegration
设置为true
。
这会在渲染器进程(即前端)中启用 NodeJ,因此您可以在 Vue 代码中使用 fs(文件系统)和其他仅限 NodeJ 的功能。
由于 ipcRenderer 也需要 NodeJs 的环境(__dirname 只是 NodeJs 的全局变量),所以需要激活它。
【讨论】:
嗨@Oussama!感谢您的帮助!!我用更新 1 更新了我的帖子) 嗨,是的,您对 preload.js 解决方案是正确的,它更安全,但缺点是您要将逻辑放在 public/ 文件夹中,这不是很理想。至于错误,因为您使用的是vue-cli-plugin-electron-builder
,我建议您尝试在vue.config.js
中添加您的配置,如文档中所述:nklayman.github.io/vue-cli-plugin-electron-builder/guide/… 而且,为了确定,请确保您正在运行您的应用程序使用 yarn electron:serve
而不是在浏览器中。
我在尝试运行我的应用程序时一直在使用 yarn electron:serve。我用更新 2) 更新了我的帖子。感谢您的帮助。以上是关于如何在 vue.js 中导入 ipcRenderer? __dirname 未定义的主要内容,如果未能解决你的问题,请参考以下文章
如何在vue.js项目的main.js文件中导入js类并在所有组件中使用它而不是在每个组件中导入?
如何使用 axios 在 Vue Js 中导入 json 数据