# react18-webpack5-demo
**Repository Path**: kayanchan/react18-webpack5-demo
## Basic Information
- **Project Name**: react18-webpack5-demo
- **Description**: 在node=16.17.0的环境下,实现基于webpack5构建的react18项目框架。
同时也满足vite的构建。
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-10-25
- **Last Updated**: 2025-01-10
## Categories & Tags
**Categories**: Uncategorized
**Tags**: React, webpack, vite
## README
# React18-Webpack5-demo
React 项目搭建方式:
1. 浏览器中通过标签直接引入 -- 不符合项目工程化
2. 使用官方脚手架 create-react-app -- webpack 配置默认不暴露
3. 使用 react、webpack 等自行搭建 -- 推荐,配置灵活
4. 使用 Next.js 构建全栈式 -- 官方推荐,需要学习 Next.js
本项目采用从 0 开始自行搭建,对配置过程进行记录。项目需满足在`node=16.17.0`环境下运行。
## 初始化,基本配置
1. 新建项目文件夹 react18-webpack5-demo
```bash
mkdir react18-webpack5-demo
cd react18-webpack5-demo
```
2. git 初始化
```bash
git init
touch README.md
git add README.md
git commit -m '提交 README.md'
git remote add origin git@gitee.com:kayanchan/react18-webpack5-demo.git
git push -u origin "master"
```
3. package.js 初始化 `yarn init`
4. 安装 webpack
```bash
yarn add webpack webpack-cli -D
# webpack 5.95.0
# webpack-cli 5.1.4
```
5. 安装 react
```
yarn add react react-dom
```
6. 搭建项目目录
- config (配置目录)
- webpack.config.base.js (webpack 公共配置)
- webpack.config.dev.js (webpack 开发配置)
- webpack.config.prod.js (webpack 生产配置)
- public (静态目录)
- index.html
- src
- components
- pages
- index.js
7. 安装 HtmlWebpackPlugin
```bash
yarn add html-webpack-plugin -D
# html-webpack-plugin 5.6.3
yarn add html-loader -D
# 当前稳定版本(5.1.0)不兼容node环境
npm view html-loader engines
# node: '>= 18.12.0'
npm view html-loader@4.2.0 engines
# node: '>= 14.15.0'
yarn add html-loader@4.2.0 -D
# 需要安装指定历史版本
```
8. 安装 babel
```
yarn add @babel/core babel-loader @babel/preset-env @babel/preset-react -D
```
在根目录下建立.babelrc 文件,写入 babel 配置
```
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
```
9. 安装 WDS
```bash
yarn add webpack-dev-server@4.15.2 -D
```
10. 编辑 package.json 的 scripts
```json
"scripts": {
"start": "webpack serve --mode development --config config/webpack.config.base.js --open",
"build": "webpack --mode production --config config/webpack.config.base.js"
}
```
11. 编写 webpack 配置 - config/webpack.config.base.js
```javascript
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: {
index: "./src/index.js",
},
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "..", "build"),
},
plugins: [
new HtmlWebpackPlugin({
title: "react18-webpack5-demo",
filename: "index.html",
template: "./public/index.html",
}),
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
{
test: /\.html$/,
use: {
loader: "html-loader",
},
},
],
},
};
```
12. 编写 html 模版 - public-index.html
```html
Document
```
13. 编写入口文件 - src/index.js
```javascript
import React from "react";
import { createRoot } from "react-dom/client";
const App = () => Hello
;
const root = createRoot(document.getElementById("app"));
root.render();
```
## 环境分离
环境分离主要是区分本地和生产两种环境,本地调试需要能实时看到代码变化,而生产环境需要编译成指定的文件。
### 方法一:开发环境和生产环境共用配置文件,通过参数来区分环境
1. 配置文件分离 package.json
**开发环境和生产环境都使用 webpack.config.base.js 文件**,通过 package.json 中设置指令增加 --env 参数来区分
```javascript
"scripts": {
"start": "webpack serve --config config/webpack.config.base.js --env development",
"build": "webpack --config config/webpack.config.base.js --env production"
}
```
2. 在 webpack.config.base.js 中 module.exports 定义为函数,就可以接收 env 传递的参数
```javascript
module.exports = (env) => {
// 赋值后可在 babel.config.js 中获取当前环境
process.env.NODE_ENV = env.production ? "production" : "development";
const config = env.production ? prodConfig : devConfig;
};
```
3. 通过 webpack-merge 工具来对配置代码进行合并
```javascript
const { merge } = require("webpack-merge");
merge(baseConfig, config);
```
### 方法二:开发环境和生产环境分别定义配置文件,在 package.json 中定义对应的指令
1. 配置文件分离 package.json
```json
"scripts": {
"start": "webpack serve --config config/webpack.config.dev.js --env development",
"build": "webpack --config config/webpack.config.prod.js --env production"
}
```
2. 添加环境参数
```javascript
process.env.NODE_ENV = "development";
```
3. 在指定环境配置文件中,合并公共配置
```javascript
const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.config.base");
const devConfig = {...};
module.exports = merge(baseConfig, devConfig);
```
## 开发环境配置
1. 设置 mode `mode: 'development'`
2. 配置 devServer
## 生产环境配置
1. 设置 mode `mode: production`
2. 代码压缩、分包、优化
## 样式资源
1. 安装所需要的包
```bash
# less
yarn add less less-loader@11.1.4
# postcss
yarn add postcss postcss-loader@4.3.0 postcss-preset-env@9.6.0
# css
yarn add css-loader@6.11.0
# 样式处理
yarn add mini-css-extract-plugin style-loader
```
2. commonStyleLoader: 提取相同的配置
```javascript
// 1. 使用 postcss-loader 进行兼容性处理
// 2. 通过 css-loader 解析 css 语法
const commonStyleLoader = [
isDevelopment && "style-loader",
isProduction && MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"],
},
},
},
];
```
3. 处理 less 和 css
```javascript
{
test: /\.css$/,
exclude: /node_modules/,
use: commonStyleLoader,
},
{
test: /\.less$/,
exclude: /node_modules/,
use: [...commonStyleLoader, "less-loader"],
}
```
4. mini-css-extract-plugin: 将 JS 中 import 导入的样式文件代码单独打包成一个 CSS 文件,适用于生产环境,减少 HTML 文件大小,可利用浏览器缓存
```javascript
new MiniCssExtractPlugin({
filename: "style/[name].[contenthash:8].css",
});
```
5. style-loader: 将 JS 中 import 导入的样式文件代码打包到 JS 文件中,运行时将样式自动插入到 style 标签中,适用于开发环境
6. 在 package.json 设置兼容性要求
```json
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 safari version",
"last 1 firefox version"
],
"production": [
">0.2%",
"not dead"
]
}
```
## babel 处理 js/jsx
1. 安装 babel 相关资源
- babel-loader 处理 js 和 jsx 文件
- @babel/preset-env 将高版本 js 编译成低版本 js
- @babel/preset-react 编译 react 的 jsx 文件
- @babel/plugin-transform-runtime 抽离公共的辅助编译方法,减少构建后包的体积
- @babel/runtime-corejs3 添加 corejs 的配置增加 js 兼容处理 polyfills
```bash
yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/plugin-transform-runtime @babel/runtime-corejs3 -D
```
2. 在`.babelrc`添加 babel 配置
```
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": [["@babel/plugin-transform-runtime", { "corejs": "3" }]]
}
```
3. 配置 webpack 的 extension
```
resolve: {
extensions: [".jsx", ".js", ".json"],
}
```
## 图片
在 webpack5 之前,处理字体图片等资源需要通过 url-loader(将文件作为 data URI 内联到 bundle 中) 和 file-loader(将文件发送到输出目录
)
webpack5 新增 [asset module type](https://www.webpackjs.com/guides/asset-modules),通过 4 种新的模块类型替代以前的 loader
```javascript
{
test: /\.(jp(e)g|png|gif)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 8 * 1024, // 8kb
},
},
generator: {
filename: "img/[name].[contenthash:8].[ext]"
},
}
```
## 开发配置 mode=development
1. 安装 webpack-dev-server
`yarn add webpack-dev-server`
2. 在 webpack.config.dev.js 定义开发所需要的配置
3. 使用 webpack-merge 工具来合并 webpack.config.base.js 中的公共配置,将 dev 配置和公共配置合并导出
4. 在 package.json 文件的 script 属性中配置指令
```json
"scripts": {
"dev": "webpack serve -c config/webpack.config.dev.js"
}
```
5. HMR
使用 webpack 插件 [react-refresh-webpack-plugin](https://github.com/pmmmwh/react-refresh-webpack-plugin) 实现
## 生产配置 mode=production
当 mode 定义为 production 时,webpack 会自动给我们做一些代码压缩和 tree shaking 等操作,可以自己再对编译出来的 js 和 css 文件进行压缩
- 使用 css-minimizer-webpack-plugin 压缩 css 资源
- 通过 terser-webpack-plugin 开启多进程并发运行以提高构建速度
- splitChunks 将 node_modules 中使用到的依赖单独打包,利用浏览器缓存策略
- 设置 output.clean 为 true 来自动删除旧的输出文件(webpack4 需要使用插件 clean-webpack-plugin)
- 配置 externals 来使用稳定可靠的 cdn 资源,提升页面加载速度,减少打包出来的 bundle 体积,
1. js/css 压缩
```bash
yarn add css-minimizer-webpack-plugin@5.0.1 terser-webpack-plugin
```
```javascript
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const prodConfig = {
optimization: {
minimizer: [
new CssMinimizerWebpackPlugin(),
new TerserWebpackPlugin({
parallel: true,
}),
],
},
};
```
2. 分包
```javascript
const prodConfig = {
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
filename: "[name].bundle.js",
},
},
},
},
};
```
3. externals
webpack 配置中定义 externals,告诉 webpack 当遇到 react、react-dom 时,不要将其打包,期望在**全局环境**中找到 React、ReactDOM 的配置
```
const prodConfig = {
externals: {
react: "React",
"react-dom": "ReactDOM",
},
};
```
在 index.html 页面引入 react、react-dom
```
```
## Tailwind CSS
1. 安装 Tailwind CSS `yarn add tailwindcss`
2. 创建 Tailwind CSS 配置文件 `npx tailwindcss init`
3. 添加 Tailwind CSS 到 PostCSS 配置中
```javascript
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env", "tailwindcss"],
},
},
}
```
4. 配置模版路径
```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{jsx,js}"],
theme: {
extend: {},
},
plugins: [],
};
```
5. 添加 Tailwind CSS 指令到 CSS 文件
```CSS
/* index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
```
- **基础类(Base)**:定义了基本的样式规则,如 margin、padding、color、font-size 等。
- **组件类(Components)**:用于创建可复用的样式块,例如按钮、卡片等。
- **实用工具类(Utilities)**:包含了 Tailwind 的大部分功能,如布局、flex、grid、spacing、colors、typography、borders 等。
## 优化
### 开发环境
- [x] HMR 热替换
- [x] webpack-dev-server 本地服务器
- [x] soure-map 调试
- [ ] webpack-bundle-analyzer 打包生成代码块分析视图
- [ ] size-plugin 监控打包资源的体积变量化
- [ ] speed-measure-webpack-plugin 分析 loader 和 plugin 打包的耗时
### 生产环境
- [x] mini-css-extract-plugin css 提取
- [x] css-minimizer-webpack-plugin css 压缩
- [x] html-webpack-plugin html 压缩
- [ ] externals 排除不需要被打包的第三方
- [x] terser-webpack-plugin js 压缩
- [x] tree-shake production 模式自动开启
- [x] code-split 代码分离
- [ ] import(懒加载,预加载)
- [ ] 多线程打包
- [ ] dll 动态链
- [ ] babel 缓存
- [x] include、exclude 排除一些不需要编译的文件
## vite
### 安装依赖
```bash
# 安装vite
yarn add vite@4.3.0 -D
# 安装react、react-dom
yarn add react react-dom
# 安装vite插件
# @vitejs/plugin-react 提供对 React 的支持,包括 JSX 转换、热模块替换(HMR)等功能
yarn add @vitejs/plugin-react -D
# 兼容低版本浏览器,生成传统版本的 chunk 及与其相对应 ES 语言特性方面的 polyfill
yarn add @vitejs/plugin-legacy@3.0.0-alpha.0 -D
```
### vite.config.js
```javascript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
const path = require("path");
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
});
```
### 入口文件
```html
react18-webpack5-demo
```
### 产出实现 file 协议预览
```bash
node scripts/build.cjs
```
### Tailwind CSS
1. 安装 Tailwind CSS `yarn add tailwindcss`
2. 创建 Tailwind CSS 配置文件 `npx tailwindcss init`
3. 添加 Tailwind CSS 到 vite 配置中
```javascript
import tailwindcss from "tailwindcss";
css: {
postcss: {
plugins: [tailwindcss()],
},
},
```
4. 配置模版路径(tailwind.config.js)
```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{jsx,js}"],
theme: {
extend: {},
},
plugins: [],
};
```
5. 添加 Tailwind CSS 指令到 CSS 文件
```CSS
/* index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
```