前言
使用前端框架 (React/Vue/Angular 等) 搭配 Electron 開發桌面應用程式時,最容易在呼叫 Node 套件時遇到問題,此時若查詢相關文獻,會發現大多數人提供一種方法,也就是將 require
改為 window.require
來引用套件。卻伴隨 TypeError: window.require is not a function
錯誤訊息出現,且通常不會提到此問題的解法。因此這裡記錄下個人對於該問題的想法與解決方法,供未來的自己或同好參考。
環境
- node 14.16.1
- electron 13.1.8
- react 17.0.2
問題描述
前端框架預設是以瀏覽器 (Browser) 來執行的,我們可以用其作為桌面應用程式的 UI 開發工具,因此若在前端框架中使用 Browser 預設不支援的套件,就會出現如下的錯誤訊息,告訴我們某些被使用的套件不被 Browser 所支援
1 | Error: Workbook.fromFileAsync is not supported in the browser |
其對應的原始碼為
1 | // App.js |
將上方錯誤訊息拿去餵 Google,大部分的解決方案是將 require
修改為 window.require
,若真的照著做,很大的機率會噴出另一種錯誤訊息
1 | TypeError: window.require is not a function |
根本原因
Electron 將應用程式的運作切割為兩種 Process,分別為 Main Process 與 Render Process,兩個 Process 的環境是隔離開來的,且前端框架都是運作在 Render Process 中。若想在前端中引用 Node 的套件 (該套件預設只允許運作在 Main Process),必須先在 preload.js
明確定義要讓 Render Process 能使用甚麼樣的套件,這樣才能於前端框架中使用。
我們可以將 preload.js
想像是 Main Process 釋放出來的 API,供 Render Process 呼叫使用。通常會以 window
物件來作為介面,例如想在前端使用 remote
模組,就需要先在 preload.js
引入該模組並存放在 window.remote
1 | // preload.js |
若前端需要使用 remote
模組內的模組,例如 dialog
,在前端就可以這樣指定
1 | // App.js |
但這樣還是不夠的,Electron 對於安全性設定非常嚴格,我們需要在 main.js
中建立 BrowserWindow
時,加上 enableRemoteModule
與 contextIsolation
兩個安全性選項
1 | //main.js |
解決方法
理解根本原因後,可以推理出 window.require
應該是已經在 preload.js
中先定義好的介面,但我們 preload.js
中沒有相關定義,所以才會噴出錯誤訊息 (TypeError: window.require is not a function
)。解決方法就是只需要在 preload.js
加上下方程式即可
1 | // preload.js |
這裡我們沒有使用到 remote
模組,因此只需確認 contextIsolation
設為 false
,重新運行 Electron 就能在 Render Process 中使用 window.require
了!
結語
個人非常不建議直接將 Main Process 的 require
開放給 Render Process 使用,這是非常危險的事情。取而代之的是,先明確知道會使用到甚麼套件,再針對該套件來做介面開放,例如
1 | // preload.js |