久在樊笼里,复得返自然。
随着前端的发展,前端工程化 早已不是一个新鲜的话题了,这个赛道已经成熟到 react 都不在自己文档中提自己的 create-react-app
了。而我在工作之后使用最多的便是 umijs
,它有一套完整工程化体系,在项目初期基本上不需要时间成本上手,可以立即开展业务迭代。轮子用久了,都不会走路了 , 前不久打算写一个组件库,正好复习一下 webpack 工程。
工程结构

整个工程项目包含三部分:业务代码 ,静态检查 和 打包工具 。业务代码由最基本的三件套即 react , typescript , css 组成,静态检查则由 eslint 负责,最后由 webpack 负责打包。
项目配置
package.json
因为是个最简单的 react 应用,甚至不涉及路由部分,因此只有两个 dependencies
:
json
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
devDependencies
涉及较多依赖,部分安装依赖解释如下:
- @types/react , @types/react-dom:react的类型定义
- typescript:指定项目的 typescript 版本
- @babel/core ,@babel/preset-env:babel 的核心配置
- ts-node :解决后缀名是
.ts
的 webpack 编译 - webpack ,webpack-dev-server ,webpack-cli:webpack 的依赖
webpack 配置
项目根目录新建 public/index.html 用来配合 webpack-dev-server。
在项目的根目录新建 webpack 目录用来存放 webpack 的配置文件,新建 webpack/webpack.dev.config.ts 作为开发调试项目的配置。
ts
import path from 'path';
import type { Configuration } from 'webpack';
import webpackBor from 'webpackbar'
const rootPath = path.join(__dirname,'../');
const webpack: Configuration = {
//* 模式
mode: 'development',
//* 主入口文件
entry: './src/index.tsx',
//* 输出文件
//! 暂时不考虑拆包
// todo
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
resolve: {
//* 解析文件的优先级 ts > tsx > js > jsx
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
//* 处理模块对应的不同 loader
module: {
rules: [
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
],
},
//* dev server 相关配置
//@ts-ignore
devServer: {
static: path.join(rootPath, 'public'),
port: 3000,
open: true,
client: {
overlay: true, //* 增加 overlay
progress: true, //* 增加进度条
}
},
//* 关闭 webpack 编译的产物日志,只保留错误的
stats: "errors-only",
//* 增加 webpack 打包编译条
plugins: [
new webpackBor({
basic: true,
profile: false
})
]
}
export default webpack
其中 babel-loader
用来处理 ts -> js ,css-loader
用来解析处理 css 文件,style-loader
则是用来渲染 css 样式。 webpackBar
则是一个显示webpack打包进度的插件😏,效果如下

babel 配置
json
{
"presets": [
[
"@babel/preset-env", //* babel 的预设,必须包含 corejs
{
"browserslistEnv": "> 0.25%, not dead",
"useBuiltIns": "usage",
"corejs": "3"
}
],
[
"@babel/preset-react", //* 一些 react 的预设,若不想 import react 需将 runtime 置为 automatic
{
"runtime": "automatic"
}
],
[
"@babel/preset-typescript"
]
]
}
一些小坑
在 react 的 17 版本后,新的 JSX 转换不再依赖 React 环境,在转换时会自动引入react 的 runtime,体现在代码上的便是少了这一行代码
tsx
import React from 'react;
但是在 babel 中,如果不加 "runtime": "automatic"(默认是 classic)
则不会自动导入 jsx 的 runtime 函数,结果就是项目会出现 React is not defined 的错误
eslint 配置
js
/* eslint-disable no-undef */
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
},
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
"plugin:react/recommended",
"plugin:react/jsx-runtime"
],
rules: {
"@typescript-eslint/ban-ts-comment": "off", //! 关闭 ts-check 确保可以写一些 后门
},
};
之前习惯写 ts-ignore(见上图) , 但在最新的规则里面是不允许直接写的😶🌫️(这里就偷个懒,对如果是团队项目推荐开启,关了不利于 review)
tsconfig.json
json
{
"compilerOptions": {
"target": "ES6",
"module": "ES6",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"jsx": "react-jsx",
"importHelpers": true,
"sourceMap": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "bundler"
},
"ts-node": {
"compilerOptions": {
"module": "CommonJS",
"allowSyntheticDefaultImports": true
}
},
"include": [
"./src/**/*",
"./webpack"
],
"exclude": [
"node_modules",
"./webpack/dist/**/*",
".eslintrc.js"
]
}
其中 ts-node 的相关配置是为了解决 webpack 自身没法识别 .ts 后缀文件
一点趣事
在配置 tsconfig 的时候,由于我想使用自动转换 react,即每个文件都不引入 react,需要把 "jsx":"react" 这项配置改成 "jsx":"react-jsx"。但改了之后所有的 html 的 jsx 标签会报这个错

查阅百度发现需要把 jsx 这项配置改成 "jsx":"react" 死循环了属于是🤺。
其实将 moduleResolution 这个配置改成 moduleResolution:"bundler" 就可以了
启动命令
在 package.json 中增加调试脚本:
json
"scripts": {
"start": "webpack serve --config webpack/webpack.dev.config.ts"
},

项目成果跑起来,完结撒花 ~🎉🎉🎉
hi, there👋
i am siroi
一个接触前端 2.5 年的新人,欢迎关注我的微信公众号:siroi的前端手册
让我们一起愉快的玩耍吧🤓