使用Webpack/React去打包构建Electron应用

本文详细介绍了如何使用Webpack和React构建Electron应用,涵盖了从Electron的介绍、安装、项目结构,到主进程和渲染进程的Webpack打包配置,以及Electron-builder的应用、C++模块支持、Redux与React-Router集成和Devtron辅助开发工具的集成。通过实例展示了从创建到调试的完整流程,旨在帮助开发者理解前端构建工具在Electron开发中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

Electron是一个跨平台创建桌面应用程序的框架,允许我们使用HTML/CSS/JS去创建跨平台桌面应用程序。随着大前端的发展,当我们去开发Web UI时,会习惯性的使用Webpack等构建工具以及React等钱的MVVM框架去辅助开发。在开发Electron时也是同理,因此本文将介绍如何使用Webpack/React去打包构建整个Electron应用,并使用Electron-builder构建出App。其实社区提供了很多Electron Webpack的脚手架和模版,比如electron-forgeelectron-react-boilerplate等等,但通过自己的摸索和构建(重复造轮子),能对前端打包构建体系有个更深刻的理解。

目录

  1. Electron简介
  2. Electron安装
  3. 结构设计
  4. 使用webpack打包主进程和渲染进程
  5. 使用electron-builder构建应用
  6. C++模块支持
  7. Redux + React-router集成
  8. Devtron辅助开发工具集成
  9. 总结
  10. 参考

Electron简介

Electron是使用Web前端技术(HTML/CSS/JavaScript/React等)来创建原生跨平台桌面应用程序的框架,它可以认为是Chromium、Node.js、Native APIs的组合。

Chromium由Google开源,相当于Chrome浏览器的精简版,在Electron中负责Web UI的渲染。Chromium可以让开发者在不考虑浏览器兼容性的情况下去编写Web UI代码。

Node.js是一个 JavaScript 运行时,基于事件驱动、非阻塞I/O 模型而得以轻量和高效。在Electron中负责调用系统底层API来操作原生GUI以及主线程JavaScript代码的执行,并且 Node.js中常用的utils、fs等模块在 Electron 中也可以直接使用。

Native APIs是系统提供的GUI功能,比如系统通知、系统菜单、打开系统文件夹对话框等等,Electron通过集成Native APIs来为应用提供操作系统功能支持。

与传统Web网站不同,Electron基于主从进程模型,每个Electron应用程序有且仅有一个主进程(Main Process),和一个或多个渲染进程(Renderer Process),对应多个Web页面。除此之外,还包括GUP进程、扩展进程等其他进程。

主进程负责窗口的创建、进程间通信的协调、事件的注册和分发等。渲染进程负责UI页面的渲染、交互逻辑的实现等。但在这种进程模型下容易产生单点故障问题,即主进程崩溃或者阻塞将会导致整个应用无法响应。

Electron安装

在安装Electron的过程中遇到最大的问题可能就是下载Electron包时出现网络超时(万恶的墙),导致安装不成功。

解决方法自然是使用镜像,这里我们可以打开node_modules/@electron/get/dist/cjs/artifact-utils.js,找到处理镜像的方法mirrorVar

function mirrorVar(name, options, defaultValue) {
   
    // Convert camelCase to camel_case for env var reading
    const lowerName = name.replace(/([a-z])([A-Z])/g, (_, a, b) => `${
     a}_${
     b}`).toLowerCase();
    return (process.env[`NPM_CONFIG_ELECTRON_${
     lowerName.toUpperCase()}`] ||
        process.env[`npm_config_electron_${
     lowerName}`] ||
        process.env[`npm_package_config_electron_${
     lowerName}`] ||
        process.env[`ELECTRON_${
     lowerName.toUpperCase()}`] ||
        options[name] ||
        defaultValue);
}

以及获取下载路径getArtifactRemoteURL方法

async function getArtifactRemoteURL(details) {
   
    const opts = details.mirrorOptions || {
   };
    let base = mirrorVar('mirror', opts, BASE_URL); // ELECTRON_MIRROR 环境变量
    if (details.version.includes('nightly')) {
   
        const nightlyDeprecated = mirrorVar('nightly_mirror', opts, '');
        if (nightlyDeprecated) {
   
            base = nightlyDeprecated;
            console.warn(`nightly_mirror is deprecated, please use nightlyMirror`);
        }
        else {
   
            base = mirrorVar('nightlyMirror', opts, NIGHTLY_BASE_URL);
        }
    }
    const path = mirrorVar('customDir', opts, details.version).replace('{
   { version }}', details.version.replace(/^v/, '')); // ELECTRON_CUSTOM_DIR环境变量,并将{
   {version}}替换为当前版本
    const file = mirrorVar('customFilename', opts, getArtifactFileName(details));
    // Allow customized download URL resolution.
    if (opts.resolveAssetURL) {
   
        const url = await opts.resolveAssetURL(details);
        return url;
    }
    return `${
     base}${
     path}/${
     file}`;
}

可以看到可以定义挺多环境变量来指定镜像,比如ELECTRON_MIRROR、ELECTRON_CUSTOM_DIR等等,这其实在官方文档中也有标明

Mirror

You can use environment variables to override the base URL, the path at which to look for Electron binaries, and the binary filename. The URL used by @electron/get is composed as follows:

url = ELECTRON_MIRROR + ELECTRON_CUSTOM_DIR + '/' + ELECTRON_CUSTOM_FILENAME

For instance, to usethe China CDN mirror:

ELECTRON_MIRROR="https://cdn.npm.taobao.org/dist/electron/"
ELECTRON_CUSTOM_DIR="{
    { version }}"

因此在下载Electron时只需要添加了两个环境变量即可解决网络超时(墙)的问题

ELECTRON_MIRROR="https://cdn.npm.taobao.org/dist/electron/"  ELECTRON_CUSTOM_DIR="{
   { version }}" npm install --save-dev electron

安装完electron后,可以尝试写一个最简单的electron应用,项目结构如下

project
  |__index.js     # 主进程
  |__index.html   # 渲染进程
  |__package.json # 

对应的主进程index.js部分

const electron = require('electron');
const {
    app } = electron;

let window = null;

function createWindow() {
   
  if (window) return;
  window = new electron.BrowserWindow({
   
    webPreferences: {
   
      nodeIntegration: true // 允许渲染进程中使用node模块
    },
    backgroundColor: '#333544',
    minWidth: 450,
    minHeight: 350,
    height: 350,
    width: 450
  });
  window.loadFile('./index.html').catch(console.error);
  window.on('close', () => window = null);
  window.webContents.on('crashed', () => console.error('crash'));
}
app.on('ready', () => createWindow());
app.on('window-all-closed', () => {
   
  if (process.platform !== 'darwin') {
   
    app.quit();
  }
});

app.on('activate', createWindow)

对应的渲染进程index.html部分

<!DOCTYPE>
<html lang="zh">
<head><title></title></head>
<style>
    .box {
    color: white;font-size: 20px;text-align: center;}
</style>
<body>
<div class="box">Hello world</div>
</body>
</html>

package.json中添加运行命令

{
   
  ...,
  "main": "index.js",
  "script": {
   
     "start": "electron ."
  },
  ...
}

npm run start运行,一个最简单的electron应用开发完成。

项目结构

Electron项目通常由主进程和渲染进程组成,主进程用于实现应用后端,一般会使用C++或rust实现核心功能并以Node插件的形式加载到主进程(比如字节跳动的飞书、飞聊的主进程则是使用rust实现),其中的JavaScript部分像一层胶水,用于连接Electron和第三方插件,渲染进程则是实现Web UI的绘制以及一些UI交互逻辑。主进程和渲染进程是独立开发的,进程间使用IPC进行通信,因此对主进程和渲染进程进行分开打包,也就是两套webpack配置,同时为区分开发环境和生产环境,也需要两套webpack配置。此外在开发electron应用时会有多窗口的需求,因此对渲染进程进行多页面打包,整体结构如下。

project
  |__src
     |__main                                          # 主进程代码 
        |__index.ts
        |__other
     |__renderer                                      # 渲染进程代码
        |__index                                      # 一个窗口/页面
           |__index.tsx
           |__index.scss
        |__other   
  |__dist                                             # webpack打包后产物
  |__native                                           # C++代码
  |__release                                          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sundial dreams

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值