1. 初始化项目
mkdir webpack-react
cd webpack-*
npm init -y
cd webpack-*
: 用到了 glob 语法,可自行了解npm init -y
: 迅速初始化 npm 项目
2. 安装
- 下载 Webpack 基础依赖
npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin clean-webpack-plugin
webpack-dev-server
的作用:启动一个express服务器,并在内存中生产bundle文件。html-webpack-plugin
的作用:clean-webpack-plugin
: 打包前清除dist
文件夹
- 下载 babel 相关
npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react
- 下载 css相关的loader
npm i -D css-loader style-loader less less-loader
css-loader
:解析cssstyle-loader
: 将解析后的css放在style标签中,并添加到html文件
- 下载 react 相关的loader
npm i react react-dom
3. 创建 react 文件
- 在主目录下创建
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>React Title</title> </head> <body> <div id="root"></div> </body> </html>
- 在主目录下创建
src
文件夹,并在该文件夹下创建index.js
文件import React from 'react'; import ReactDOM from 'react-dom/client'; import App from '../App'; const root = document.getElementById('root'); ReactDOM.createRoot(root).render(<App />);
- 在主目录的
src
文件夹下,创建App.js
文件import React from 'react'; function App() { return ( <div>Hello World</div> ) } export default App;
4. 配置 webpack
- 在主目录下创建
webpack.config.js
文件const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { // 入口文件,webpack会首先从这里开始编译 mode: 'development', entry: { index: './src/index' }, module: { rules: [ { test: /\.(tsx?|jsx?)$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'] } }, ] }, { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' } ] }, { test: /\.less$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'less-loader' }, ] } ] }, devtool: 'inline-source-map', // 更好的追踪代码和给出错误代码的位置 // 解析-相关配置 resolve: { // 扩展名 extensions: ['.js', jsx, '.tsx', '.ts', '.less', 'css'], // 设置别名 alias: { components: path.resolve(__dirname, 'src/components/'), utils: path.resolve(__dirname, 'src/utils/'), } }, // 3000 端口打开网页 devServer: { static: './dist', port: 3000, hot: true, }, // 打包后输出的位置 output: { filename: 'index.js', path: path.resolve(__dirname, 'dist'), }, plugins: [ new HtmlWebpackPlugin({ template: './public/index.html' }), new CleanWebpackPlugin(['dist']), ] };
5. 配置 package.json
文件
{
"name": "webpack-react",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server" // 添加运行脚本
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.18.9",
"@babel/preset-env": "^7.18.9",
"@babel/preset-react": "^7.18.6",
"babel-loader": "^8.2.5",
"clean-webpack-plugin": "^4.0.0",
"css-loader": "^6.7.1",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.3",
"less-loader": "^11.0.0",
"style-loader": "^3.3.1",
"webpack": "^5.73.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.9.3"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
6. 项目添加 typescript
- 安装依赖
npm i -D typescript @babel/preset-typescript
- 安装 react的 types
npm i -D @types/react @types/react-dom
- 生成配置文件
npx tsc --init
- 然后就会在主目录下生成
tsconfig.json
文件 - 对 npx 不太熟悉的 可以看阮一峰老师的这篇文章:npx 使用教程
- 然后就会在主目录下生成
- 修改 主目录下的
tsconfig.json
文件{ "compilerOptions": { "target": "es2016", "jsx": "react", // 1. 配置 jsx "module": "commonjs", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "baseUrl": "./", // 2. 配置 baseUrl "paths": { "utils/*": ["src/utils/*"], // 3. 配置 paths "components/*": ["src/components/*"], }, }, "include": ["src/**/*"], // 4. 配置 include "exclude": ["node_modules"] // 5. 配置 exclude }
-
配置
webpack.config.js
-
解决 ts 报错
修改文件:App.js => App.tsx, src/index.js => src/index.tsx
Cannot use JSX unless the '--jsx' flag is provided
: 根目录下的tsconfig.json
文件中加入{ // ... "jsx": "react", // ... }
类型“HTMLElement | null”的参数不能赋给类型“Element | DocumentFragment”的参数。不能将类型“null”分配给类型“Element | DocumentFragment”。
:App.tsx
文件的root后加!# 找不到模块“utils/index”或其相应的类型声明”
: 配置根目录下的tsconfig.json
{ "compilerOptions": { "target": "es2016", "jsx": "react", "module": "commonjs", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "baseUrl": "./", // 1. 配置 baseUrl "paths": { "utils/*": ["src/utils/*"], // 2. 配置 paths "components/*": ["src/components/*"], }, }, "include": ["src/**/*"], // 3. include 和 exclude 也配置上 "exclude": ["node_modules"] }
-
ts的配置方式
- 项目没有配置 babel 时,选择 typescript + ts-loader
- 项目配置了 babel 时,可以使用 typescript +
@babel/preset-typescrip
,它是TypeScript 和 Babel 团队官方合作的项目 - 两种方式的webpack配置差异如下
7. 添加 eslint
- 安装
npm i -D eslint
- 配置
然后根目录下就生成了npx eslint --init You can also run this command directly using 'npm init @eslint/config' // y ✔ How would you like to use ESLint? // To check syntax, find problems, and enforce code style ✔ What type of modules does your project use? // JavaScript modules (import/export) ✔ Which framework does your project use? // react ✔ Does your project use TypeScript? // Yes ✔ Where does your code run? // browser ✔ How would you like to define a style for your project? // Use a popular style guide ✔ Which style guide do you want to follow? // Airbnb ✔ What format do you want your config file to be in? // JavaScript
.eslint.js
文件 - 解决
eslint
报错
Newline required at end of file but not found
: 换行就可以了- ``Unable to resolve path to module './App': 在
.eslintrc.json
中添加rules
设置{ rules: { 'import/no-unresolved': 0, 'import/extensions': 0, 'import/no-absolute-path': 0, }, };
JSX not allowed in files with extension '.tsx'
: 在.eslintrc.json
中添加rules
设置{ 'react/jsx-filename-extension': [ 2, { extensions: ['.js', '.jsx', '.tsx', '.ts'], }, ], }
- 配置
package.json
{ "scripts": { "start": "webpack-dev-server", "build": "webpack build", "eslint": "eslint --ext .js,.jsx,ts,.tsx src" /* 添加 eslint 脚本 */ }, }
- 运行
npm run lint
8. 添加 prettier
-
安装
npm i -D prettier eslint-config-prettier eslint-plugin-prettier
- prettier: 核心模块
- eslint-config-prettier: 关闭所有不必要或可能跟prettier产生冲突的规则
- eslint-plugin-prettier: 可以让eslint使用prettier规则进行检查
-
配置
根目录下
.eslintrc.js
文件中添加extends
设置{ // ... "extends": [ // ... 'plugin:prettier/recommended' ], }
根目录下创建
.prettierrc.json
文件{ "printWidth": 80, "tabWidth": 2, "semi": true, "singleQuote": true, "trailingComma": "none" }
注意⚠️:
- 修改
.prettierrc.json
文件后,需要重启vscode才生效 - 如果配置后,配置不生效,尝试以下设置:
- 修改
9. 添加 husky
和lint-staged
-
安装
npm i -D lint-staged husky
-
配置
-
在
package.json
中添加脚本npm set-script prepare "husky install"
package.json
文件的scripts
中,就会自动添加prepare
; -
初始化husky,将 git hooks钩子交由husky执行
npm run prepare
会在根目录创建
.husky
文件夹 -
配置
package.json
- 添加钩子
pre-commit
npx husky add .husky/pre-commit "npx lint-staged"
package.json
文件如下{ "name": "webpack-react", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "webpack-dev-server", "build": "webpack build", "eslint": "eslint --ext .js,.jsx,ts,.tsx src", "prepare": "husky install", "lint": "lint-staged" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "@babel/core": "^7.18.9", "@babel/preset-env": "^7.18.9", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.18.6", "@types/react": "^18.0.15", "@types/react-dom": "^18.0.6", "@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/parser": "^5.30.7", "babel-loader": "^8.2.5", "clean-webpack-plugin": "^4.0.0", "css-loader": "^6.7.1", "eslint": "^8.20.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^8.5.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jsx-a11y": "^6.6.0", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "html-webpack-plugin": "^5.5.0", "husky": "^8.0.1", "less": "^4.1.3", "less-loader": "^11.0.0", "lint-staged": "^13.0.3", "prettier": "^2.7.1", "style-loader": "^3.3.1", "typescript": "^4.7.4", "webpack": "^5.73.0", "webpack-cli": "^4.10.0", "webpack-dev-server": "^4.9.3" }, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "lint-staged": { "src/**": "eslint" } }
-
10. 配置commitlint
-
作用:规范提交信息
-
格式:
git commit -m '类型: 描述性文字'
类型 概念 build 编译相关的修改,例如发布版本、对项目构建或者依赖的改动 ci 持续集成修改 docs 文档修改 feat 新特性、新功能 fix 修改bug perf 优化相关,比如提升性能、体验 refactor 代码重构 revert 回滚到上一个版本 style 代码格式修改, 注意不是 css 修改 test 测试用例修改 chore 其他修改,比如改变构建流程、或者增加依赖库、工具等 -
安装
npm i -D commitlint @commitlint/config-conventional
复制代码
- 配置
package.json
中配置commitlint
{
// ...
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
}
}
复制代码
- 添加钩子
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
git commit
就会触发提交规范的校验;