前言
本人后端开发,思维比较活跃,脑子里经常会冒出些小点子,但很多时候,只有后端手段的我难以将他们实现出来,故此借助electron系统学习一下前端的技术栈。
本文目标:搭建一套 Electron + Vite + React + TypeScript 的模板。
创建 electron 项目
既然是以学习为目的,那就不使用quick-start了,照着 官网教程走一遍。
先初始化一个node项目:
bash
cd electron-demo && cd electron-demo
npm init -y
npm init -y
命令将自动创建一个 package.json
文件,并填充默认值。
这里了解一下几个字段:
-
scripts : 这个字段是一个对象,它包含了可以运行的脚本命令。这些脚本可以通过
npm run <script>
命令来执行。常用的npm run dev
就来自于它。 -
dependencies: 这个字段列出了项目运行时所需的依赖包。当你发布或部署应用时,这些依赖是必须的。
-
devDependencies: 这个字段列出了只在开发过程中需要的依赖包,比如编译工具或测试框架。这些依赖不会被包含在生产环境的部署中。我的理解是能放这里的都尽量放这里,别让打出的包太臃肿。
-
repository : 这个字段指定了项目的存储库信息(第一眼我以为这是指定发包maven仓的呢)。这个字段通常包含类型(如
git
)、URL(项目的存储库地址),以及可能的分支(如master
)。这有助于其他开发者找到项目的源代码。例如:
JSON
"repository": {
"type": "git",
"url": "https://github.com/bby580/electron-demo.git"
}
将 Electron 加入项目
现在项目里空空荡荡,只有package.json
一个光杆司令,我们将electron引入进来:
bash
npm install --save-dev electron electron-builder
附带上了构建所需依赖,这里都不指定版本,用最新的。
这时候应该添加主程序了,为了方便管理,我选择创建一个文件夹专门存储于electron有关的代码,并将入口改为 main.js,如下图:
新建 main.js 文件,只填入一条打印语句:
js
console.log("Hello World!");
引入 TypeScript
添加依赖
将 typescript 添加项目:
bash
npm install --save-dev typescript eslint
配置文件
添加ts的配置文件: tsconfig.json
tsconfig.json
是一个用于配置TypeScript编译器的JSON文件,它可以用来指定TypeScript项目的根文件、编译选项和类型检查规则,以下配置使用GPT添加了注释。
json
// 这个 tsconfig.json 文件是用来配置 TypeScript 编译器的
{
"compilerOptions": {
// 指定编译后的目标 JavaScript 版本,ESNext 表示使用最新的 ES 标准
"target": "ESNext",
// 指定是否使用 class 字段的新语法,true 表示使用,false 表示使用旧的赋值语法
"useDefineForClassFields": true,
// 指定要包含在编译中的库文件,这里包含了 ES2020 标准库,DOM 库和 DOM 可迭代库
"lib": ["ES2020", "DOM", "DOM.Iterable"],
// 指定生成的模块代码的类型,ESNext 表示使用最新ES标准,即使用 import 和 export 关键字
"module": "ESNext",
// 指定是否跳过对所有声明文件(*.d.ts)的类型检查,true 表示跳过,可以提高编译速度,但可能会忽略一些类型错误
"skipLibCheck": true,
// 指定模块解析策略,bundler 表示使用与打包工具(如 webpack 或 rollup)相同的策略,即尝试解析相对路径和非相对路径的模块
"moduleResolution": "bundler",
// 指定是否允许导入扩展名为 .ts 的文件,true 表示允许,false 表示不允许
"allowImportingTsExtensions": true,
// 指定是否支持导入 JSON 模块,true 表示支持,false 表示不支持
"resolveJsonModule": true,
// 指定是否将每个文件作为单独的模块,true 表示是,false 表示否,这对于使用 babel 或 ts-loader 的项目有用
"isolatedModules": true,
// 指定是否生成输出文件,true 表示不生成,false 表示生成,这对于只进行类型检查的项目有用
"noEmit": true,
// 指定是否允许编译 JavaScript 文件,true 表示允许,false 表示不允许
"allowJs": true,
// 指定是否启用所有严格类型检查选项,true 表示启用,false 表示不启用
"strict": true,
// 指定是否报告未使用的局部变量错误,false 表示不报告,true 表示报告
"noUnusedLocals": false,
// 指定是否报告未使用的参数错误,false 表示不报告,true 表示报告
"noUnusedParameters": false,
// 指定是否报告 switch 语句中缺少 break 或 return 的错误,true 表示报告,false 表示不报告
"noFallthroughCasesInSwitch": true
},
// 指定要包含在编译中的文件或目录的列表,这里包含了 web 和 electron 两个目录
"include": ["web", "electron"]
}
顺便查一下 module
选项可以常用的模式:
None
:不生成任何模块代码,适用于脚本或全局作用域的代码。CommonJS
:使用require
和module.exports
的模块系统,适用于 Node.js 或其他 CommonJS 兼容的环境。AMD
:使用define
和require
的模块系统,适用于异步加载的场景,如 RequireJS。System
:使用System.register
的模块系统,适用于动态加载的场景,如 SystemJS。UMD
:使用通用模块定义(Universal Module Definition)的模块系统,适用于多种环境,如浏览器或 Node.js。ESNext
:使用最新的 ES 标准的模块系统,使用import()
,用于支持原生 ES 模块的环境,如现代浏览器。
运行
将 js 文件换成 ts,并将package.json 里的 main 地址修改成tsc输出路径:
json
"main": "dist-electron/main.js",
还需修改启动脚本,先编译再启动:
json
"scripts": {
"start": "tsc && electron ./dist-electron/main.js"
},
整体如下:
引入 ESLint
这是一个可选项,对于个人项目而言,不配这玩意儿也完全没问题,但是还是那句话,我们的目的是学习,所以还是搞里头!
添加依赖
ESLint 是一个用来识别和报告 JavaScript 代码中的模式的静态代码分析工具1。ESLint 可以帮助你找到和修复代码中的问题,提高代码的质量和一致性。ESLint 是完全可配置的,你可以自定义规则,使用自定义解析器,或者使用预定义的配置集合2。
记得以前还有个TSLint的,后面好像被 TypeScript 官方弃用了,我们不纠结,直接用 ESLint。
添加 eslint 和 其相关插件:
bash
npm install --save-dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
配置文件
添加 ESLint 的配置文件 eslintrc.cjs
eslintrc.cjs
是一个用于配置ESLint的JavaScript文件,它可以在使用"type":"module"的JavaScript包中运行ESLint。
js
// 这个 .eslintrc.cjs 文件是一个用于配置 ESLint 的 JavaScript 文件,它可以在使用 "type":"module" 的 JavaScript 包中运行 ESLint[^1^] [^2^]
module.exports = {
// 表示这是最顶层的配置文件,ESLint 会停止在父文件夹中查找其他配置文件
root: true,
// 表示指定代码运行的环境,这里是浏览器和 ES2020 标准
env: { browser: true, es2020: true },
// 表示继承一些共享的配置,这里是 ESLint 推荐的配置,TypeScript 推荐的配置,和 React Hooks 推荐的配置
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended'
],
// 表示指定要忽略的文件或目录,这里是 dist 和 .eslintrc.cjs
ignorePatterns: ['dist', '.eslintrc.cjs'],
// 表示指定要使用的解析器,这里是 TypeScript 的解析器
parser: '@typescript-eslint/parser',
// 表示指定要使用的插件,这里是 react-refresh 插件
plugins: ['@typescript-eslint'],
// 表示指定要启用或禁用的规则,以及它们的错误级别或选项
rules: {
// 启用 @typescript-eslint 插件的 no-unused-vars 规则,它会报告未使用的变量或参数,这里忽略所有变量,但不忽略参数
'@typescript-eslint/no-unused-vars': [
'error',
{ varsIgnorePattern: '.*', args: 'none' }
],
},
}
测试
可添加脚本 lint,这里要注意使用--ext,否则默认不检查ts文件:
json
"scripts": {
"start": "tsc && electron ./dist-electron/main.js",
"lint": "eslint ./ --ext ts,tsx --max-warnings 0"
}
执行结果如下:
引入 Vite
添加依赖
此事不着急去写逻辑,我们先把项目配置好。
Vite 是尤大在出Vue3时推出的新一代的前端构建工具,按理说使用React更好的选择应该是webpack,但谁让Vite上手简单呢?
使用Vite打包electron,只引Vite肯定是不行的,还需两个插件:vite-plugin-electron 和 vite-plugin-electron-renderer,看名字就知道干啥的了。
bash
npm install --save-dev vite vite-plugin-electron vite-plugin-electron-renderer
配置文件
1、Vite.config.ts
vite.config.ts
是一个用于配置Vite的TypeScript文件,它可以用来指定Vite项目的基本信息、插件、构建选项和服务端渲染设置。
ts
import {defineConfig} from 'vite'
import electron from 'vite-plugin-electron/simple'
import * as path from 'path';
export default defineConfig({
plugins: [
electron({
main: {
entry: 'electron/main.ts',
},
preload: {
input: path.join(__dirname, 'electron/preload.js'),
},
renderer: {},
}),
]
})
2、tsconfig.node.json
tsconfig.node.json
是一个用于配置Node.js环境下的TypeScript编译器的JSON文件,它可以用来指定Node.js项目的根文件、编译选项和类型检查规则,以下配置也使用GPT添加了注释。
json
// 这个tsconfig.node.json文件是用来配置Node.js环境下的TypeScript编译器的
{
"compilerOptions": {
// 启用项目引用,表示这个配置文件可以被其他配置文件引用
"composite": true,
// 跳过对所有声明文件的类型检查,可以提高编译速度,但可能会忽略一些类型错误
"skipLibCheck": true,
// 使用ESNext标准的模块系统,即使用import和export关键字
"module": "ESNext",
// 使用与打包工具相同的模块解析策略,即尝试解析相对路径和非相对路径的模块
"moduleResolution": "bundler",
// 允许从没有默认导出的模块中导入默认成员,例如import React from 'react'
"allowSyntheticDefaultImports": true
},
// 只包含vite.config.ts文件,表示只对这个文件进行编译
"include": ["vite.config.ts"]
}
那么为什么要创建 tsconfig. json 和 tsconfig.node.json两个 TypeScript 配置文件 ?
这是一个很好的问题。
- Vite 的项目包含两种不同的环境:浏览器和 Node.js。浏览器是用来运行应用程序的,而 Node.js 是用来运行 Vite 本身和它的配置的。这两种环境有不同的模块系统、API 和约束,所以需要不同的编译选项和类型检查规则。
tsconfig.json
是一个通用的配置文件,它适用于浏览器环境,也就是你的应用程序的源代码。它使用 ES2020 标准的模块系统,即使用 import 和 export 关键字12。tsconfig.node.json
是一个针对 Node.js 环境的配置文件,它适用于 Vite 的配置文件,也就是vite.config.ts
文件。它使用 CommonJS 的模块系统,即使用 require 和 module.exports12。- tsconfig.node.json 会继承 tsconfig.json 的部分设置,但也会根据 Node.js 的特性进行一些调整。例如,tsconfig.node.json 会设置 module 为 CommonJS,而 tsconfig.json 会设置 module 为 ES202012。
- tsconfig.json 会通过 references 字段引入 tsconfig.node.json 中的配置,这样可以启用项目引用的功能,即可以在不同的配置文件之间建立依赖关系。
测试
添加dev和build到scripts:
json
"scripts": {
"dev": "vite",
"build": "tsc && vite build && electron-builder",
"start": "tsc && electron ./dist-electron/main.js",
"lint": "eslint ./ --ext ts,tsx --max-warnings 0"
}
直接运行 npm run dev
:
引入 React
创建一个窗口
先在主进程创建一个窗口,这个窗口加载百度主页。修改main.ts:
ts
import {app, BrowserWindow} from 'electron'
import path from "node:path";
console.log('Hello World!')
app.whenReady().then(() => {
const window = new BrowserWindow({
width: 1100, height: 700,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
window.loadURL('https://www.baidu.com')
window.show()
})
添加依赖
shell
# 添加依赖,与之前不同,这里是添加到 `dependencies` 中的
npm install react react-dom
# 添加 react 的 ts 类型信息
npm install --save-dev @types/react @types/react-dom
# 添加 Vite 的 react 插件
npm install --save-dev @vitejs/plugin-react
添加文件
在根目录新建一个web文件夹,用于存放所有网页文件,并创建两个入口文件
├─ web
│ └─index.html
│ └─index.tsx
index.tsx
是 react 的入口文件,通过 index.html
被读取。在这个文件写了一句"Hello React!"
js
import React from 'react'
import ReactDOM from 'react-dom/client'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<h1>Hello React!</h1>
</React.StrictMode>,
)
index.html
是 Vite 启动服务的入口文件,服务启动后从此处加载资源,我们在该文件中引入 index.tsx
。默认情况下,index.html
应该是在根目录的,具体见 官方文档,此处我想把它和react放在一起,用了多入口的方式,说不定以后还会再开一个页面呢!
index.html
默认写了一句"Hello, world!",与index.tsx
中不同,因为我们要看看react是否会成功运行。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>electron-demo</title>
</head>
<body>
<div id="root">
<h1>Hello, world!</h1>
</div>
<!-- 以模块方式导入index.tsx -->
<script type="module" src="index.tsx"></script>
</body>
</html>
修改代码
修改 vite.config.ts
,此处改动两处
- 修改入口文件位置
- 将插件注册:
ts
import {defineConfig} from 'vite'
import electron from 'vite-plugin-electron/simple'
import react from '@vitejs/plugin-react'
import path from 'node:path';
import { resolve } from 'path'
export default defineConfig({
build: {
rollupOptions: {
input: { // 这里修改了配置文件入口
index: resolve(__dirname, '/web/index.html')
},
},
},
plugins: [
react(), // 添加 react 插件
electron({
main: {
entry: 'electron/main.ts',
},
preload: {
input: path.join(__dirname, 'electron/preload.ts'),
},
renderer: {},
}),
]
})
修改主进程 main.ts
,让窗口浏览器加载 Vite 服务器:
ts
import {app, BrowserWindow} from 'electron'
import path from "node:path";
// Vite 服务器地址,这里使用了web文件夹中的入口
const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL+'web/'
app.whenReady().then(() => {
const window = new BrowserWindow({
width: 1100, height: 700,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
})
window.loadURL(VITE_DEV_SERVER_URL)
window.show()
})
结果
如此,程序完美运行:
另外,我试了下,打包还是有问题,下周末再研究吧,先不卷了。