前言
- 为什么是react?
- 因为react可以完美的使用tsx,tsx使用ts-loader不经过babel转换就可以编译成js代码,配合Chromium的高兼容性
- 为什么是ts?
- 可以使用import语法+N原因
- 为什么自己搭建?
- 实际也可以用cra,但是需要使用
customize-cra react-app-rewired修改cra的默认配置
- 实际也可以用cra,但是需要使用
- vite搭建的项目做渲染线程可以吗
- 不可以,因为vite不支持fs等nodejs内置模块,如果有配置方法,可以留言下
必备文档汇总
webpack官方文档 中文版本感觉和官方英文文档有差异,推荐看官方的
我的环境信息:
Nodejs: v12.18.3
npm: 6.14.6
操作系统: Macos 10.15.7
项目所需依赖都是用最新版本
开始搭建
1.安装依赖
- 初始化npm
mkdir react-electron && cd react-electron
npm init -y
- 支持Typescript
npm i typescript ts-loader source-map-loader -D
tsc --init
- 支持React
npm i react react-dom @types/react @types/react-dom react-router-dom @types/react-router-dom -S
- 支持webpack,不指定版本号,默认使用webpack5
npm i webpack webpack-cli webpack-dev-server html-webpack-plugin webpack-merge clean-webpack-plugin hoist-non-react-statics -D
- 支持electron
npm i electron electron-is-dev
2.配置tsconfig
/tsconfig.json
第一个ts配置文件,用于react项目(渲染线程),这里为了节省篇幅把注释都删除了,建议保留
{
"compilerOptions": {
"target": "esNext",
"module": "commonjs",
"jsx": "react",
"outDir": "./render/dist",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"baseUrl": ".",
"paths": {
},
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"./render/**/*"
]
}
/tsconfig-main.json
第二个ts配置文件,用于编译主线程
{
"compilerOptions": {
"target": "esNext",
"module": "commonjs", "outDir": "dist",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"baseUrl": ".",
"paths": {
},
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"./main/**/*"
]
}
3.搭建react环境
新建文件夹/render 和/render/main , 分别含义为渲染线程文件夹,和渲染线程主页面,未来可能有多个页面
/render/main/index.html
最基础的一个html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
/render/main/index.tsx
react入口文件,没有任何逻辑,仅渲染一个div
import React, {useEffect, useState} from 'react'
import ReactDom from 'react-dom'
const App = () => {
return <div>
<div>hello react</div>
</div>
}
ReactDom.render(<App></App>, document.getElementById('root'))
4.配置webpack
新建文件夹/render/config 这里面放webpack的配置文件
/render/config/htmlWebpackPlugin.js
htmlWebpackPlugin逻辑封装(因为有时候要配置cdn),这里可以都写进主配置文件
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
function htmlWebpackPlugin(mode){
return new HtmlWebpackPlugin({
template: path.join(__dirname, "../main/index.html"),
filename: 'index.html',
})
}
module.exports ={
htmlWebpackPlugin
}
/render/config/webpack.common.js
webpack主配置文件,注意这里的
target: "electron-renderer",这样修改才能使用electron和fs等模块,但是修改为electron-renderer后只能在electron环境中运行,自行灵活配置
对应文档:www.webpackjs.com/configurati…
或者通过 const {ipcRenderer}=window.require('electron') 方式来解决,webpack不会解析electron依赖
const webpack = require('webpack')
const path = require('path');
module.exports = {
entry: './render/main/index',
output: {
filename: "[name].[hash].js",
path: path.join(__dirname, "../dist-main"),
},
target: "electron-renderer",
resolve: {
// 引入的默认后缀名,一个个找
extensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
alias: {
// "@": path.resolve("src"), // 这样配置后 @ 可以指向 src 目录
},
},
module: {
rules: [{
test: /\.tsx?$/,
loader: "ts-loader",
exclude: /node_modules/,
}],
},
plugins: [],
}
/render/config/webpack.dev.js
webpack开发环境配置,没什么特殊,主要是配置一个开发服务器
const webpack = require('webpack')
const {
merge
} = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path');
const {htmlWebpackPlugin} = require('./htmlWebpackPlugin')
const mode = 'development'
module.exports = merge(common, {
mode,
devtool: 'inline-source-map',
devServer: {
hot: true,
contentBase: path.join(__dirname, "../dist"),
historyApiFallback: {
index: "./index.html",
},
},
plugins: [
htmlWebpackPlugin(mode),
new webpack.HotModuleReplacementPlugin()
],
})
/render/config/webpack.prod.js
webpack打包配置
const webpack = require('webpack')
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const {htmlWebpackPlugin} = require('./htmlWebpackPlugin')
const mode = 'production'
module.exports = merge(common,{
mode,
devtool: 'source-map',
plugins: [
// 打包时候才需要clear
new CleanWebpackPlugin(),
htmlWebpackPlugin(mode),
],
})
5.启动webpack开发服务器
package.json加上两条执行命令,start:react对应启动开发服务器,build:react对应执行打包
"start:react": "webpack serve --config render/config/webpack.dev.js",
"build:react": "webpack --config render/config/webpack.prod.js"
npm run start:react
如果启动过程没有报错.而且浏览器可以正常打开默认的ip端口http://localhost:8080,就说明这一步完成了
6.配置主线程
新建文件夹/main,所有主线程的逻辑都在这里写
/main/mainWindow.ts
一个常见的主线程打开窗口的逻辑,封装为
create函数,electron-is-dev包可以让我们识别现有的环境, 开发环境和打包环境分别load
import {BrowserWindow} from 'electron'
import isDev from 'electron-is-dev'
import {resolve} from 'path'
let win: BrowserWindow;
export function create() {
win = new BrowserWindow({
width: 600,
height: 600,
webPreferences: { // 网页功能设置
nodeIntegration: true, // 是否在node工作器中启用工作集成默认false
enableRemoteModule: true, // 是否启用remote模块默认false
}
})
if (isDev) {
win.webContents.openDevTools() //打开控制台
win.loadURL('http://localhost:8080')
} else {
// 线上模式, 用react打包的
win.loadFile(resolve(__dirname, '../render/dist-main/index.html'))
}
return win
}
/main/index.ts
主线程入口文件
import {app, BrowserWindow} from 'electron'
import {create} from './mainWindow'
app.on('ready', () => {
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'; // 关闭web安全警告
create()
})
package.json添加npm执行命令
dev:main,tsc监控文件变化并实时编译,这里使用-p手动执行ts配置文件
"build:main": "tsc --p tsconfig-main.json",
"dev:main": "tsc -w --p tsconfig-main.json"
配置好了之后可以尝试执行下npm run dev:main,如果都按照我的配置,主线程打包文件在根目录的dist文件夹下面
7.启动主线程
- 修改package.json
- 配置main字段
- 配置
start:electron命令 - author和description也可以先配置上,后面打包要用到
对应文档:www.electronjs.org/docs/tutori…
{
"name": "react-electron",
"version": "1.0.0",
"author": "",
"description": "My Electron app",
"main": "dist/index.js",
"scripts": {
"start:react": "webpack serve --config render/config/webpack.dev.js",
"build:react": "webpack --config render/config/webpack.prod.js",
"build:main": "tsc --p tsconfig-main.json",
"dev:main": "tsc -w --p tsconfig-main.json",
"start:electron": "electron ."
}
}
执行命令:
npm run start:electron
如果窗口成功弹出并且带着react渲染,就说明成功了
8.打包发布版本
- 执行webpack打包命令
npm run build:react
如果按照我的配置文件,打包出来的文件在/render/dist-main
- 修改主线程的load逻辑
...
if (isDev) {
...
} else {
// 引用webpack的打包内容
win.loadFile(resolve(__dirname, '../render/dist-main/index.html'))
}
...
- 打包主线程
npm run build:main
- 导入 Electron Forge 到应用文件夹
npx @electron-forge/cli import
- 创建一个分发版本,软件包在out文件夹
npm run make
对应文档:www.electronjs.org/docs/tutori…
可能遇到的问题
- 安装electron报红
Permission denied,mkdir xxx
请勿将electron作为全局依赖安装,如果有请手动卸载
代码仓库,注意是1.base_env分支
https://github.com/Licht-club/react-electron/tree/1.base_env
下一期主题(已更新)
这期忘记截图了,所以可能有点枯燥,下次一定注意