如何在vue.js中导入ipcRenderer? __dirname未定义

时间:2020-08-27 11:50:26

标签: javascript typescript vue.js electron ipcrenderer

我正在努力了解如何在.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存储库。 您可以从此处git复制存储库:https://github.com/raphael10-collab/ElectronVueTypeScriptScaffolding.git

执行完纱线后->纱线电子:发条 您将获得正确的页面。

但是在/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

如何解决问题? 期待您的帮助

3 个答案:

答案 0 :(得分:1)

要将ipcRenderer与Vue CLI插件Electron Builder一起使用,您需要首先设置electronic以使用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

答案 1 :(得分:1)

对我有用的是将电子窗口的 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,这使得 window 看到的 preload.js 与您的 vue 应用程序看到的不同。< /p>

答案 2 :(得分:-1)

您需要将nodeIntegration设置为true

这将在渲染器进程(即前端)中启用NodeJ,因此您可以在Vue代码中使用fs(文件系统)之类的功能以及其他仅NodeJs的功能。

由于ipcRenderer也需要NodeJ的环境(__dirname仅是NodeJ的全局变量),因此需要将其激活。