一、初始化项目
- 1、初始化package.json
// 生成package.json
npm init
项目中新增目录结构和文件
├── 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
- 2、安装依赖
npm i webpack webpack-cli -D
npm i react react-dom -S
npm i @types/react @types/react-dom -D
- 3、添加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>
- 4、添加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"]
}
- 5、添加src/App.tsx内容
import React from 'react'
function App() {
return <h2>webpack5-react-ts</h2>
}
export default App
- 6、添加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 />)
}
二、配置环境
2.1 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、配置loader解析ts和jsx 由于webpack默认只能识别js文件,不能识别jsx语法,需要配置loader的预设预设 [ @babel/preset-typescript]来先ts语法转换为 js 语法,再借助预设 [ @babel/preset-react] 来识别jsx语法。
npm i babel-loader @babel/core @babel/preset-react @babel/preset-typescript -D
在webpack.base.js添加module.rules配置
// webpack.base.js
module.exports = {
// ...
module: {
rules: [
{
test: /.(ts|tsx)$/, // 匹配.ts, tsx文件
use: {
loader: 'babel-loader',
options: {
// 预设执行顺序由右往左,所以先处理ts,再处理jsx
presets: [
'@babel/preset-react',
'@babel/preset-typescript'
]
}
}
}
]
}
}
- 4、配置extensions
extensions是webpack的resolve解析配置下的选项,在引入模块时不带文件后缀时,会来该配置数组里面依次添加后缀查找文件,因为ts不支持引入以 .ts, tsx为后缀的文件,所以要在extensions中配置,而第三方库里面很多引入js文件没有带后缀,所以也要配置下js
修改webpack.base.js,(把高频出现的文件后缀放在前面)
// webpack.base.js
module.exports = {
// ...
resolve: {
extensions: ['.js', '.tsx', '.ts'],
}
}
这里只配置js, tsx和ts,其他文件引入都要求带后缀,可以提升构建速度。
- 5、添加html-webpack-plugin插件
npm i html-webpack-plugin -D
// 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, // 自动注入静态资源
})
]
}
2.2 webpack开发环境配置
- 1、安装webpack-dev-server 开发环境配置代码在webpack.dev.js中,借助webpack-dev-server在开发环境启动服务器来辅助开发,还需要依赖webpack-merge来合并基本配置。
npm 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文件夹
}
}
})
- 2、package.json添加dev脚本
// package.json
"scripts":{
"dev":"webpack-dev-server -c build/webpack.dev.js"
}
2.3webpack打包环境配置
- 1、修改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和压缩代码,以及其他优化
})
- 2、package.json添加build打包命令脚本
// package.json
"scripts":{
"dev":"webpack-dev-server -c build/webpack.dev.js",
“build”:"webpack -c build/webpack.prod.js"
}
- 3、浏览器查看打包结果
打包后的dist文件可以在本地借助node服务器server打开,安装
npm i serve -g,然后在项目根目录命令行执行serve -s dist,就可以启动打包后的项目。
三、基础功能配置
3.1配置环境变量
环境变量分两种:
- 开发模式还是打包构建模式
- 项目业务环境,开发/测试/预发布/正式
开发模式还是打包构建模式可以用process.env.NODE_ENV,
项目接口环境可以自定义一个环境变量process.env.BASE_ENV,设置环境变量可以借助cross-env和webpack.DefinePlugin来设置
- cross-env:兼容各系统的设置环境变量的包
- webpack.DefinePlugin:webpack内置的插件,为业务代码注入环境变量
安装cross-env
npm i cross-env -D
修改package.json的script脚本字段,删除原来的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",
},
dev开头是开发模式,build开头是打包模式,冒号后面对应的dev/test/pre/prod是对应的业务环境的开发/测试/预测/正式环境。
process.env.NODE_ENV环境变量webpack会自动根据设置的mode字段来给业务代码注入对应的development和prodction,这里在命令中再次设置环境变量NODE_ENV是为了在webpack和babel的配置文件中访问到。
修改webpack.base.js
// webpack.base.js
// ...
const webpack = require('webpack')
module.export = {
// ...
plugins: [
// ...
new webpack.DefinePlugin({
'process.env.BASE_ENV': JSON.stringify(process.env.BASE_ENV)
})
]
}
3.2 处理css和less文件
安装loader解析CSS,为了更好的开发体验,一般会使用css超集less或scss。
npm i style-loader css-loader less -D
- style-loader:把解析后的css代码从js中抽离,放到头部style标签中
- css-loader:解析css文件代码
解析css的配置开发和打包环境都会用到,需要在webpack.base.js中添加配置
// webpack.base.js
// ...
module.exports = {
// ...
module: {
rules: [
// ...
{
test:/.(css|less)&/, //匹配 css 文件
use: ['style-loader','css-loader','less-loader']
}
]
},
// ...
}
loader执行顺序是从右往左,从下往上的,匹配到css文件后先用css-loader解析css, 最后借助style-loader把css插入到头部style标签中。
3.3 处理CSS3前缀兼容
借助插件自动添加前缀,postcss-loader
安装依赖:
npm i postcss-loader autoprefixer -D
- postcss-loader:处理css时自动加前缀
- autoprefixer:添加哪些浏览器前缀到css中
修改webpack.base.js,解析css和less的规则中添加配置
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /.(css|less)$/, //匹配 css和less 文件
use: [
'style-loader',
'css-loader',
// 新增
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['autoprefixer']
}
}
},
'less-loader'
]
}
]
},
// ...
}
配置完成后,需要一份兼容浏览器的清单,让postcss-loader知道要加哪些浏览器的前缀,在根目录创建.browserslistrc文件
IE 9 #兼容IE 9
chrome 35 #兼容chrome 35
postcss.config.js是postcss-loader的配置文件,会自动读取配置,根目录新建postcss.config.js
module.exports = {
plugins:['autoprefixer']
}
修改webpack.base.js,取消postcss-loader的options配置
// webpack.base.js
// ...
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /.(css|less)$/, //匹配 css和less 文件
use: [
'style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
]
},
// ...
}
3.4babel预设处理js兼容
安装依赖:
npm i babel-loader @babel/core @babel/preset-env core-js -D
-
babel-loader: 使用 babel 加载最新js代码并将其转换为 ES5(上面已经安装过)
-
@babel/corer: babel 编译的核心包
-
@babel/preset-env: babel 编译的预设,可以转换目前最新的js标准语法
-
core-js: 使用低版本js语法模拟高版本的库,也就是垫片
修改webpack.base.js
// webpack.base.js
module.exports = {
// ...
module: {
rules: [
{
test: /.(ts|tsx)$/,
use: {
loader: 'babel-loader',
options: {
// 执行顺序由右往左,所以先处理ts,再处理jsx,最后再试一下babel转换为低版本语法
presets: [
[
"@babel/preset-env",
{
// 设置兼容目标浏览器版本,这里可以不写,babel-loader会自动寻找上面配置好的文件.browserslistrc
// "targets": {
// "chrome": 35,
// "ie": 9
// },
"useBuiltIns": "usage", // 根据配置的浏览器兼容,以及代码中使用到的api进行引入polyfill按需添加
"corejs": 3, // 配置使用core-js低版本
}
],
'@babel/preset-react',
'@babel/preset-typescript'
]
}
}
}
]
}
}
避免webpack配置文件过于庞大,可以把babel-loader的配置抽离出来, 新建babel.config.js文件,使用js作为配置文件,是因为可以访问到process.env.NODE_ENV环境变量来区分是开发还是打包模式。
// babel.config.js
module.exports = {
// 执行顺序由右往左,所以先处理ts,再处理jsx,最后再试一下babel转换为低版本语法
"presets": [
[
"@babel/preset-env",
{
// 设置兼容目标浏览器版本,这里可以不写,babel-loader会自动寻找上面配置好的文件.browserslistrc
// "targets": {
// "chrome": 35,
// "ie": 9
// },
"useBuiltIns": "usage", // 根据配置的浏览器兼容,以及代码中使用到的api进行引入polyfill按需添加
"corejs": 3 // 配置使用core-js使用的版本
}
],
"@babel/preset-react",
"@babel/preset-typescript"
]
}
移除webpack.base.js中babel-loader的options配置
// webpack.base.js
module.exports = {
// ...
module: {
rules: [
{
test: /.(ts|tsx)$/,
use: 'babel-loader'
},
// 如果node_moduels中也有要处理的语法,可以把js|jsx文件配置加上
// {
// test: /.(js|jsx)$/,
// use: 'babel-loader'
// }
// ...
]
}
}
```
```
```
```
```
```
```
```