# Electron + Vite + Typescript + React -- 桌面應用開發 ep1. 環境設定 參考 [Electron Course - Code Desktop Applications (inc. React and Typescript)](https://www.youtube.com/watch?v=fP-371MN0Ck) ## Create project 建一個資料夾,並進入資料夾路徑 1. create vite project ```bash npm create vite . ``` - 選 React ![image](https://hackmd.io/_uploads/BJbOnULrJx.png) - 選 TypeScript ![image](https://hackmd.io/_uploads/ByrK3UIrJe.png) 2. 所有檔案會出現長這樣 ![image](https://hackmd.io/_uploads/HJ2o28US1l.png) 3. 安裝package.json的東西 ```bash npm install ``` ![image](https://hackmd.io/_uploads/SJWx6U8BJx.png) 4. 就會出現 node_modules,裡面就會一堆 dependencies,到這部就算是初步完成project的建置 ![image](https://hackmd.io/_uploads/SJ8fTLIBkl.png) 5. 檢查是否可以跑出預設的介面 - 先下指令 ```bash npm run dev ``` - 會在預設的port長這樣 ![image](https://hackmd.io/_uploads/Sy5J08IBJg.png) ## 設定 React 1. 存放 code 的 `src/` 中新增一個 `ui/` 資料夾 ![image](https://hackmd.io/_uploads/BJh90L8Hke.png) 2. 把預設的的檔案都放到 `ui/` 底下 ![image](https://hackmd.io/_uploads/rkE_JPIr1x.png) 3. 設定 ui 的 javascript 路徑,因為他剛剛被我移到 `ui/` 底下了 ![image](https://hackmd.io/_uploads/rkZyewIByx.png) 4. 測試一下目前做的對不對 ```bash npm run dev ``` ![image](https://hackmd.io/_uploads/Sy5J08IBJg.png) 5. 把 `vite` 的 icon圖片svg 還有不用的東西刪掉 - public 這裡可以整個刪掉 ![image](https://hackmd.io/_uploads/rJ7kbw8H1l.png) - 把有用到這張圖的地方也刪掉 ![image](https://hackmd.io/_uploads/SyuVGwUHJx.png) - 就剩這樣 ![image](https://hackmd.io/_uploads/S1AvbD8Hyg.png) 6. 設定 **包裝完的程式** 要放哪個路徑 - 首先看到他原本 build 完是直接丟在 `dist/` 底下 ```bash npm run build ``` ![image](https://hackmd.io/_uploads/HyaHMDLSyl.png) - 為了跟 electron 的 build 出來的東西有區別,在 `vite.config.ts` 中設定 output 的路徑 ![image](https://hackmd.io/_uploads/B12-IdLBkg.png) - 在跑一次 build,他就會到我們指定的 `dist-react/` 中了,這時候 `dist/` 就可以刪掉了 ```bash npm run build ``` ![image](https://hackmd.io/_uploads/H1oL8d8Syg.png) - 最後,記得把他加到 `.gitignore`,這樣他就不會被 push 上去了 ![image](https://hackmd.io/_uploads/HyGCLOUr1x.png) ## 設定 Electron 1. 安裝 electron ```bash npm install --save-dev electron ``` 2. 在 `src/` 底下創建 `electron/` ,並新增 `main.js` ![image](https://hackmd.io/_uploads/BJKE_u8S1g.png) 3. `main.js`: 控制 electron 的介面,叫他載入 `dist-react/index.html` ```javascript import {app, BrowserWindow} from 'electron'; import path from 'path'; app.on("ready", ()=>{ const mainWindow = new BrowserWindow({}); mainWindow.loadFile(path.join(app.getAppPath(), '/dist-react/index.html')) }) ``` 4. 在 `package.json` 設定主要程式進入點,以及react和electron的執行腳本 ```jsonld { ... "main": "src/electron/main", "homepage": "./", "scripts":{ "dev:react": "vite", "dev:electron":"electron .", ... } } ``` ![image](https://hackmd.io/_uploads/B1vCFdUHkg.png) 5. 到 `vite.config.ts` 中設定路徑 - 加上 相對路徑的符號 `./` ![image](https://hackmd.io/_uploads/Sk1rs_8HJx.png) - 否則build出來會長這樣,這樣會找不到檔案 ![image](https://hackmd.io/_uploads/Hk-5idUr1l.png) 6. 開始跑 electron 應用程式 ```bash npm run dev:electron ``` ![image](https://hackmd.io/_uploads/Skl6nu8ryl.png) ## 設定 TypeScript 1. 刪先看到這三個檔案 - `tsconfig.json`:全局的配置。 - `tsconfig.app.json`:前端的配置(React 项目)。 裡面加上這行表明 這個 TypeScript 專案是一个複合專案,允許引用其他项目 ```jsonld { ... "composite": true, ... } ``` - `tsconfig.node.json`:後端的配置(Node.js 或 Electron)。 裡面加上這行表明 這個 TypeScript 專案是一个複合專案,允許引用其他项目 ```jsonld { ... "composite": true, ... } ``` ![image](https://hackmd.io/_uploads/rJQ8AOUH1l.png) 2. 在全局的 `tsconfig.json` 中指定 包含和不包含設定涵蓋的範圍 ![image](https://hackmd.io/_uploads/rJSSytLByx.png) 3. 在 `electron/` 底下新增 `tsconfig.json`,並把 `main.js` 改名為 `main.ts` ![image](https://hackmd.io/_uploads/H1dcJt8Hyx.png) 4. 在 `electron/tsconfig.json` 中 ```javascript { "compilerOptions": { // require strict types (null-save) "strict": true, // tell TypeScript to generate ESM Syntax "target": "ESNext", // tell TypeScript to require ESM Syntax as input (including .js file imports) "module": "NodeNext", // define where to put generated JS "outDir": "../../dist-electron", // ignore errors from dependencies "skipLibCheck": true } } ``` 5. 在 `package.json` 加入 `electron/tsconfig.json` 編譯 ```jsonld "scripts":{ ..., "transpile:electron": "tsc --project src/electron/tsconfig.json" } ``` 6. 執行 `build`,就會看到build完的東西跑到 `dist-electron/` 底下了 ```bash npm run transpile:electron ``` ![image](https://hackmd.io/_uploads/S1CJ-F8Hyl.png) 7. `package.json` 設定程式進入點為 `electron/main`,因為我們是要跑 electron 而不是 react ```jsonld { ... "main": "dist-electron/main.js", ... } ``` 8. 測試能不能跑 ```bash npm run dev:electron ``` 應該要是依樣長這樣喔 ![image](https://hackmd.io/_uploads/S1XRWF8B1e.png) 9. 最後,記得加到 `.gitignore`,設定TypeScript到這就結束了 ![image](https://hackmd.io/_uploads/By3GGKIBJe.png) ## 設定 electron-builder 1. 安裝 `electron-builder` ```bash npm i --save-dev electron-builder ``` 2. 設定要件成怎樣的 執行檔 - 創建 `electron-builder.json` ![image](https://hackmd.io/_uploads/ryAQ7KISJg.png) - 在 `electron-builder.json` 設定不同平台要創建的執行檔格式,`icon`的部分隨便,沒有設定應該就是預設的 icon ```jsonld { "appId": ".com.lun.ICDApp", "files":["dist-electron", "dist-react"], "icon": "desktopIcon.png", "mac":{ "target":"dmg" }, "linux":{ "target":"AppImage", "category":"Utility" }, "win":{ "target":["portable", "msi"] } } ``` 3. 在 `package.json` 中設定生成執行檔的腳本 ```jsonld { ..., "scripts":{ ..., "dist:mac": "npm run transpile:electron && npm run build && electron-builder --mac --arm64", "dist:win": "npm run transpile:electron && npm run build && electron-builder --win --x64", "dist:linux": "npm run transpile:electron && npm run build && electron-builder --linux --x64", }, ... } ``` 4. 看你用啥 OS,就執行哪個,阿我是 windows ```bash npm run dist:win ``` ![image](https://hackmd.io/_uploads/rk8HOKLSyx.png) 5. 到產生執行檔的路徑 `dist/` ![image](https://hackmd.io/_uploads/BJc2OK8Bkl.png) 6. 長這樣就代表build的功能設定完成了! ![image](https://hackmd.io/_uploads/SJA1YYLrke.png) ## 設定開發模式和生產模式 1. 安裝 `corss-env` ```bash npm i --save-dev cross-env ``` 2. 到 `package.json` 設定辨別現在的模式是 development 在執行 electron ```jsonld { ..., "scripts":{ ..., "dev:electron": "cross-env NODE_ENV=development electron .", }, ... } ``` 3. 上面是OS 知道現在啥情況,但是程式碼並不知道,所以現在要寫一個程式來判斷現在是開發模式還是啥 - 先在 `src/electron/` 底下創建一個 `util.ts` ![image](https://hackmd.io/_uploads/BkrziK8rJe.png) - 判斷函數 `isDev()` ```javascript export function isDev(): boolean { return process.env.NODE_ENV === 'development'; } ``` 4. 在 `vite.config.ts` 設定 react 要跑在哪個 port,`port` 那個就看你自己可以隨便定 ![image](https://hackmd.io/_uploads/HyZnoFLB1x.png) 5. 先測試 react 是不是跑在 port 上 ``` npm run dev:react ``` 水 :laughing: ![image](https://hackmd.io/_uploads/SknVht8ryg.png) 6. 對於 electron 到底要載哪個,介面也要設定,到 `src/electron/main.ts` ```javascript import {app, BrowserWindow} from 'electron'; import path from 'path'; import { isDev } from './util.js'; app.on("ready", ()=>{ const mainWindow = new BrowserWindow({ }); if(isDev()){ // 如果是開發模式 mainWindow.loadURL('http://localhost:5173'); }else{ // 如果是生產模式 mainWindow.loadFile(path.join(app.getAppPath(), '/dist-react/index.html')) } }) ``` 7. 開始測試 要開兩個 terminal,順序沒差,如果沒開react server的話electron就開不了喔 - 一個執行 react 的 server ```bash npm run dev:react ``` - 一個執行 electron 的應用程式 ```bash npm run dev:electron ``` ![image](https://hackmd.io/_uploads/S1FrycUSJx.png) ## 優化開發 為了不用每次都要開兩個 terminal 1. 安裝 `npm-run-all` ```bash npm i npm-run-all ``` 2. `package.json` 修改執行腳本 ```jsonld { ..., "scripts": { "dev": "npm-run-all --parallel dev:react dev:electron", //加這行 "dev:react": "vite", "dev:electron": "npm run transpile:electron && cross-env NODE_ENV=development electron .",//改這行 "build": "tsc -b && vite build", "lint": "eslint .", "preview": "vite preview", "transpile:electron": "tsc --project src/electron/tsconfig.json", "dist:mac": "npm run transpile:electron && npm run build && electron-builder --mac --arm64", "dist:win": "npm run transpile:electron && npm run build && electron-builder --win --x64", "dist:linux": "npm run transpile:electron && npm run build && electron-builder --linux --x64" }, } ``` 3. 這樣之後開發就只要跑一行就行 ```bash npm run dev ``` ![image](https://hackmd.io/_uploads/SJbbMc8BJe.png) 4. `vite` 支持 HMR,所以就一邊改程式,畫面也會跟著變 ![image](https://hackmd.io/_uploads/H1ggf9IBkx.png) 可以開始開發app了!