6 changed files with 426 additions and 11 deletions
@ -0,0 +1,407 @@
@@ -0,0 +1,407 @@
|
||||
--- |
||||
title: "使用Electron+React开发跨平台桌面应用" |
||||
date: 2019-07-29T19:59:59+08:00 |
||||
draft: false |
||||
toc: true |
||||
tags: [electron, react] |
||||
categories: web |
||||
images: ["img/electron.png"] |
||||
--- |
||||
|
||||
使用Electron开发跨平台桌面应用,已经被越来越多的人接受。从开发者的角度,以前需要很多代码才能做到的自动布局、脏区裁剪、图像栅格化、GPU加速,现在通通不用管了,即使要处理,也是几行代码的事;从企业角度,前端开发人员众多,比较容易招聘,另外,资深前端相对于资深C++客户端,薪资还是有差距的,也节省了不少成本。本文主要着重说明使用Electron+React搭建开发环境的步骤。 |
||||
|
||||
<!--more--> |
||||
|
||||
## 技术栈 |
||||
|
||||
- [**Electron**](https://electronjs.org/) |
||||
- [**React - Create React App**](https://github.com/facebook/create-react-app) |
||||
- [**Rescripts**](https://github.com/harrysolovay/rescripts) |
||||
- [**Electron Builder**](https://github.com/electron-userland/electron-builder) |
||||
|
||||
## 开发环境设置 |
||||
|
||||
创建一个新的React项目 |
||||
|
||||
```shell |
||||
npx create-react-app web-designer-test |
||||
cd web-designer-test |
||||
``` |
||||
|
||||
添加依赖库 |
||||
|
||||
```shell |
||||
yarn add electron wait-on concurrently --dev |
||||
yarn add electron-is-dev |
||||
``` |
||||
|
||||
- electron 用于界面开发的核心框架 |
||||
- electron-builder 用于构建安装包 |
||||
- wait-on concurrently 由于electron需要在react启动之后启动,所以增加这两个库用于同步进程启动顺序 |
||||
- electron-is-dev 判断当前运行环境 |
||||
|
||||
创建文件`public/main.js` |
||||
|
||||
```js |
||||
const electron = require('electron'); |
||||
const app = electron.app; |
||||
const BrowserWindow = electron.BrowserWindow; |
||||
|
||||
const path = require('path'); |
||||
const isDev = require('electron-is-dev'); |
||||
|
||||
let mainWindow; |
||||
|
||||
function createWindow() { |
||||
mainWindow = new BrowserWindow({width: 900, height: 680}); |
||||
mainWindow.loadURL(isDev ? 'http://localhost:3000' : `file://${path.join(__dirname, '../build/index.html')}`); |
||||
if (isDev) { |
||||
// Open the DevTools. |
||||
//BrowserWindow.addDevToolsExtension('<location to your react chrome extension>'); |
||||
mainWindow.webContents.openDevTools(); |
||||
} |
||||
mainWindow.on('closed', () => mainWindow = null); |
||||
} |
||||
|
||||
app.on('ready', createWindow); |
||||
|
||||
app.on('window-all-closed', () => { |
||||
if (process.platform !== 'darwin') { |
||||
app.quit(); |
||||
} |
||||
}); |
||||
|
||||
app.on('activate', () => { |
||||
if (mainWindow === null) { |
||||
createWindow(); |
||||
} |
||||
}); |
||||
``` |
||||
|
||||
增加下面的命令到`package.json`文件中的`scripts`标签内 |
||||
|
||||
```js |
||||
"electron-dev": "concurrently \"yarn start\" \"wait-on http://localhost:3000 && electron .\"" |
||||
``` |
||||
|
||||
增加入口文件到`package.json`文件中 |
||||
|
||||
```javascript |
||||
"main": "public/main.js" |
||||
``` |
||||
|
||||
到现在为止,`package.json`文件应该类似于下面这样 |
||||
|
||||
```json |
||||
{ |
||||
"name": "web-designer-test", |
||||
"version": "0.1.0", |
||||
"private": true, |
||||
"dependencies": { |
||||
"electron-is-dev": "^1.1.0", |
||||
"react": "^16.8.7", |
||||
"react-dom": "^16.8.6", |
||||
"react-scripts": "3.0.1" |
||||
}, |
||||
"main": "public/main.js", |
||||
"scripts": { |
||||
"start": "rescripts start", |
||||
"build": "rescripts build", |
||||
"test": "rescripts test", |
||||
"eject": "react-scripts eject", |
||||
"electron-dev": "concurrently \"yarn start\" \"wait-on http://localhost:3000 && electron .\"" |
||||
}, |
||||
"eslintConfig": { |
||||
"extends": "react-app" |
||||
}, |
||||
"browserslist": { |
||||
"production": [ |
||||
">0.2%", |
||||
"not dead", |
||||
"not op_mini all" |
||||
], |
||||
"development": [ |
||||
"last 1 chrome version", |
||||
"last 1 firefox version", |
||||
"last 1 safari version" |
||||
] |
||||
}, |
||||
"devDependencies": { |
||||
"concurrently": "^4.1.1", |
||||
"electron": "^5.0.8", |
||||
"wait-on": "^3.3.0" |
||||
} |
||||
} |
||||
|
||||
``` |
||||
|
||||
为了开发环境下,不启动默认浏览器,需要设置`BROWSER`环境变量,在根目录创建`.env`文件 |
||||
|
||||
```ini |
||||
BROWSER=non |
||||
``` |
||||
|
||||
这个时候可以使用下面命令运行程序 |
||||
|
||||
```shell |
||||
yarn electron-dev |
||||
``` |
||||
|
||||
如果在新的程序窗口内出现了React的欢迎页,则表示一切已经准备OK。但是现在JavaScript的运行环境是浏览器,无法访问宿主机的资源,比如读取文件或注册表,所以需要切换到Node.js环境,使用`electron-renderer`作为[Webpack target](https://webpack.js.org/configuration/target/),我们使用`Rescripts`来处理这个问题。 |
||||
|
||||
安装依赖库 |
||||
|
||||
```shell |
||||
yarn add @rescripts/cli @rescripts/rescript-env --dev |
||||
``` |
||||
|
||||
修改`package.json`文件中`scripts`标签内的启动脚本 |
||||
|
||||
```json |
||||
"start": "react-scripts start", |
||||
"build": "react-scripts build", |
||||
"test": "react-scripts test", |
||||
``` |
||||
|
||||
修改为 |
||||
|
||||
```json |
||||
"start": "rescripts start", |
||||
"build": "rescripts build", |
||||
"test": "rescripts test", |
||||
``` |
||||
|
||||
在根目录新建文件`.rescriptsrc.js` |
||||
|
||||
```javascript |
||||
module.exports = [require.resolve('./.webpack.config.js')] |
||||
``` |
||||
|
||||
最后,在根目录新建另一个文件`.webpack.config.js` |
||||
|
||||
```javascript |
||||
// define child rescript |
||||
module.exports = config => { |
||||
config.target = 'electron-renderer'; |
||||
return config; |
||||
} |
||||
``` |
||||
|
||||
现在就切换到了Node.js运行环境,可以随意访问主机资源了。 |
||||
|
||||
## 打包环境设置 |
||||
|
||||
首先,要添加依赖库 |
||||
|
||||
```shell |
||||
yarn add electron-builder --dev |
||||
``` |
||||
|
||||
CRA(**C**reate **R**eactive **A**pplication)默认创建的`index.html`,会使用绝对路径来访问资源,在Electron中会加载资源失败,所以需要修改配置,在`package.json`中增加`homepage`属性 |
||||
|
||||
```json |
||||
"homepage": "./", |
||||
``` |
||||
|
||||
接下来添加打包命令,在`package.json`中的`scripts`标签中 |
||||
|
||||
```json |
||||
"postinstall": "electron-builder install-app-deps", |
||||
"preelectron-pack": "yarn build", |
||||
"electron-pack": "electron-builder -mw" |
||||
``` |
||||
|
||||
- `"postinstall": "electron-builder install-app-deps"`用于确保本地依赖库都已经安装 |
||||
- `"preelectron-pack": "yarn build"`会保证在打包前构建应用 |
||||
- `"electron-pack": "electron-builder -mw"`会为Mac(m)和Windows(w)平台进行App打包 |
||||
|
||||
在执行打包命令前,还需要设置打包参数,在`package.json`中添加如下信息 |
||||
|
||||
```json |
||||
"author": { |
||||
"name": "lniwn", |
||||
"email": "[email protected]", |
||||
"url": "https://oaoa.me" |
||||
}, |
||||
"build": { |
||||
"appId": "me.oaoa.web-designer-test", |
||||
"productName": "WebDesignerTest", |
||||
"copyright": "Copyright © 2019 ${author}", |
||||
"mac": { |
||||
"category": "public.productivity.utilities" |
||||
}, |
||||
"win": { |
||||
"icon": "assets/icon.png", |
||||
"target": "nsis" |
||||
}, |
||||
"nsis": { |
||||
"allowToChangeInstallationDirectory": true, |
||||
"allowElevation": false, |
||||
"createDesktopShortcut": true, |
||||
"menuCategory": true, |
||||
"oneClick": false |
||||
}, |
||||
"files": [ |
||||
"build/**/*", |
||||
"node_modules/**/*" |
||||
], |
||||
"directories": { |
||||
"buildResources": "assets" |
||||
} |
||||
} |
||||
``` |
||||
|
||||
可以在[这里](https://www.electron.build/configuration/configuration)查看Electron Builder的所有选项。 |
||||
|
||||
创建一个assets文件夹,用于存放图片资源。 |
||||
|
||||
最好在一个平台只构建当前平台的可执行程序,这里针对Windows平台的构建进行了详细设置。 |
||||
|
||||
最终,package.json文件内容如下: |
||||
|
||||
```json |
||||
{ |
||||
"name": "web-designer-test", |
||||
"version": "0.1.0", |
||||
"private": true, |
||||
"dependencies": { |
||||
"electron-is-dev": "^1.1.0", |
||||
"react": "^16.8.6", |
||||
"react-dom": "^16.8.6", |
||||
"react-scripts": "3.0.1" |
||||
}, |
||||
"main": "public/main.js", |
||||
"homepage": "./", |
||||
"description": "Web页面设计器", |
||||
"scripts": { |
||||
"start": "rescripts start", |
||||
"build": "rescripts build", |
||||
"test": "rescripts test", |
||||
"eject": "react-scripts eject", |
||||
"electron-dev": "concurrently \"yarn start\" \"wait-on http://localhost:3000 && electron .\"", |
||||
"postinstall": "electron-builder install-app-deps", |
||||
"preelectron-pack": "yarn build", |
||||
"electron-pack": "electron-builder -mw", |
||||
"electron-pack-win": "electron-builder -c.extraMetadata.main=build/main.js --win --x64" |
||||
}, |
||||
"eslintConfig": { |
||||
"extends": "react-app" |
||||
}, |
||||
"browserslist": { |
||||
"production": [ |
||||
">0.2%", |
||||
"not dead", |
||||
"not op_mini all" |
||||
], |
||||
"development": [ |
||||
"last 1 chrome version", |
||||
"last 1 firefox version", |
||||
"last 1 safari version" |
||||
] |
||||
}, |
||||
"devDependencies": { |
||||
"@rescripts/cli": "^0.0.11", |
||||
"@rescripts/rescript-env": "^0.0.10", |
||||
"concurrently": "^4.1.1", |
||||
"electron": "^5.0.8", |
||||
"electron-builder": "^21.1.5", |
||||
"wait-on": "^3.3.0" |
||||
}, |
||||
"author": { |
||||
"name": "lniwn", |
||||
"email": "[email protected]", |
||||
"url": "https://oaoa.me" |
||||
}, |
||||
"build": { |
||||
"appId": "me.oaoa.web-designer-test", |
||||
"productName": "WebDesignerTest", |
||||
"copyright": "Copyright © 2019 ${author}", |
||||
"mac": { |
||||
"category": "public.productivity.utilities" |
||||
}, |
||||
"win": { |
||||
"icon": "assets/icon.png", |
||||
"target": "nsis" |
||||
}, |
||||
"nsis": { |
||||
"allowToChangeInstallationDirectory": true, |
||||
"allowElevation": false, |
||||
"createDesktopShortcut": true, |
||||
"menuCategory": true, |
||||
"oneClick": false |
||||
}, |
||||
"files": [ |
||||
"build/**/*", |
||||
"node_modules/**/*" |
||||
], |
||||
"directories": { |
||||
"buildResources": "assets" |
||||
} |
||||
} |
||||
} |
||||
|
||||
``` |
||||
|
||||
由于Electron默认入口文件为`build/Electron.js`,如果想自定义,需要在参数中指定入口文件,否则编译会报错 |
||||
|
||||
`"electron-pack-win": "electron-builder -c.extraMetadata.main=build/main.js --win --x64"` |
||||
|
||||
最后,执行打包命令 |
||||
|
||||
```shell |
||||
yarn electron-pack-win |
||||
``` |
||||
|
||||
会在dist文件夹下生成对应安装包 |
||||
|
||||
文件夹结构如下: |
||||
|
||||
```txt |
||||
F:\Project\electron\web-designer-test |
||||
├.env |
||||
├.gitignore |
||||
├.rescriptsrc.js |
||||
├.webpack.config.js |
||||
├assets |
||||
│ ├icon.png |
||||
├build |
||||
│ ├asset-manifest.json |
||||
│ ├favicon.ico |
||||
│ ├index.html |
||||
│ ├main.js |
||||
│ ├manifest.json |
||||
│ ├precache-manifest.3ef21b1d6090801b808aaff5b52f1a17.js |
||||
│ ├service-worker.js |
||||
│ ├static |
||||
├dist |
||||
│ ├.icon-ico |
||||
│ ├builder-effective-config.yaml |
||||
│ ├WebDesignerTest Setup 0.1.0.exe |
||||
│ ├WebDesignerTest Setup 0.1.0.exe.blockmap |
||||
│ ├win-unpacked |
||||
├node_modules |
||||
├package.json |
||||
├public |
||||
│ ├favicon.ico |
||||
│ ├index.html |
||||
│ ├main.js |
||||
│ ├manifest.json |
||||
├README.md |
||||
├src |
||||
│ ├App.css |
||||
│ ├App.js |
||||
│ ├App.test.js |
||||
│ ├index.css |
||||
│ ├index.js |
||||
│ ├logo.svg |
||||
│ ├serviceWorker.js |
||||
├yarn.lock |
||||
|
||||
``` |
||||
|
||||
|
||||
|
||||
*参考文档* |
||||
|
||||
- https://www.codementor.io/randyfindley/how-to-build-an-electron-app-using-create-react-app-and-electron-builder-ss1k0sfer |
||||
- https://juejin.im/post/5c356a396fb9a049e30848f0 |
||||
Loading…
Reference in new issue