手记

使用Electron开发一个文件上传小工具实践

ID: 符合预期的CoyPan
CoyPan,BAT某厂符合预期的FE,正努力成为一名出色的工程师

写在前面

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.js
if (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的官方文档:

写在后面

本文简单介绍了开发一个Electron应用的流程。偶尔开发一些Electron小工具,提高工作生产效率,是一个不错的选择,符合预期。

1人推荐
随时随地看视频
慕课网APP