一. 搭建基础开发环境
2.1 前置工作
本章节将按照 entry,output,loader,plugin,其他配置 的顺序带大家搭建一个基础的React开发环境。在正式开始之前我们先做好如下前置工作:
版本:
node:16.20.1
webpack:5.89.0
react:18.2.0
步骤1: 安装 webpack 与 webpack-cli
pnpm i webpack webpack-cli -D
在开始webpack配置之前,先手动初始化一个基本的react+ts项目,新建项目文件夹webpack5-react-18, 在项目下执行
pnpm init -y
初始化好package.json后,在项目下新增以下所示目录结构和文件
├── build
| ├── webpack.base.js # 公共配置
| ├── webpack.dev.js # 开发环境配置
| └── webpack.prod.js # 打包环境配置
├── public
│ └── index.html # html模板
├── src
| ├── App.tsx
│ └── index.tsx # react应用入口页面
├── tsconfig.json # ts配置
└── package.json
安装webpack依赖
pnpm i webpack webpack-cli -D
安装react依赖
pnpm i react react-dom -S
安装react类型依赖
pnpm i @types/react @types/react-dom -D
添加public/index.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>webpack5-react-ts</title>
</head>
<body>
<!-- 容器节点 -->
<div id="root"></div>
</body>
</html>
添加tsconfig.json内容
{
"compilerOptions": {
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react", // react18这里也可以改成react-jsx
},
"include": ["./src"]
}
添加src/App.tsx内容
import React from 'react'
function App() {
return <h2>webpack5-react-ts</h2>
}
export default App
添加src/index.tsx内容
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
const root = document.getElementById('root');
if(root) {
createRoot(root).render(<App />)
}
配置基础版React+ts环境
webpack公共配置
修改webpack.base.js
1. 配置入口文件
// webpack.base.js
const path = require('path')
module.exports = {
entry: path.join(__dirname, '../src/index.tsx'), // 入口文件
}
2、 配置出口文件
// webpack.base.js
const path = require('path')
module.exports = {
// ...
// 打包文件出口
output: {
filename: 'static/js/[name].js', // 每个输出js的名称
path: path.join(__dirname, '../dist'), // 打包结果输出路径
clean: true, // webpack4需要配置clean-webpack-plugin来删除dist文件,webpack5内置了
publicPath: '/' // 打包后文件的公共前缀路径
},
}
3、配置extensions
extensions是webpack的resolve解析配置下的选项,在引入模块时不带文件后缀时,会来该配置数组里面依次添加后缀查找文件,因为ts不支持引入以 .ts, tsx为后缀的文件,所以要在extensions中配置,而第三方库里面很多引入js文件没有带后缀,所以也要配置下js
修改webpack.base.js,注意把高频出现的文件后缀放在前面
// webpack.base.js
module.exports = {
// ...
resolve: {
extensions: ['.js', '.tsx', '.ts'],
}
}
4、添加html-webpack-plugin插件
webpack需要把最终构建好的静态资源都引入到一个html文件中,这样才能在浏览器中运行,html-webpack-plugin就是来做这件事情的,安装依赖:
pnpm i html-webpack-plugin -D
因为该插件在开发和构建打包模式都会用到,所以还是放在公共配置webpack.base.js里面
// webpack.base.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// ...
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html'), // 模板取定义root节点的模板
inject: true, // 自动注入静态资源
})
]
}
到这里一个最基础的react基本公共配置就已经配置好了,需要在此基础上分别配置开发环境和打包环境了
webpack开发环境配置
1. 安装 webpack-dev-server
开发环境配置代码在webpack.dev.js中,需要借助 webpack-dev-server在开发环境启动服务器来辅助开发,还需要依赖webpack-merge来合并基本配置,安装依赖
pnpm i webpack-dev-server webpack-merge -D
修改webpack.dev.js代码, 合并公共配置,并添加开发模式配置
// webpack.dev.js
const path = require('path')
const { merge } = require('webpack-merge')
const baseConfig = require('./webpack.base.js')
// 合并公共配置,并添加开发环境配置
module.exports = merge(baseConfig, {
mode: 'development', // 开发模式,打包更加快速,省了代码优化步骤
devtool: 'eval-cheap-module-source-map', // 源码调试模式,后面会讲
devServer: {
port: 3000, // 服务端口号
compress: false, // gzip压缩,开发环境不开启,提升热更新速度
hot: true, // 开启热更新,后面会讲react模块热替换具体配置
historyApiFallback: true, // 解决history路由404问题
static: {
directory: path.join(__dirname, "../public"), //托管静态资源public文件夹
}
}
})
package.json添加dev脚本
在package.json的scripts中添加
// package.json
"scripts": {
"dev": "webpack-dev-server -c build/webpack.dev.js"
},
修改webpack.prod.js代码
// webpack.prod.js
const { merge } = require('webpack-merge')
const baseConfig = require('./webpack.base.js')
module.exports = merge(baseConfig, {
mode: 'production', // 生产模式,会开启tree-shaking和压缩代码,以及其他优化
})
package.json添加build打包命令脚本
"scripts": {
"dev": "webpack-dev-server -c build/webpack.dev.js",
"build": "webpack -c build/webpack.prod.js"
},
基础功能配置
配置环境变量
环境变量按作用来分分两种
- 区分是开发模式还是打包构建模式
- 区分项目业务环境,开发/测试/预测/正式环境
区分开发模式还是打包构建模式可以用process.env.NODE_ENV,因为很多第三方包里面判断都是采用的这个环境变量。
区分项目接口环境可以自定义一个环境变量process.env.BASE_ENV,设置环境变量可以借助cross-env和webpack.DefinePlugin来设置。
cross-env:兼容各系统的设置环境变量的包
webpack.DefinePlugin:webpack内置的插件,可以为业务代码注入环境变量
安装cross-env
pnpm i cross-env -D
修改package.json的scripts脚本字段,删除原先的dev和build,改为
"scripts": {
"dev:dev": "cross-env NODE_ENV=development BASE_ENV=development webpack-dev-server -c build/webpack.dev.js",
"dev:test": "cross-env NODE_ENV=development BASE_ENV=test webpack-dev-server -c build/webpack.dev.js",
"dev:pre": "cross-env NODE_ENV=development BASE_ENV=pre webpack-dev-server -c build/webpack.dev.js",
"dev:prod": "cross-env NODE_ENV=development BASE_ENV=production webpack-dev-server -c build/webpack.dev.js",
"build:dev": "cross-env NODE_ENV=production BASE_ENV=development webpack -c build/webpack.prod.js",
"build:test": "cross-env NODE_ENV=production BASE_ENV=test webpack -c build/webpack.prod.js",
"build:pre": "cross-env NODE_ENV=production BASE_ENV=pre webpack -c build/webpack.prod.js",
"build:prod": "cross-env NODE_ENV=production BASE_ENV=production webpack -c build/webpack.prod.js",
},
处理css和less文件
在src下新增app.css
h2 {
color: red;
transform: translateY(100px);
}
在src/App.tsx中引入app.css
import React from 'react'
import './app.css'
function App() {
return <h2>webpack5-rea11ct-ts</h2>
}
export default App
执行打包命令pnpm run build:dev,会发现有报错, 因为webpack默认只认识js,是不识别css文件的,需要使用loader来解析css, 安装依赖
pnpm i style-loader css-loader -D
style-loader: 把解析后的css代码从js中抽离,放到头部的style标签中(在运行时做的)
css-loader: 解析css文件代码
因为解析css的配置开发和打包环境都会用到,所以加在公共配置webpack.base.js中
// webpack.base.js
// ...
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /\.css$/, //匹配 css 文件
use: ['style-loader','css-loader']
}
]
},
// ...
}
优化构建速度
构建耗时分析
当进行优化的时候,肯定要先知道时间都花费在哪些步骤上了,而speed-measure-webpack-plugin插件可以帮我们做到,安装依赖:
pnpm i speed-measure-webpack-plugin -D
使用的时候为了不影响到正常的开发/打包模式,我们选择新建一个配置文件,新增webpack构建分析配置文件build/webpack.analy.js
const prodConfig = require('./webpack.prod.js') // 引入打包配置
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); // 引入webpack打包速度分析插件
const smp = new SpeedMeasurePlugin(); // 实例化分析插件
const { merge } = require('webpack-merge') // 引入合并webpack配置方法
// 使用smp.wrap方法,把生产环境配置传进去,由于后面可能会加分析配置,所以先留出合并空位
module.exports = smp.wrap(merge(prodConfig, {
}))
修改package.json添加启动webpack打包分析脚本命令,在scripts新增:
{
// ...
"scripts": {
// ...
"build:analy": "cross-env NODE_ENV=production BASE_ENV=production webpack -c build/webpack.analy.js"
}
// ...
}
开启持久化存储缓存
在webpack5之前做缓存是使用babel-loader缓存解决js的解析结果,cache-loader缓存css等资源的解析结果,还有模块缓存插件hard-source-webpack-plugin,配置好缓存后第二次打包,通过对文件做哈希对比来验证文件前后是否一致,如果一致则采用上一次的缓存,可以极大地节省时间。
webpack5 较于 webpack4,新增了持久化缓存、改进缓存算法等优化,通过配置 webpack 持久化缓存,来缓存生成的 webpack 模块和 chunk,改善下一次打包的构建速度,可提速 90% 左右,配置也简单,修改webpack.base.js
// webpack.base.js
// ...
module.exports = {
// ...
cache: {
type: 'filesystem', // 使用文件缓存
},
}
开启多线程loader
webpack的loader默认在单线程执行,现代电脑一般都有多核cpu,可以借助多核cpu开启多线程loader解析,可以极大地提升loader解析的速度,thread-loader就是用来开启多进程解析loader的,安装依赖
pnpm i thread-loader -D
使用时,需将此 loader 放置在其他 loader 之前。放置在此 loader 之后的 loader 会在一个独立的 worker 池中运行。
修改webpack.base.js
// webpack.base.js
module.exports = {
// ...
module: {
rules: [
{
test: /.(ts|tsx)$/,
use: ['thread-loader', 'babel-loader']
}
]
}
}
配置alias别名
webpack支持设置别名alias,设置别名可以让后续引用的地方减少路径的复杂度。
修改webpack.base.js
module.export = {
// ...
resolve: {
// ...
alias: {
'@': path.join(__dirname, '../src')
}
}
}
修改tsconfig.json,添加baseUrl和paths
{
"compilerOptions": {
// ...
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
}
}
}
src/App.tsx可以修改为
import React from 'react'
import smallImg from '@/assets/imgs/5kb.png'
import bigImg from '@/assets/imgs/22kb.png'
import '@/app.css'
import '@/app.less'
function App() {
return (
<>
<img src={smallImg} alt="小于10kb的图片" />
<img src={bigImg} alt="大于于10kb的图片" />
<div className='smallImg'></div> {/* 小图片背景容器 */}
<div className='bigImg'></div> {/* 大图片背景容器 */}
</>
)
}
export default App
总结
理解模块化:Webpack是一个模块打包工具,可以将多个模块打包成一个或多个文件,方便开发者调用。
掌握配置文件:Webpack的配置文件(webpack.config.js)允许自定义打包规则,满足项目的特定需求。
熟悉Loader和Plugin:Loader用于处理模块的加载,Plugin用于扩展Webpack的功能。了解常见的Loader和Plugin,如Babel Loader、CSS Loader等。
掌握代码拆分:代码拆分可以将大型项目分成多个较小的包,提高应用的加载性能。
学习热更新:Webpack支持热更新技术,允许在开发过程中实时查看代码修改后的效果,提高开发效率。
学习React:
理解组件化思想:React提倡将页面拆分成多个独立的、可复用的组件,从而提高代码的可维护性和可扩展性。
了解路由:学习如何使用React Router实现单页面应用的路由功能。
编写脚手架:
掌握脚手架概念:脚手架是一种用于搭建和管理项目的工具,可以帮助开发者快速启动项目、统一项目规范等。
学会使用常见脚手架框架:如Jest、Express、Babel等,搭建项目结构。
熟悉脚手架配置:根据项目需求,配置相关插件和加载器,提高开发效率。
webpack和react是现代前端开发的核心技术。编写脚手架则有助于提高开发效率、规范项目结构。接下来,可以尝试结合实际项目,运用所学知识进行开发,不断提升自己的技能水平。
最后,分享本人分享在gitee上的一个完整的脚手架WNanXuan/webpackFrame