Dva.js框架整合Electron实践(加载本地文件)

Published: 2018-07-27

Tags: Electron

本文总阅读量

开发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 with 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 buildcross-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,这个包的作用是同时运行起devrun-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框架里开发的事情了

参考:

  1. 能否支持watch模式工作?

  2. 使用externals 并不能过滤moment 等个别模块,依然会被打包进来,整个项目打包的文件特别大

  3. roadhog-extra

  4. 介绍 roadhog —— 让 create-react-app 可配的命令行工具

  5. How to import the electron ipcRenderer in a react / webpack 2 setup