说明
Electron是一个跨平台创建桌面应用程序的框架,能让我们使用传统前端技术(Nodejs, Javascript, HTML, CSS)开发一个跨平台桌面应用程序。像大家熟知和使用的VsCode编辑器也是基于Electron实现的,在VsCode中点击上方菜单栏中的帮助,点击帮助菜单中的切换开发人员工具,就可以在打开我们熟悉的Chrome devtool。
而在我们平时使用UmiJs等框架来开发React时,会习惯性的使用Webpack等构建工具来辅助开发。因此,这篇文章便是用来记录如何使用Webpack和electron-builder将一个Electron + UmiJs项目打成可执行程序(.exe)。
Electron安装
Electron 应用程序遵循与其他 Node.js 项目相同的结构。 首先创建一个文件夹并初始化 npm 包。
# npm
mkdir my-electron-app && cd my-electron-app
npm install --save-dev electron
# yarn
mkdir my-electron-app && cd my-electron-app
yarn add --dev electron
安装完electron后,可以尝试写一个最简单的electron应用,项目结构如下
my-electron-app
|__src
|__main # 主进程
|__main.js
|__renderer # 渲染进程
|__index.html
|__package.json #
其中package.json部分配置为
"main": "./src/main/main.js",
"scripts": {
"start": "electron ."
},
主进程main.js为
const electron, {app, BrowserWindow } = require('electron')
const Menu = electron.Menu;
function createWindow() {
Menu.setApplicationMenu(null); // 隐藏菜单栏
mainWindow = new BrowserWindow({
height: 960,
width: 1280,
minHeight: 960,
minWidth: 1280,
webPreferences: {
nodeIntegration: true,
},
});
mainWindow.loadFile('./src/renderer/index.html') //渲染进程地址
mainWindow.maximize(); //最大化
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
渲染进程index.html为
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>你好!</title>
</head>
<body>
<h1>你好!</h1>
我们正在使用 Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
和 Electron <span id="electron-version"></span>.
</body>
</html>
npm run start运行,一个最简单的electron应用开发完成。
接着,便可以将我们的渲染进程替换为UmiJs框架,不过主进程main.js中的渲染进程需要修改成
mainWindow.loadURL('http://localhost:8000/#/');
使用webpack打包主进程和渲染进程
安装webpack
yarn add webpack webpack-cli webpack-merge --dev
主进程webpack打包配置
主进程打包时只需要将src/main下的main.js文件打包到dist/main下,对应的webpack配置webpack.main.prod.config.js如下
const path = require('path');
const webpack = require('webpack');
module.exports = {
target: 'electron-main', //指定 webpack 的目标为 Electron 主进程。
entry: {
main: './src/main/main.js', //指定 webpack 入口文件的位置
},
output: {
path: path.resolve(__dirname, '../dist/main'), //指定 webpack 构建输出的位置
filename: '[name].js', //输出文件名模板
},
plugins: [ //webpack 插件的配置项
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(
process.env.NODE_ENV || 'development'
),
}),
],
mode: 'production', //指定 webpack 的构建模式为生产模式
node: {
__dirname: false,
__filename: false,
},
resolve: {
extensions: ['.jsx', '.ts', '.js', '.json'],
},
devtool: 'source-map',
};
渲染进程webpack打包配置
由于渲染进程使用UmiJs框架,webpack配置采用UmiJs框架。但在渲染进程的config.js文件中有一个配置非常重要
chainWebpack(config, { webpack }) {
config.target('electron-renderer');
},
主进程和渲染进程的webpack配置完成后,即可在package.json中加入相应脚本,来执行打包
"scripts": {
"build-main-prod": "cross-env NODE_ENV=production webpack --config ./build/webpack.main.prod.config.js",
"build:renderer": "cross-env APP_ROOT=src/renderer umi build",
"exe": "npm run build:renderer && npm run build-main-prod",
},
到此为止,已经完成了主进程和渲染进程的全部打包配置,使用exe命令并行打包主进程和渲染进程代码
yarn exe
打包完成后,即会在根目录生成dist文件夹。
使用electron-builder构建exe
安装electron-builder
yarn add --save-dev electron-builder
然后在package.json中添加build字段
"build": {
"productName": "CouplingSoftware",
"files": [
"dist/",
"node_modules/",
"package.json"
],
"mac": {
"category": "your.app.category.type"
},
"win": {
"requestedExecutionLevel": "requireAdministrator",
"target": [
"nsis"
]
},
"nsis": {
"oneClick": false,
"perMachine": true,
"allowToChangeInstallationDirectory": true
},
"directories": {
"output": "release"
},
"appId": "com.cn.littlestrong.demo",
"asar": false
},
build字段配置可以参考electron-builder官网(Common Configuration),接着再使用yarn electron-builder --win命令便可以在release目录下看到打包出来的结果。
总结
使用Webpack和electron-builder将Electron项目打包成exe程序,主要在于对主进程和渲染进程配置不同webpack文件。不过因为本次项目渲染进程使用了UmiJs,因此得以偷懒不用详细配置渲染进程的webpack。写这篇文章,也是因为浏览了很多文章提供的功能不符合我项目的需求,所以本文可能对其他项目帮助不大,希望大家能多提出意见。