Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@nao-a

electron-vue で dialog.showOpenDialog(...) しようとした時に出る厄介なエラーと対処法

はじめに

electron-vueでWindows/macOS向けのアプリを作成することがあると思います

デスクトップ向けOSのアプリで欲しい機能といえば、おそらく 「ファイル(ディレクトリ)を開くダイアログ」 ではないでしょうか? (少なくとも私はそうでした)

そんなときに、dialogを使用しようとすると出る厄介なエラーとその解決方法を記載します

※前提として、Typescriptで一部のコードが記載されています

元のコードと発生するエラー

元のコード

MyComponent.vue
<template>
  <div class="mycomponent">
    <button @click="OpenDialog" />
  </div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { remote } from 'electron

@Component
export default class AppCard extends Vue {
  private OpenDialog() {
    remote.dialog.showOpenDialog({defaultPath: '/', properties: ['openFile']})
  }
}
</script>
src/background.ts
// :
// :
async function createWindow() {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      enableRemoteModule: true,
    }
  })

  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
  }
}
// :
// :

発生するエラー

Uncaught ReferenceError: __dirname is not defined

スクリーンショット 2021-02-11 19.02.59.png

解決方法

// src/background.ts
// :
// :
 async function createWindow() {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
       enableRemoteModule: true,
+      nodeIntegration: true
    }
  })

  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
  }
}
// :
// :

解決した結果

一難去ってまた一難とはこのことだと感じます

スクリーンショット 2021-02-11 19.02.14.png

さらに修正します

  1. preloadの項目をwebPreferenceに追加し
  2. preload.jsを対象のプロジェクトに追加し
  3. preload.jsを記述し
  4. 実際に showOpenDialog を呼び出す箇所を変更します

1. preloadの項目をwebPreferenceに追加

// src/background.ts
// :
// :
async function createWindow() {
  // Create the browser window.
  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
      enableRemoteModule: true,
+      preload: path.join(__dirname, '..', 'src', 'preload.js'),
      nodeIntegration: true
    }
  })

  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
  }
}
// :
// :

2. preload.js をプロジェクトに追加 (パスは先ほど追加したコードの位置と合わせる必要があります)

スクリーンショット 2021-02-11 19.20.17.png

3. preload.jsを記述

preload.js
const remote = require("electron").remote;
window.remote = remote;

4. 実際に showOpenDialog を呼び出す箇所を変更

<!-- MyComponent.vue -->
<template>
  <div class="mycomponent">
    <button @click="OpenDialog" />
  </div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { remote } from 'electron

@Component
export default class AppCard extends Vue {
  private OpenDialog() {
-        remote.dialog.showOpenDialog({defaultPath: '/', properties: ['openFile']})
+        window.remote.dialog.showOpenDialog({defaultPath: '/', properties: ['openFile']})
  }
}
</script>

最終コード

src/background.ts
// :
// :
async function createWindow() {
  // Create the browser window.
  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
      enableRemoteModule: true,
      preload: path.join(__dirname, '..', 'src', 'preload.js'),
      nodeIntegration: true
    }
  })

  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
  }
}
// :
// :
preload.js
const remote = require("electron").remote;
window.remote = remote;
MyComponent.vue
<template>
  <div class="mycomponent">
    <button @click="OpenDialog" />
  </div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { remote } from 'electron

@Component
export default class AppCard extends Vue {
  private OpenDialog() {
    window.remote.dialog.showOpenDialog({defaultPath: '/', properties: ['openFile']})
  }
}
</script>

ただし

以下のように、tslintによって赤波線が立ちます
ので、windowに依存させない方法をとった方が良いかもしれません

スクリーンショット 2021-02-11 19.27.56.png

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
nao-a
I am dev (so fat)

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?