乐趣区

Electron + Antd + Mobx 环境搭建

最近要重构一版桌面管理软件。业务需求与 WEB 版基本一致,但需要用到断点续传等本地功能。最经济的办法当然是移植到 Electron 环境中。
之前的应用框架主要用到了以下 React 套餐:

React
React-Router 路由
Mobx 数据管理
AntDesign 界面组件

经过一天时间的摸索大致找到了门路,构建完成后写了一个脚手架,欢迎下载。
下面回顾一下本次环境搭建的过程。
安装 AntDesign 的脚手架
关于 Antd 在 CRA 框架下的使用,官网有一份很详细的操作说明(包括 babel-import 等的设置),初学者可以跟着一步一步学习。如果你赶时间,也可以直接用它的脚手架。
$ git clone https://github.com/ant-design/create-react-app-antd.git my-project
$ cd my-project
$ npm install && npm start
跑起来以后,会自动弹出一个页面 localhost:3000,网页上显示的就是最基础的包括了 antd 的 demo 示例。
安装 Electron 及配置
关于 electron 的介绍,可以看官网文档,本文不涉及。完成 antd 脚手架安装后,在工程目录下安装 electron。
$ npm install electron –save-dev
安装完成以后,在根目录下需要做一些设置,包括:

electron 启动脚本
npm 启动及编译命令
render 端使用 electron 模块的设置

electron 启动脚本
在根目录下新建 main.js,写入以下内容。(其实与官方例子是一样的)
// Modules to control application life and create native browser window
const {app, BrowserWindow} = require(‘electron’)

// Keep a global reference of the window object, if you don’t, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({width: 800, height: 600})

// and load the index.html of the app.
mainWindow.loadFile(‘build/index.html’)

// Open the DevTools.
// mainWindow.webContents.openDevTools()

// Emitted when the window is closed.
mainWindow.on(‘closed’, function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on(‘ready’, createWindow)

// Quit when all windows are closed.
app.on(‘window-all-closed’, function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== ‘darwin’) {
app.quit()
}
})

app.on(‘activate’, function () {
// On macOS it’s common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
npm 启动及编译命令
在工程根目录的 package.json 中加入以下内容:
{

“main”: “main.js”,
“homepage”: “.”,
“scripts”: {
“electron-dev”: “electron . –env dev”,
“electron-build”: “npm run build && electron . –env build”,
“start”: “react-app-rewired start”,

}
}
我们希望在执行 npm run electron-dev 时,能打开 electron 应用并展示 antd 的网页内容,那么需要修改 main.js:

// and load the index.html of the app.
// mainWindow.loadFile(‘index.html’) // 这个是原内容,修改为以下内容
if (argv && argv[1] === ‘dev’) {// 如果 npm run electron-dev,加载本地网页
mainWindow.loadURL(‘http://localhost:3000/’)
}
else if (argv && argv[1] === ‘build’) {
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, ‘./build/index.html’),
protocol: ‘file:’,
slashes: true
}))
}

配置到这里后,打开两个终端,分别 cd 到项目根目录下。
$ npm start // 终端 1
$ npm run electron-dev // 终端 2
electron 界面应该就会展示出来,界面中显示的就是 antd 的 demo 内容。
render 端使用 electron 模块
经过以上设置,界面内容已经可以正常展示并可以实时刷新,但还缺少了一个重要功能:electron 模块,用以支持本地化操作。
配置的基本思路是,在 electron 启动过程中在 window 对象中设置 webPreferences 的 preload 属性 [文档],将 electron 模块注册为 global 对象供 renderer 侧使用。

// Create the browser window.
// mainWindow = new BrowserWindow({width: 800, height: 600})
mainWindow = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
fullscreenable: false,
webPreferences: {
javascript: true,
plugins: true,
nodeIntegration: false, // 不集成 Nodejs
webSecurity: false,
preload: path.join(__dirname, ‘./public/renderer.js’) // public 目录下的 renderer.js
}
})

设置成功后,在 renderer 侧即可引入 electron 的 remote 模块。
// 新建 renderer.js,public 目录下
const process = require(‘process’);

process.once(‘loaded’, () => {
global.electron = require(‘electron’)
});
使用 mobx
安装 mobx 及 mobx-react
$ npm install mobx mobx-react –save
安装成功后,在 App.js 中使用:

import {observer} from ‘mobx-react’;

@observer
class App extends React.Component {

}
执行开发命令后,会发现出现了一个编译错误。原因就在于 CRA 团队并不倾向于支持所有未正式发布的 javascript 语言特性,目前要使用装饰圈,均需要使用 babel 等进行转译。这个问题目前有两个方法:使用 eject 方式或 react-app-rewire-mobx 模块。
使用 eject 方式将会暴露出所有的 webpack 配置,开发者如果熟悉可以进行自定义的配置。当然,这样做的话 create-react-app 的意义就大打折扣了。
使用 react-app-rewire-mobx 则相对方便了许多,只需安装该模块,并在 config-overrides.js 中加入,即可正常使用。

const rewireMobX = require(‘react-app-rewire-mobx’);

module.exports = function override(config, env) {

config = rewireMobX(config, env);
return config;
}
注意
按照上面的方式配置以后,仍然会报错。
./src/index.js Error: The ‘decorators’ plugin requires a’decoratorsBeforeExport’ option, whose value must be a boolean. If youare migrating from Babylon/Babel 6 or want to use the old decoratorsproposal, you should use the ‘decorators-legacy’ plugin instead of’decorators’.
原因在于,新版的 babel7.0 的描述换了一种方式。应该将上面的配置改为:
module.exports = function override(config, env) {

config = injectBabelPlugin([“@babel/plugin-proposal-decorators”, { legacy: true}], config);
return config;
}
其实在 react-app-rewire-mobx 中也仅仅就是就是导入这个修饰符,只不过是旧版的写法。但就因为没有跟随 babel7.0 更新,所以导致了这个
// react-app-rewire-mobx/index.js
const {injectBabelPlugin} = require(‘react-app-rewired’);

function rewireMobX(config, env) {
return injectBabelPlugin(‘transform-decorators-legacy’, config);
}

module.exports = rewireMobX;

退出移动版