开发Electron小应用时,一般先下载个官方示例,然后开始写HTML/CSS/JS,但是往往应用都不会是一个展示用的小页面,稍微大一点的应用,是需要拆分组件,需要用到路由,交互数据流较多,于是需要使用React、Vue等前端框架来开发,使用前端脚手架,写好代码逻辑,打包,把dist文件往Electron项目相应路径一放,打包就做出一个桌面应用了。
以上,看起来是个不错的流程,实际开发过程中会遇到一个问题
比如页面与主进程通信,页面需要引入electron,但是如果使用electron下的写法,那么浏览器打开就会报错,更别提打包发布
丑陋且有效的折中办法是前端框架打包出来后,手动添加一些用到的方法到index.html中,比如
<script>
const ipc = require('electron').ipcRenderer;
const drag = require('electron-drag');
let clear = drag('#header');
</script>
这样开发就很不方便,如果Electron的壳功能很多,页面与壳的功能由两个人开发,那么在通信等联调时就需要频繁的打包发布,很不方便
那可不可以将他们整合起来,开发的时候直接启动Electron框架,加载资源,并且页面变更自动刷新页面呢?
当然可以,本文接下来从Dva框架着手,将Electron整合到Dva,实现这个需求。
Demo:https://github.com/sincerefly/simple-dva-electron
(一)安装Dva.js框架
yarn global add dva-cli
dva new simple-dva-electron
Dva文档见:https://dvajs.com/
(二)Electron加载本地资源
可以安装一下Electron的示例,这样方便复制代码
# 克隆示例项目的仓库
$ git clone https://github.com/electron/electron-quick-start
# 进入这个仓库
$ cd electron-quick-start
# 安装依赖并运行
$ npm install && npm start
修改package.json配置文件,添加一些Electron需要的信息
"name": "simple-dva-electron",
"version": "1.0.0",
"description": "A minimal Electron application",
"main": "main_process.js",
main这里的作用是指定electron的入口文件,使用"electron ."命令时会根据main字段寻找入口
main_process.js文件直接用electron示例里的main.js就可
等等,main.js中窗口加载什么呢
因为dva安装好后,使用yarn start
启动就直接打开浏览器http://127.0.0.1:8000
端口了,所以很自然的想到在Electron中使用mainWindow.loadURL('http://127.0.0.1:8000/')
来加载网页,网上很多的示例也都是这样做的,但是这种方式有个问题,因为走的是HTTP,一些本地资源加载会触发安全机制无法实现,加载本地的index.html文件就没有安全的限制
可以这样做,使用mainWindow.loadFile('dist/index.html')
来加载打包好后的文件,修改打包命令roadhog build
为cross-env COMPRESS=none roadhog build --watch
,重点在--watch
参数,它使得roadhog监听文件变化,自动打包文件输出到dist目录,设置COMPRESS
不进行压缩,减少打包时间
那么之后需要做的就是electron自动刷新了,当文件变化,自动刷新页面,这个可以使用electron-reload
包
并在main_process.js中引入
require('electron-reload')(__dirname);
整理一下,package.json中的script命令如下:
"scripts": {
"dev": "cross-env COMPRESS=none roadhog build --watch",
"bundle": "roadhog build",
"run-electron": "electron .",
"start": "npm-run-all --parallel dev run-electron"
...
}
start命令中的npm-run-all
,这个包的作用是同时运行起dev
与run-electron
使用yarn start
启动项目,页面应该就展示出来了(第一次需要手动刷新一下页面,使用Ctrl + Shift + I
打开Chrome控制台,点击一下控制台,F5刷新)
(三)在渲染进程加载electron包
接下来在页面上使用ipcRenderer
来确认确实是整合到了一起,可以正常开发使用了
在src/routes/IndexPage.js
内添加
import { ipcRenderer } from 'electron';
再次运行,页面空白,打开控制台看到如下输出:
Uncaught TypeError: fs.existsSync is not a function
at Object.<anonymous> (index.js:115728)
at Object.sFIW (index.js:115734)
at __webpack_require__ (index.js:20)
at Object.cHtD (index.js:95802)
at __webpack_require__ (index.js:20)
at Object.lVK7 (index.js:104719)
at __webpack_require__ (index.js:20)
at index.js:63
at index.js:66
这个是因为roadhog默认配置没有添加electron支持,还解析不了electron的包
两种解决办法
第一种,不使用import方式导入,替换为
const electron = window.require('electron')
const ipcRenderer = electron.ipcRenderer;
如果我就是想使用import方式导入electron呢?那看一下第二种方式
因为roadhog默认没有加载使用electron的扩展,但是我不太熟悉roadhog配置的编写,新建一个webpack.config.js
文件,内容为:
const webpack = require("webpack");
module.exports = function (webpackConfig, env) {
webpackConfig.plugins.push(new webpack.ExternalsPlugin('commonjs', ['electron']))
return webpackConfig
}
roadhog默认会读取webpack.config.js
配置文件并应用,但是roadhog并不推荐这种做法,可能是怕roadhog的配置与webpack.config.js
里的配置冲突,不过这一小段用来添加electron支持倒是不会有什么问题
退出并重新运行,再次使用import的方式导入electron就不会报错了。
在页面设置个按钮,点击给主进程发送一条消息,主页面接收消息后退出,没有问题。困扰了又一阵的框架整合算是解决了,页面变更Electron窗体自动刷新,Demo在上边的Github连接,接下来就是在Dva框架里开发的事情了
参考: