用 electron-forge 搭建 React + Ts 的项目

前言

如果你有桌面应用开发的需求,且比较熟悉 Web 相关的技术,那么 Electron 会是一个非常不错的选择,作为一个使用 Web 技术构建跨平台桌面应用的框架,其允许开发者使用JavaScript、HTML 和 CSS 等 Web 技术来构建桌面应用;同时,Electron 拥有一个活跃的社区和丰富的生态系统,这不仅意味着开发者可以轻松找到解决问题的资源和工具,还意味着框架的更新和改进是持续不断的,能够紧跟技术发展的步伐

本文将介绍如何用其构建一个应用 Demo 项目

介绍

创建 Electron 应用程序项目的方式有很多,如手动集成、electron-vite 快速构建等,本文将介绍通过 electron-forge 构建的方式

主要环境

  • electron-forge v7.6
  • webpack
  • react
  • typescript

Electron Forge 介绍

Electron Forge 是一个用于打包和分发 Electron 应用程序的一体化工具,可以认为是 Electron Builder 的替代品,它提供了一个全面的解决方案,包括初始化项目、本地开发、打包和发布,同时,其简化了 Electron 应用的开发和打包流程,使得开发者可以更专注于应用本身的开发

具体步骤

项目构建步骤主要如下,如果你需要源码,可从文末获取:

创建 electron 项目

在开始前,需先备有对应的工具,如:npmyarn
npm

本例使用的是npm,使用yarn的命令也差不多

通过模板创建项目

模板集成了一些项目构建工具,可以更为方便的为项目加入插件,主要提供了如下模板:

  • webpack

  • webpack-typescript

  • vite

  • vite-typescript

创建命令

选择合适的模板后,按照下列命令创建项目

npm init electron-app@latest [project-name] -- --template=[template-name]
  • [project-name]:表示项目名
  • [template-name]:表示模板名,在上侧提供的里面选择

开始创建

本例使用命令如下:

npm init electron-app@latest demo -- --template=webpack-typescript

该模板集成了webpacktypescript的能力

如果你选用vite相关模板,需注意:
vnote

创建好项目后的package.json依赖内容如下:

"devDependencies": {
  "@electron-forge/cli": "^7.6.0",
  "@electron-forge/maker-deb": "^7.6.0",
  "@electron-forge/maker-rpm": "^7.6.0",
  "@electron-forge/maker-squirrel": "^7.6.0",
  "@electron-forge/maker-zip": "^7.6.0",
  "@electron-forge/plugin-auto-unpack-natives": "^7.6.0",
  "@electron-forge/plugin-fuses": "^7.6.0",
  "@electron-forge/plugin-webpack": "^7.6.0",
  "@electron/fuses": "^1.8.0",
  "@typescript-eslint/eslint-plugin": "^5.0.0",
  "@typescript-eslint/parser": "^5.0.0",
  "@vercel/webpack-asset-relocator-loader": "1.7.3",
  "css-loader": "^6.0.0",
  "electron": "33.2.1",
  "eslint": "^8.0.1",
  "eslint-plugin-import": "^2.25.0",
  "fork-ts-checker-webpack-plugin": "^7.2.13",
  "node-loader": "^2.0.0",
  "style-loader": "^3.0.0",
  "ts-loader": "^9.2.2",
  "ts-node": "^10.0.0",
  "typescript": "~4.5.4"
},
"dependencies": {
  "electron-squirrel-startup": "^1.0.1"
}

如果命令一直创建失败,可能是网络问题,可考虑使用一些镜像站

试运行

创建好项目后,可以进入项目根目录,用执行如下命令,尝试是否可以正常运行:

# 运行
npm start

除此运行可能会报一些类型错误,大致如下:

Failed to load: ...\...\ele-react-demo\forge.config.ts

An unhandled rejection has occurred inside Forge:
TSError:
1. ⨯ Unable to compile TypeScript:
forge.config.ts:1:34 - error TS2307: Cannot find module '@electron-forge/shared-types' or its corresponding type declarations.

按照错误提示添加上相关依赖即可,可能需要添加的依赖如下

"devDependencies": {
    "@electron-forge/shared-types": "^7.6.0",
    "@electron-forge/maker-base": "^7.6.0",
    "@electron-forge/plugin-base": "^7.6.0",
    "webpack": "^5.97.0",
    "@types/node": "^22.10.1"
}

添加完缺少的依赖后,再次运行npm start启动项目,如运行成功,可看到如下界面
start

可以看到,默认会启动开发者工具,这是由于src/index.ts内的代码设置的,如下:
dev

如不需要,可将其注释或删除,需要打开开发者工具时通过快捷键 Ctrl + Shift + I (windows 系统)打开即可

试打包

当编写好项目后,需进行打包,可运行如下命令:

# 打包
npm run make

打包好后,项目根目录会出现一个out目录,内部即是打包好的文件;打包会检测本机系统,然后生成对应的打包文件

正常打包好后,内部会有两个目录,一个为make目录,里面有对应系统的二进制安装程序,如exe;另一个目录(如**-win32-x64),里面为对应系统的便携式免安装程序,点击产品名.exe即可打开应用,此目录内有个resource文件夹,装着项目编译的一些内容,如app.asar

asar 解包方法

asar文件类似一种压缩包,通过对应的工具可以对其进行解包,得到实际的文件

  • 安装解包工具:npm install -g asar
  • 运行命令解包:asar extract app.asar ./app (该命令会将 app.asar 解包到当前目录的 app 目录下)

解包后,目录内会有如下结构:

.webpack     # 项目编译部分
 ├- main     # electron 部分
 └- renderer # web 部分
node_modules # 项目依赖
package.json

如果你是用vite模板构建项目,文件名称可能稍有差别,但结构大致类似

集成 React

集成 React 可以让 UI 开发变得更为方便

安装依赖

首先安装对应依赖,如下:

# 安装 React 包
npm install --save react react-dom
# 安装 React 类型支持相关包
npm install --save-dev @types/react @types/react-dom
修改 tsconfig

修改项目根目录下的tsconfig.json,在 compilerOptions 下添加如下内容:

"compilerOptions": {
  "jsx": "react-jsx"
}
修改项目文件

在项目内使用React组件的能力,首先在src目录下新建文件app.tsx,内容如下:

/** src/app.tsx */

import { createRoot } from 'react-dom/client';
import { useState } from 'react';

// 主应用
function App() {
  const [count, setCount] = useState(0);

  return (
    <>
      <h1>Hello React</h1>
      <p>count: {count}</p>
      <button onClick={() => setCount(count + 1)}>count + 1</button>
    </>
  );
}

const root = createRoot(document.body);
root.render(<App />);

接着,在src/renderer.ts内导入它
render

然后,运行npm start启动项目,正常启动后如下
render

正常情况下,无需额外配置,项目即可实现热重载,比如修改了app.tsx内容后保存,无需重启项目,修改内容即可渲染出来

集成 SCSS

如果你需要使用一些 CSS预编译器,可参考一下步骤,这里以scss举例:

安装依赖

需安装sass相关依赖,如下:

npm install --save-dev sass sass-loader
配置 loader

修改项目根目录下的 webpack.renderer.config.ts 文件,如下:

// webpack.renderer.config.ts

// ··· ···

// 加入对对应样式文件的解析规则
rules.push({
  test: /\.(sass|scss|css)$/,
  use: [{ loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'sass-loader' }]
});

// ··· ···
使用 SCSS

重命名src目录下的样式文件,将index.css改为index.scss,然后即可在文件内添加scss样式规则,例如:

/* index.scss */
body {
  h1 {
    color: #68945c;
  }
}
导入 SCSS

index.scss导入src/renderer.ts内部使用
ren
接着,npm start启动项目,查看效果
scss
可以看到,scss的样式已可正常渲染

配置静态资源

如果你在项目内使用了一些静态资源(如图片),如下:
static

我在src目录下新建了一个assets目录,专门用于放置静态资源,现在里面放了一张图片;然后我在app.tsx内引用了它;接着启动项目,如果没有意外,可以看到图片并不会显示,控制台会报错找不到对应资源,查看编译后的.webpack目录,发现缺少没有对应的图片资源

这是由于静态资源没有被正确加载或复制,以下介绍两种简单可行的方式,仅供参考:

方法一

此方法仅配置打包后的静态资源,具体步骤如下:

  • 配置 forge.config.ts
const config: ForgeConfig = {
  packagerConfig: {
    asar: true,
    // 通过如下配置项,配置需打包的静态资源
    // 该配置会将对应资源复制到打包后的 resource 目录下
    // 这里表示复制 src/assets 整个目录
    // 打包后在 out/**-win32-x64/resource 目录下,会有一个 assets 目录
    extraResource: ['./src/assets']
  }
}
  • 使用时可以用相对路径,也可以借助path工具
// src/app.tsx
function App() {
  const [count, setCount] = useState(0);

  return (
    <>
      <h1>Hello React</h1>
      // 通过相对路径
      // 打包后的结构可看上方解答
      // web 部分在 resource/app.asar/.webpack/renderer/main_window
      // 资源部分在 resource/assets
      <img src="../../../../assets/images/cat.jpg" />
      // 也可以使用 path 拼接路径,如:path.join(process.resourcesPath, 'assets/images/cat.jpg')
      // process.resourcesPath 表示 resource 目录
      <p>count: {count}</p>
      <button onClick={() => setCount(count + 1)}>count + 1</button>
    </>
  );
}

此时npm run make打包后,运行打包的文件,即可看到静态资源已经可以正常显示了
img

这种方法只适用于处理打包的静态资源,开发npm start运行时依旧无法正常显示

并且,复制的静态资源存在于 renderer 目录下,并为打包进 app.asar

方法二

通过一些插件实现,如rollup-plugin-copycopy-webpack-plugin等,这里介绍copy-webpack-plugin的用法

  • 首先安装copy-webpack-plugin插件
npm install --save-dev copy-webpack-plugin
  • 接着配置使用插件,打开根目录下的webpack.plugins.ts文件
    plugin

以上配置会将./src/assets文件夹的内容复制到./.webpack/renderer/static文件夹内,在项目中使用时,只需通过./static目录进行访问即可,如下

// src/app.tsx
function App() {
  const [count, setCount] = useState(0);

  return (
    <>
      <h1>Hello React</h1>
      // 使用静态资源
      <img src="./static/images/cat.jpg" />
      <p>count: {count}</p>
      <button onClick={() => setCount(count + 1)}>count + 1</button>
    </>
  );
}

此时无论是开发运行npm start,还是打包npm run make运行,都能正确渲染静态资源
make

这种方法不仅可以正常显示与开发和打包中,同时在打包时,静态资源也会一并打包进 app.asar 内

配置 Loading 页面

以下内容是一些体验优化,参考即可

使用 electron 开发,在启动时,会有一段白屏时间,这主要是由于窗口加载后,页面资源还未加载渲染好造成的,在项目集成了RreactVue后,这个问题会愈发明显,白屏时间会更长

想要解决这个问题,由很多方式可以参考,如:优化资源、做一些预加载工作等

这里主要介绍一种比较简单的解决方式:加入 Loading 页面,主要思路就是在主窗口创建前,先创建一个 Loading 窗口,只用显示简单的 Loading 页面,然后再创建主窗口;窗口创建时默认都隐藏,当创建好后才显示,首先显示 Loading 窗口,待主窗口创建完成并准备好时,隐藏 Loading 窗口,展示主窗口

  • 首先在assets目录下新建一个loading.html,里面存放着一个loading动画样式,效果如下(可自行创意实现):
    ld
  • 接着,创建窗口渲染使用它,修改src/index.ts文件
// Loading 窗口
let loadingWin: BrowserWindow;
// Loading 窗口的渲染文档,即上侧的 loading 效果
const loadingUrl = path.join(__dirname, '../renderer/static/loading.html');

/** Loading 窗口 */
const createLoading = () => {
  return new Promise((resolve, reject) => {
    loadingWin = new BrowserWindow({
      // 一开始是否显示
      show: false,
      width: 512,
      height: 512,
      frame: false, // 无边框(窗口、工具栏等),只包含网页内容
      transparent: true // 窗口是否支持透明,在做高级效果时最好为 true
    });
    // 当窗口显示时
    loadingWin.once('show', () => {
      resolve(true);
    });
    // 配置窗口渲染文档
    loadingWin.loadFile(loadingUrl);
    // 显示 Loading 窗口
    loadingWin.show();
  });
};

/** 主窗口 */
const createWindow = () => {
  // 创建渲染窗口
  const mainWindow = new BrowserWindow({
    // 窗口图标
    // icon: './assets/logo/logo.ico',
    height: 600,
    width: 800,
    // 一开始隐藏
    show: false,
    webPreferences: {
      // 预加载脚本
      preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY
    }
  });
  // 主窗口准备还显示
  mainWindow.once('ready-to-show', () => {
    // 隐藏 Loading 窗口
    loadingWin.hide();
    // 关闭 Loading 窗口
    loadingWin.close();
    // 展示 主窗口
    mainWindow.show();
  });

  // 为窗口加载 index.html
  mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);

  // 打开开发者工具
  // mainWindow.webContents.openDevTools();
};

// 当 Electron 初始化完成并准备创建渲染窗口(mainWindow)时调用
// 某些 API 只能在此事件发生后使用
// app.on('ready', createWindow);
app.on('ready', async () => {
  // 先创建 Loading 窗口
  await createLoading();
  // 再创建 主窗口
  createWindow();
});

加入loading窗口后,白屏时间可以显著改善,程序启动后,会先显示loading窗口,待主窗口完全准备好后再显示主窗口,效果大致如下:

【一张动图,但这放不了】

如果需要,还可以给主窗口页面加入一个淡入的动画效果,交互体验也许会更好

总结

本文介绍了用electron-forgewebpacktypescriptreactscss搭建的一个模板项目,同时还包含静态资源配置及loading效果

如果你由于网络原因npm init创建electron项目一直失败,也可以到github克隆本项目直接修改使用
git

克隆完成后到项目根目录通过如下命令即可使用

# 安装依赖
pnpm install
# 运行
npm start
# 打包
npm run make
参考资料

Electron Forge: https://www.electronforge.io/

模板地址: https://github.com/skmcj/demo

想了解更多类似知识点文章可关注公zhon号【代码杂谈

### 创建 Vite + Electron + React + TypeScript 项目的启动流程 以下是关于如何使用 Vite、ElectronReactTypeScript 创建并启动项目的详细说明: #### 初始化项目 通过 `npm` 或 `yarn` 使用 Vite 工具来初始化一个新的 React 项目,并选择 TypeScript 支持。 ```bash npm create vite@latest my-vite-electron-app --template react-ts cd my-vite-electron-app ``` 这一步会生成一个基础的 React + TypeScript 的 Vite 项目结构[^2]。 --- #### 安装依赖项 进入项目目录后,安装必要的依赖包。这些依赖包括但不限于以下内容: - **Electron**: 提供跨平台桌面应用支持。 - **electron-builder**: 打包和发布 Electron 应用程序。 - **typescript**: 类型定义支持。 - **vite-plugin-electron**: 集成 Vite 和 Electron 的插件。 运行以下命令以安装上述依赖项: ```bash npm install electron electron-builder vite-plugin-electron -D ``` 如果需要热重载功能(解决渲染进程代码修改后页面不自动刷新的问题),可以额外安装 `electron-hot-reload` 插件[^3]: ```bash npm install electron-hot-reload -D ``` --- #### 修改配置文件 为了使 Vite 能够与 Electron 正常协作,需调整 `vite.config.ts` 文件的内容。例如,在其中引入 `vite-plugin-electron` 并启用主进程的热重载功能。 ```typescript import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import electron from 'vite-plugin-electron'; export default defineConfig({ plugins: [ react(), electron({ main: { entry: 'src/main/index.ts', // 主进程入口文件路径 plugins: [require('electron-hot-reload')()], // 启用热重载插件 }, }), ], }); ``` 此配置指定了主进程的入口文件位置,并启用了热重载功能以便于开发阶段调试。 --- #### 编写主进程逻辑 在 `src/main/` 目录下创建主进程所需的脚本文件,通常命名为 `index.ts`。这是一个基本的例子: ```typescript import { app, BrowserWindow } from 'electron'; let mainWindow: BrowserWindow | null = null; app.whenReady().then(() => { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: './preload.js', contextIsolation: true, }, }); mainWindow.loadURL(`http://localhost:3000`); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); ``` 这段代码设置了窗口大小、加载 URL 地址以及处理关闭事件的行为[^2]。 --- #### 运行项目 完成以上步骤之后,可以通过以下命令启动开发环境: ```bash npm run dev ``` 此时,Vite 将负责编译前端资源,而 Electron 则用于展示最终的应用界面。确保端口未被占用,默认情况下 Vite 开发服务器监听的是 `3000` 端口。 --- #### 生产打包 当开发完成后准备部署时,可利用 `electron-builder` 对整个项目进行打包操作。在此之前可能还需要编辑 `package.json` 中的相关字段,比如指定产品名称、版本号等信息。 执行如下指令即可生成适用于目标系统的安装包: ```bash npm run build && npm run dist ``` 具体选项可以根据实际需求进一步定制化设置。 --- ### 总结 综上所述,构建一个完整的 Vite + Electron + React + TypeScript 项目涉及多个环节,从初始模板的选择到后期的功能扩展都需要精心设计。遵循官方文档指南的同时结合社区实践经验能够有效提升效率并减少潜在错误的发生概率。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值