📘

electron-storeで保存した設定にワーカースレッドからアクセスする方法

2023/02/28に公開

electron-store で保存した設定に electron のメインプロセスで起動したワーカースレッドからアクセスする方法について共有します。

electron-store から conf に切り替える

electron-store は conf パッケージを electron 環境で扱いやすく継承したものになります。(conf パッケージと同じ開発者が electron-store を提供しています。)

https://github.com/sindresorhus/electron-store/blob/main/index.js

electron-store のソースファイルは実質この index.js のみで、Conf を継承したコンストラクタ内で electron のapp.getPath('userData')によりアプリの実行環境の場所を得て、cwdオプションが指定されなかった場合は、アプリの実行環境にある設定ファイルを Conf インスタンスで参照するように実装されています。

ところがビルド後の実行環境で起動されるワーカースレッドでは 3 行目のrequire('electron')でエラーが起こります。

開発環境では electron パッケージは devDependencies としてインストールされているためにエラーになりませんが、アプリの実行環境にはインストールされないためです。

そこで electron-store をワーカースレッド内でも実行できる conf パッケージに切り替える手順について説明します。

まず electron-store をアンインストールして conf パッケージをインストールします。conf パッケージはバージョン 10.2.0 を指定してインストールする点に注意してください。

yarn remove electron-store
yarn add conf@10.2.0

conf パッケージは ES Module のため CommonJS 環境である Electron アプリのメインスクリプトから import する場合は CommonJS のスクリプトとして取り込む必要があります。

electron-vite で作成した開発環境の場合、設定ファイルを次のように変更します。

electron.vite.config.ts
export default defineConfig({
  main: {
    // confを外部パッケージから除外する(内部パッケージとして取り込む)
    plugins: [externalizeDepsPlugin({ exclude: ['conf'] })],
    build: {
      rollupOptions: {
        output: {
          manualChunks(id) {
            // confを単体のチャンクとして出力する
            return id.includes('conf') ? 'conf' : undefined;
          },
        },
      },
    },
  },

両スクリプトから import するファイルを用意する

続いて Conf インスタンスを生成するスクリプトファイルを用意します。このスクリプトファイルをメインプロセス、ワーカースレッドの両方からimport store from './store'のように参照して設定にアクセスするものとします。

store.ts
import Conf from 'conf';
import { isMainThread } from 'node:worker_threads';

if (isMainThread) {
  // ポイント1
  const { app } = require('electron');
  process.env.ELECTRON_APP_CONF_CWD = app.getPath('userData');
  process.env.ELECTRON_APP_CONF_VER = app.getVersion();
}

type AppSettings = {
  ...
};

const store = new Conf<AppSettings>({
  // ポイント2
  cwd: process.env.ELECTRON_APP_CONF_CWD,
  projectVersion: process.env.ELECTRON_APP_CONF_VER,
  configName: 'config',
  defaults: {
    ...
  },
});

export default store;

ポイントは次の2点です。

  • メインプロセスの場合は Conf のコンストラクタに渡す値を環境変数に設定する。if 文のスコープ内で electron を require でインポートする点が重要。
  • Conf のコンストラクタには環境変数の値を引き渡してインスタンスを生成する。

ワーカースレッドに環境変数を引き渡して起動する

後はワーカースレッドを起動する際のenvオプションで process.env を渡すようにするだけです。これによりワーカースレッド側で生成される Conf インスタンスは環境変数で設定した場所にある設定ファイルを読み込むようになります。

import { Worker } from "node:worker_threads";
import { resolve } from "node:path";

const worker = new Worker(resolve(__dirname, "./worker.js"), {
  env: process.env,
});

本記事の内容は以上です。

Discussion