- Published on
基于Webpack5.0搭建React环境
- Authors
- Name
- 谢克成
Webpack 介绍
常识: 目前市场还在使用 v4
趋势: v5 简单很多, 性能更好 ; vite 呼声很高
相关: rollup, gulp....
知识: 入口, 出口, loaders, plugins, WDS, HMR, 生产与开发分离
扩展: 工程层面的性能( 代码打包优化, 构建速度优化 )
项目文件结构
react-cnode
├─ config
│ ├─ webpack.common.js
│ ├─ webpack.dev.js
│ └─ webpack.prod.js
├─ public
│ ├─ favicon.ico
│ └─ index.html
├─ src
│ ├─ App.jsx
│ └─ main.js
├─ README.md
├─ babel.config.json
├─ package-lock.json
└─ package.json
需要安装的包
webpack-merge
eslint-webpack-plugin
html-webpack-plugin // npm i --save-dev html-webpack-plugin
mini-css-extract-plugin
@babel/preset-env
@babel/preset-react
webpack-dev-server // 使用devServer serve命令
progress-webpack-plugin //构建,进度显示百分比%
happypack //加速构建
npm install -D babel-loader @babel/core @babel/preset-env webpack // babel编译器
eslint-plugin-react
App.jsx
import React from 'react'
function App() {
return (
<div>
<h1>hello webpack</h1>
</div>
)
}
export default App
mian.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App.jsx'
ReactDOM.render(<App></App>, document.getElementById('app'))
config/webpack.prod.js
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
module: {
rules: [
// css文件处理
{
test: /\.(sa|sc|c)ss$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'],
},
// 图片压缩
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {},
},
],
},
],
},
plugins: [
// css文件抽离 - 生产环境
new MiniCssExtractPlugin({
filename: './static/css/[name].[chunkhash].css',
chunkFilename: '[id].[chunkhash].css',
}),
new HtmlWebpackPlugin({
title: 'development',
template: './public/index.html',
favicon: './public/favicon.ico',
scriptLoading: 'blocking',
inject: 'body',
}),
],
// treeShaking
})
webpack.dev.js
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')
const ESLintPlugin = require('eslint-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: './public',
port: 9002,
hot: true,
},
plugins: [
new HtmlWebpackPlugin({
title: 'development',
template: './public/index.html',
favicon: './public/favicon.ico',
// scriptLoading: "blocking",
// inject: "body",
}),
new ESLintPlugin({
extensions: ['js', 'jsx'],
exclude: 'node_modules',
threads: false,
}),
],
module: {
rules: [
// css文件解析
{
test: /\.(sa|sc|c)ss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
// 图片解析
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
],
},
})
webpack.common.js
const path = require('path')
const ProgressPlugin = require('progress-webpack-plugin')
const HappyPack = require('happypack')
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// const {
// VueLoaderPlugin
// } = require('vue-loader')
module.exports = {
entry: {
// 文件抽离
'react-vendors': ['react', 'react-dom'],
app: {
// import: './src/index.js',
import: path.resolve(__dirname, '../src/main.js'),
dependOn: 'react-vendors',
},
},
output: {
// 要使用相对路径
filename: './static/js/[name].[chunkhash].js',
// filename: './static/js/[name].js',
path: path.resolve(__dirname, '../dist'),
// 外部服务器serve
// publicPath: '/',
clean: true,
// charset:true
chunkFilename: '[id].js',
},
plugins: [
// new BundleAnalyzerPlugin()
new HappyPack({
loaders: ['babel-loader'],
}),
new ProgressPlugin(true),
],
module: {
rules: [
// 开启多线程来加载并编译.js代码
{
test: /\.(js|jsx)$/i,
use: [
{
loader: 'happypack/loader',
options: {
threads: 3,
},
},
],
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: {
'@': path.resolve(__dirname, '../src'),
},
},
}
package.json
用到的依赖包
"devDependencies": {
"@babel/core": "^7.15.0",
"@babel/plugin-proposal-decorators": "^7.14.5",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.15.0",
"@babel/preset-react": "^7.14.5",
"babel-loader": "^8.2.2",
"eslint": "^7.32.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-webpack-plugin": "^3.0.1",
"happypack": "^5.0.1",
"html-webpack-plugin": "^5.3.2",
"progress-webpack-plugin": "^1.0.12",
"sass": "^1.37.5",
"webpack": "^5.48.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"
},
"dependencies": {
"@loadable/component": "^5.15.0",
"axios": "^0.21.1",
"css-loader": "^6.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"style-loader": "^3.2.1"
}
package.json 添加脚本命令 start 开发环境 build 是构建
"start": "webpack serve --open --config config/webpack.dev.js",
"build": "webpack --config config/webpack.prod.js"
babel 配置文件 babel.config.json
{
"presets": [
["@babel/preset-react", {}],
["@babel/preset-env", {}]
],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
["@babel/plugin-syntax-dynamic-import"]
]
}
eslint 配置
- .eslintrc.js
// 解决ESLint报错常用的五种方案
// 1、找到eslint的配置文件,修改eslint规则
// 2、使用eslint注释的方式,临时关闭对代码的检测
// 3、在webpack中找到eslint的插件或eslint-loader进行exclude
// 4、使用.eslintignore临时忽略对代码的检测
// 5、老老实实地把eslint错误的改好(建议的做法)
module.exports = {
extends: [
"eslint:recommended",
"plugin:react/recommended"
],
plugins: [ "react", "react-hooks" ],
// 指定检测选项
parserOptions: {
ecmaVersion: 6,
sourceType: "module",
ecmaFeatures: {
jsx: true
}
},
env: {
es6: true,
browser: true,
node: true
},
// 用户自定义修改ESLint规则
// ESLint检测代码有三种检测级别:error=2红色报错,warn=1黄色警告,off=0关闭这条规则。
rules: {
// "semi": 0,
// "semi": "off",
// "no-console": "error"
"react/prop-types": "off",
"react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则
"react-hooks/exhaustive-deps": "warn" // 检查 effect 的依赖
}
}