Possible causes for errors in packaging an Electron App

While trying to build and package your Electron application, you may occasionally encounter file load errors. Your application works perfectly in development but the distribution returns nothing more than a blank white page.

You may get error messages such as Unable to load preload script: … resources/app.asar/preload.js, Not allowed to load local resource: file://src/index.html or even Application entry file “dist/main.js” in the linux-unpacked/resources/app.asar” does not exist. Seems like a wrong configuration.

All of the above-mentioned error messages stem from file path problems. Your packaged Electron application requires absolute paths to the HTML file, modules and extra resources. And the paths in the distribution package are not always the same as those in the development.

There are a NodeJS variable and Electron functions to avoid this problem. In whichever file (or on whichever operating system) you invoke your NodeJS process, __dirname always returns the absolute path of where you start it. Electron app API allows you to get and set paths to your application resources.

Instead of using the relative path that can cause an error in production, you can set up the paths using __dirname in the main process.

If your application won’t load the HTML file using __dirname, your problem presumably won’t be related to Electron.

When bundled by Webpack, the variable __dirname doesn’t automatically show the path to build resources but to your project root, or a single forward slash ‘/’. This may be the cause of your trouble. In this case, you just need to open your webpack config and set false to node: {__dirname: }.

Then __dirname will return the path to the current application directory. Neither setting “asar”: false nor specifying “devEngines” is required. app.getPath(name) works in the same manner. This function is really useful for saving application settings and user data. Quite apart from userData, where your app’s configuration files are stored, it returns the absolute paths to User’s home, Desktop, Downloads and Documents as well.

All the Electron Docs! | Electron

For your reference, here is my version information.

React コンポーネントに history がないときに確認すること

ReactJS を使ってシングルページアプリケーション(SPA)を作成する際、コンポーネント内に props.history が見当たらないことがあります。

例えば CRUD (DBMS) 操作を行った直後にリダイレクトを行う際などに、このエラーが生じるとページ遷移も DOM の書き換えも行われません。

そこでエラー表示を少し調べてみると this.props.history が見当たらないことはありえないとか、withRouter を使ってリダイレクトする方法があるなど、いろいろな(自然)言語で好き勝手なことが書かれていることが分かります。

しかし、このエラー表示が生じた環境において TypeScript をお使いの場合、コンポーネント、つまり props や state の各変数の型定義が行われていないことを最初に疑った方が良いかも知れません。

つまり interface にてコンポーネント内の変数の型を自身で定義して React.Component <{},{}> に渡すと問題が解決する場合があります。

以下に具体例を提示します。

少し考えてみると自明なことなのですが、ドキュメントを読み返してみても原因らしきものが思い当たらなくて困惑しました。最終的に解決に役立ったのはこちらです。


TypeScript and React – Hello React and TypeScript
https://charles-bryant.gitbook.io/hello-react-and-typescript/typescriptandreact


実行環境は下記のとおりになります。

この分野は変化が激しく、毎年のように仕様が変わるので解決法をお探しのかたは記事の書かれた時期とバージョンに細心の注意を払ってください。

最後に繰り返しになりますが、私はスクリプト言語もフロントエンドも心の底から嫌いです。嫌いなので仕事では絶対に触りたくありません。

Electron & React で ContextBridge を使って安全に DB 操作する

HTML や CSS などの Web 技術を用いてクロスプラットフォームなデスクトップアプリを開発できるフレームワーク ELECTRON

動的なウェブサイトを構築できるライブラリ React (ReactJS)

この2つを組み合わせて、データベース (CRUD) 操作を行えるアプリ作成を考えます。

セキュリティを考える

一見すると、この課題には難しい点はないように思われます。

Renderer プロセスから ipcRenderer を読み込み、Main プロセスの ipcMain との間でプロセス間通信を実行すれば、Main プロセスを介して Renderer プロセスと DB との間でデータの受け渡しが可能です。

ところが、2020年現在、こうした設計はセキュリティ上の理由から推奨されていません。XSS で Node.js Modules にアクセスされて SSH キーを不正取得されたりしても困るといった動機は理解できますが、不便でもあります。

そこで Renderer プロセスから安全に Node.js Modules を利用するため、ほかのスクリプト実行前にあらかじめ preload で読み込むことを行います。

この preload において contextBridge を用いて関数を API 化し Renderer プロセスから利用可能にすることが最近のセキュリティ重視の設計です。

ここで問題となるのは contextBridge によって作成された API (オブジェクト) には型定義が存在しないため TypeScript のコンパイル時にエラーの原因となります。

TypeScript は React を安全に使うために必要です。

ELECTRON が用いる HTML/CSS/JS にはデスクトップアプリに適した UI フレームワークが存在しないため React がそれを補います。つまり React もあったほうがいいものです。

それらのリソースを管理するのは Webpack です。

こうした一つ一つの要素技術に設定ファイルがありますので、組み合わせると面倒なことになります。




整理すると、やるべきことは次のようになります。

(1) Main プロセスにおいて preload を読み込む
(2) Preload において関数を API 化する
(3) API の型定義を行う
(4) Webpack の設定ファイルを書き換える
(5) データベースに接続して操作を行う

ここで断っておきますが、私はフロントエンドもスクリプト言語も嫌いです。当然ながら専門家ではありません。最新の公式ドキュメントには目を通していますが、より良い方法がほかにあるかもしれません。

実行環境

実行環境は以下のとおりです。

TypeORM をインストールはしていますが後述の理由から使用しません。また機能要件に対して必要性を感じないので Redux も使用しません。

Main プロセスにおいて preload を読み込む

ELECTRON の main プロセスの内容を記述したファイルを main.ts とすると、その内容は次のようになるはずです。

ここでドキュメントに従い、BrowserWindow の中に preload を設定します。

ファイルパスは環境に応じて適宜変更してください。

Preload において関数を API 化する

Main プロセスから preload を読み込むよう設定したあとは、main プロセスと renderer プロセスとの間で通信を行う準備を行います。

ここで contextBridge を用いて関数を API 化することが肝要です。

先述のように contextBridge によって作成された API (オブジェクト) には型定義が存在しないため TypeScript のコンパイル時にエラーの原因となります。

API の型定義を行う

そこで正統な対処法として、型定義ファイルを作成して tsconfig に定義ファイルを読み込ませることがよく行われます。

個人的に確認はしていませんが、原則的にはこれで問題なく動作すると思われます。

この代わりに、私は API に対して interface を作成し、実行時に import することを行いました。

これで main プロセスと renderer プロセスとの間でデータの受け渡しを行えるようになります。

Webpack の設定ファイルを書き換える

型定義を与えてコンパイル(トランスパイル)できるようになっても、肝心の preload.js ファイル自体が実行ファイルとして読み込まれなければ意味がありません。

そのために次は webpack.config.js の設定を書き換えて preload を読み込ませます。

具体的には entry と output の項目に preload を書き加えるだけで大丈夫です。




データベースに接続して操作を行う

ようやくデータベースを利用する準備が整いましたので、main プロセスからデータベースに接続する関数を記述します。

これを IPC 通信を用いて renderer プロセスから呼び出してやれば良いわけです。

ここに来てついに React の出番となります。

preload にて定義した API のelectronIpcInvoke を呼び出します。

これで Connect ボタンをクリックすると IPC 通信で main プロセスの connectTest を呼び出して、データベースに接続・操作を行います。

この状態でビルド、実行してボタンをクリックした際に以下のように表示されれば成功です。

TypeORM を使えない

以下は余談です。

TypeORM (version 0.2.26) にて ormconfig.json を作成せずに createConnection に直接的に引数を渡そうとするとエラーになります。

より具体的には以下のようなことをやっています。

明らかに現状では開発中のライブラリですし、どうしても必要なものではありませんので私は使用することを諦めました。

ちなみに下記のようなエラーはコンストラクタを作成して各カラムの変数を初期化すると消えます。


TS2564: Property ‘name’ has no initializer and is not definitely assigned in the constructor.


エンティティを定義されているファイルに constructor を追加してやれば問題解決です。

また次のようなエラーは tsconfig.json の設定により表示を消すことができます。


TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the ‘experimentalDecorators’ option in your ‘tsconfig’ or ‘jsconfig’ to remove this warning.


お好きなエディタで設定ファイルを開いて該当箇所のコメントアウトを削除してください。

こうしたマイナーなエラーは簡単に対処できますが、データベースに接続できないことにはどうしようもありません。

改善されることを待つか、使用することを諦めるほかにありません。私はもう諦めてしまいました。

Contact Us