写在前面
Electron支持我们使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序。也就是说,前端工程师也可以利用自己熟悉的技术栈,开发桌面应用。著名的VS Code 是基于 Electron 进行开发的。本文将简单介绍一些利用Electron开发一个文件上传小工具的实践。
搭建开发环境
Electron 基于 Node.js(作为后端运行时)和 Chromium(作为前端渲染)。搭建开发环境比较简单,保证本地有Node环境即可。然后依次执行以下命令:
# 初始化项目$ npm init# 安装electron$ npm install --save-dev electron
修改package.json
文件:
{ "name": "cdn-uploader", "version": "1.0.0", "main": "main.js", "scripts": { "start": "electron .", // 启动electron运行时 }}
接下来,新建一个简单的main.js
const { app, BrowserWindow, ipcMain } = 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 win function createWindow() { // 创建浏览器窗口。 win = new BrowserWindow({ width: 800, height: 800 }); // 并且为你的应用加载index.html win.loadFile('index.html'); // 当 window 被关闭,这个事件会被触发。 win.on('closed', () => { // 取消引用 window 对象,如果你的应用支持多窗口的话, // 通常会把多个 window 对象存放在一个数组里面, // 与此同时,你应该删除相应的元素。 win = null });} // Electron 会在初始化后并准备// 创建浏览器窗口时,调用这个函数。// 部分 API 在 ready 事件触发后才能使用。app.on('ready', createWindow); // 当全部窗口关闭时退出。app.on('window-all-closed', () => { // 在 macOS 上,除非用户用 Cmd + Q 确定地退出, // 否则绝大部分应用及其菜单栏会保持激活。 if (process.platform !== 'darwin') { app.quit(); }}) app.on('activate', () => { // 在macOS上,当单击dock图标并且没有其他窗口打开时, // 通常在应用程序中重新创建一个窗口。 if (win === null) { createWindow(); }}) // 在这个文件中,你可以续写应用剩下主进程代码。这里的主进程,就是Node进程.
接下来,我们只需要新建一个简单index.html
就可以了。
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>cdn-uploader</title> <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" /> </head> <body> <h1>Hello World!</h1> </body></html>
在命令行执行npm start
,即可启动一个Electron应用了。
开发前端页面
Electron的GUI界面,其实就是一个网页。我们可以按照正常开发网页的方式,来开发界面。只需要将main.js
中的地址改为你本地启的前端页面地址即可,如:
win.loadURL('http://localhost:8003');
和传统的前端页面开发不同的是,我们的网页不是运行在浏览器内,而是运行在Electron中。
这里,我选择了react和ant-design来开发前端页面。
前后端通信
Electron后端是使用Node.js作为运行时的。我们可以直接通过Electron的Node.js运行时,提供后台服务。
在本文所介绍的示例中,由于没有http的文件直传接口,因此我是在Node端完成的文件上传服务。
// 前端向后台Node进程发送消息:const { ipcRenderer } = require('electron');ipcRenderer.send('uploadFile', { payload: {...}}); // 前端监听后台Node进程发过来的消息:ipcRenderer.on('uploadFileSuccess', (event, arg) => { const { msg,code } = arg; console.log('上传成功', msg); ...}); // 后台Node进程(main.js)接收前端的消息:const { ipcMain } = require('electron');ipcMain.on('uploadFile', (event, arg) => { const { payload } = arg; ... // 后台Node进程通知前端上传成功 event.sender.send('uploadFileSuccess', { msg: 'ok', code: 0 });});
项目打包
当开发完成,需要打包时,首先,我们按照正常网页开发一样,完成前端代码的打包。然后,修改主进程main.js的代码:
win.loadURL(url.format({ pathname: path.join(__dirname, './dist/h5/index.html'), // 前端代码打包产出的html地址 protocol: 'file:', slashes: true}));
当然,我们可以直接增加环境变量,避免开发和打包时,反复修改代码。
// main.jsif (process.env.NODE_ENV === 'dev') { win.loadURL('http://localhost:8003'); win.webContents.openDevTools();} else { win.loadURL(url.format({ pathname: path.join(__dirname, './dist/h5/index.html'), protocol: 'file:', slashes: true }));} // package.json{ "name": "cdn-uploader", "version": "1.0.0", "main": "main.js", "scripts": { "start": "cross-env NODE_ENV=dev electron ." // 加上环境变量 }}
有一点需要注意的是,在前端页面打包配置中(以webpack为例),需要指定
target: 'electron-renderer'
最后,使用命令行工具electron-packager,就可以产出桌面应用了。
// package.json{ "name": "cdn-uploader", "version": "1.0.0", "main": "main.js", "scripts": { "start": "cross-env NODE_ENV=dev electron .", // 加上环境变量 "make": "electron-packager ./ cdn-uploader --out ./outApp --overwrite --progress" // 产出桌面应用 }}
更多细节
想要了解更多,可以直接参考Electron的官方文档:
https://www.electronjs.org/docs
写在后面
本文简单介绍了开发一个Electron应用的流程。偶尔开发一些Electron小工具,提高工作生产效率,是一个不错的选择,符合预期。