Electron 應用如何利用 create-react-app 從 0 到 1

與我常在Jerry發表於2018-09-03

Electron 的官方文件給我一種錯綜複雜的感覺,而官方給的 starter 又過於簡單,所以如何引入 React 並實現完善的打包機制對於萌新來說也是非常困難的 ?,所以本人根據自己踩過的坑,綜合下來,寫了本教程,希望看過後大家都能有所收穫。

適用人群

此教程適用於瞭解 React,想要學習 Electron,但是不知如何將 React 新增至 Electron 中的同學。

文章結構

一、基於 React 初始化專案

1. 初始化

首先利用 facebook 官方的create-react-app建立一個基礎專案。你可以根據你平時喜歡的包管理工具安裝:

# npx
npx create-react-app react-electron-demo

# npm
npm init react-app react-electron-demo

# yarn
yarn create react-app react-electron-demo
複製程式碼

安裝完成後,專案的目錄如下:

react-electron-demo
├── README.md
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
├── src
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── index.css
│   ├── index.js
│   ├── logo.svg
│   └── registerServiceWorker.js
└── yarn.lock
複製程式碼

2. 刪除 ServiceWorker 和 manifest.json

因為Electron打包後讀取的頁面為本地靜態資源,所以不需要ServiceWorkermanifest.json,這兩個東西的作用可以自行 google。具體操作如下:

  • 刪除public/manifest.json檔案。

  • 刪除public/index.html檔案的以下程式碼:

/* public/index.html:11行 */
- <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
複製程式碼
  • 刪除src/registerServiceWorker.js
  • 刪除src/index.js的以下內容:
/* src/index.js:5行和7行 */
- import registerServiceWorker from './registerServiceWorker';

- registerServiceWorker();
複製程式碼

3.使用react-app-rewired

通過使用react-app-rewired,我們可以在不eject專案的情況下,自定義 webpack 配置等。

  • (1) 安裝
# npm
npm install react-app-rewired --save-dev
# yarn
yarn add -D react-app-rewired
複製程式碼
  • (2) 根目錄下建立config-overrides.js檔案,檔案內容如下:
module.exports = function override(config, env) {
  //do stuff with the webpack config...
  return config;
};
複製程式碼
  • (3) 更改package.json配置,變化如下:
  /* package.json */

  "scripts": {
-   "start": "react-scripts start",
+   "start": "react-app-rewired start",
-   "build": "react-scripts build",
+   "build": "react-app-rewired build",
-   "test": "react-scripts test --env=jsdom",
+   "test": "react-app-rewired test --env=jsdom"
}
複製程式碼
  • (4) 啟動專案、打包
# 執行dev
npm run start
# 打包
npm run build
複製程式碼

二、新增Electron

1.新增Electron入口檔案

  • (1) 新建app/index.js,檔案內容如下:
const { app, BrowserWindow } = require('electron');

let win;

function createWindow() {
  // 建立瀏覽器視窗。
  win = new BrowserWindow({ width: 800, height: 600 });

  // 然後載入應用的 index.html。
  win.loadURL('http://localhost:3000');

  // 當 window 被關閉,這個事件會被觸發。
  win.on('closed', () => {
    win = null;
  });
}

app.on('ready', createWindow);

// 當全部視窗關閉時退出。
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  if (win === null) {
    createWindow();
  }
});
複製程式碼
  • (2) 在package.json中新增"main": "app/index.js",表示Electron應用的入口路徑。

  • (3) 新增Electron啟動命令,並安裝Electron依賴。

npm install --save-dev electron
複製程式碼
/* package.json */
"scripts": {
+ "start:electron": "electron app"
}
複製程式碼
  • (4) 輸入npm run start:electron,一個開發環境下的Electron應用就啟動了。

2.優化 Electron 啟動

現在如果要啟動開發模式,需要啟動兩個命令,即npm run startnpm run start:electron,那如何才能一個命令就啟動呢?

  • 我們需要使用到concurrently來同時執行兩個命令
  • 如果要讓react-app-rewired start執行時,不開啟瀏覽器,需要傳入BROWSER=none,所以也需要安裝cross-env做傳值相容。
  • 因為同時執行時,Electron開啟時,伺服器還沒執行好,所以需要使用wait-on
npm install --save-dev concurrently cross-env wait-on
複製程式碼

新增package.json中的啟動命令。

/* package.json */

"script": {
-   "start": "react-app-rewired start",
+   "start": "concurrently \"npm run start:react\" \"npm run start:electron\"",
+   "start:react": "cross-env BROWSER=none react-app-rewired start",
-   "start:electron": "electron app",
+   "start:electron": "wait-on http://localhost:3000 && electron app",
}
複製程式碼

通過npm run start

3.新增除錯工具

除錯工具大致需要 Electron 和 React 除錯兩種。

新增如下程式碼,新增 React 相關的Chrome外掛,並安裝Devtron,用於除錯 Electron 程式通訊等;新增electron-is-dev,用於識別當前 Electron 是開發環境還是打包環境。

  • 安裝需要使用的依賴。
npm install --save-dev electron-devtools-installer \
electron-debug \
devtron \

npm install --save electron-is-dev
複製程式碼
  • 在程式碼中新增開發工具。
/* app/index.js */
const isDev = require('electron-is-dev');

// 利用electron-debug,新增和Chrome類似的快捷鍵
isDev && require('electron-debug')({ enabled: true, showDevTools: false });
// 用於新增Chromium外掛
function createDevTools() {
  const {
    default: installExtension,
    REACT_DEVELOPER_TOOLS,
    REDUX_DEVTOOLS,
  } = require('electron-devtools-installer');
  // 安裝devtron
  const devtronExtension = require('devtron');
  devtronExtension.install();
  // 安裝React開發者工具
  installExtension(REACT_DEVELOPER_TOOLS);
  installExtension(REDUX_DEVTOOLS);
}

// 修改應用啟動事件
app.on('ready', () => {
  createWindow();
  // 只在開發環境載入開發者工具
  isDev && createDevTools();
});
複製程式碼

安裝完畢後,執行npm run start,通過Command + Option + I(WindowsF12)就可以啟動開發者工具,然後在擴充套件中就可以檢視到ReactRedux的開發者工具了。

現在基本的開發配置已經搭好,接下來讓我們看一下如何配置打包功能。

三、打包

1.安裝依賴

  • 打包時,我們需要先安裝依賴,我們使用的是electron-builder進行打包,執行以下命令進行安裝。
npm install --save-dev electron-builder
複製程式碼

2.打包流程及配置

  • 打包的基本流程為:
    • 打包 Reactbuild 目錄下
    • 拷貝 Electron 程式碼至 build 目錄下
    • 使用 electron-builder 進行打包

根據以上流程,新增對應的打包命令。

/* package.json */
{
  "scripts": {
-    "build": "react-app-rewired build",
+    "build": "npm run build:copy && npm run pack",
+    "build:react": "react-app-rewired build",
+    "build:copy": "npm run build:react && npm run copy:electron",
+    "pack": "electron-builder",
+    "copy:electron": "cp -r ./app/. ./build"
  }
}
複製程式碼

因為 Electron 是訪問本地的檔案,所以需要將 Webpack 的 output.publicPath 設定為 ./。需要做以下修改:

/* config-overrides.js */
module.exports = function override(config, env) {
  //do stuff with the webpack config...
+  if (env === "production") {
+    config.output.publicPath = './';
+  }
  return config;
};
複製程式碼

在根目錄下建立icons資料夾,用於存放應用logo,我在網上找了一個,也就是資料夾內的icon.pngicon.icns。然後在package.json中新增一些配置資訊。

{
  "build": {
    "productName": "Electron-React-Test",
    "extends": null,
    "files": ["build/**/*"],
    "mac": {
      "icon": "icons/icon.icns"
    },
    "win": {
      "target": "nsis",
      "icon": "icons/icon.png"
    },
    "linux": {
      "target": ["AppImage", "deb"],
      "icon": "icons/icon.png"
    },
    "extraMetadata": {
      "main": "build/index.js"
    },
    "directories": {
      "buildResources": "assets"
    }
  }
}
複製程式碼

3.修改 Electron 入口檔案

  • 新增打包環境下,訪問的URL地址。
const isDev = require('electron-is-dev');
const path = require('path');

const devUrl = 'http://localhost:3000';
// 本地檔案路徑定位到打包的react檔案
const localUrl = `file://${path.resolve(
  __dirname,
  '../../app.asar/build'
)}/index.html`;
const appUrl = isDev ? devUrl : localUrl;

function createWindow() {
  win = new BrowserWindow({ width: 800, height: 600 });

  // 然後載入應用的地址
  win.loadURL(appUrl);

  win.on('closed', () => {
    win = null;
  });
}
複製程式碼

4.新增 Windows 系統打包配置

如果需要增加Windows系統的打包檔案,需要在package.json中加入以下程式碼:

/* package.json */
{
  "scripts": {
+   "build:win": "npm run build:react-copy && npm run pack:win",
+   "pack:win": "electron-builder --win",
  }
}
複製程式碼

然後執行npm run build:win即可。

結語

經過以上步驟,我們已經得到了一個可以打包的基礎專案。原始碼詳見react-electron-demo專案。

相關文章