webpack5
Recently, I finally had time and energy to focus on the company’s technical infrastructure, so at the beginning, the company’s Saas
system was transformed into a micro front-end model, which solved some of the problems left over from history.
Then, thinking that webpack5
has been released for so long, it should be used in the production environment, and I also want to promote micro front end,
webpack5
, vite
in the industry. Friends who have not read my previous article can find it at the end of the article. There are a lot of dry goods
Officially begin
What changes have been made after webpack5 is upgraded?
- Improve performance through persistent caching
- Adopt better persistent caching algorithm and default behavior
- Reduce Bundle size by optimizing Tree Shaking and code generation (get rid of nodejs polyfill)
- Improve the compatibility of the web platform
- To clear the unreasonable state caused by no incompatibility changes in Webpack4 before
- Try to introduce major changes now to prepare for future features so that we can use Webpack 5 for as long as possible
Added Module Federation (Federal Module)
Build guide
I recommend that you use the scaffolding I made in our company (
Shenzhen Mingyuan Cloud Space) to generate project templates with one click, so that everyone will get better upgrades when reading this article
Steps to generate template:
npm i ykj-cli -g
ykj init webpack5 (这里选择通用项目模板)
cd webpack5
yarn
yarn dev
Start building
First create a new folder, use yarn to initialize the project
mkdir webpack5-demo cd webpack5-demo yarn init webpack5-demo ...一路回车
Download the latest version of
webpack webpack-cli
yarn add webpack@next webpack-cli@next -D
Then install the
React react-dom
17 version of the libraryyarn add react@17.0.0 react-dom@17.0.0 --save
- Then install the libraries recommended by the official hot update of
react
yarn add react-refresh -D
- Install
less css style tag postcss and other style processing libraries (
mini-css-extract-plugin
to install@next
version)
yarn add less less-loader css-loader style-loader mini-css-extract-plugin@next -D
Installation related
babel
dependenciesyarn add core-js@3.9.0 @babel/core@next babel-loader@next @babel/preset-env@next -D
babel
What are the specific configurations, I suggest you refer to my template
Completed the preparatory work for dependencies and started to build the project
- Create a 061036b411c1d3 folder in the project root directory to
config
webpack
configuration file Create four new files under the
config
paths.js//存放路径 webpack.base.js //基础配置 webpack.dev.js//开发配置 webpack.prod.js//生产配置
In the
paths
file, use variables to record several key directories:const path = require('path'); module.exports = { // 源码目录 src: path.resolve(__dirname, '../src'), // 构建后的资源产物文件夹 build: path.resolve(__dirname, '../dist'), // 静态资源 public: path.resolve(__dirname, '../public'), };
Write the basic
webpack.base.js
configuration file and introduce dependencies//webpack.base.js const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const path = require('path'); const paths = require('./paths');
Write the
entry
andoutput
fields:entry: paths.src + 'index.tsx', output: { path: path.resolve(__dirname, '../dist'), filename: '[name].[contenthash].js', publicPath: '', },
It should be noted here that
webpack5
thecontenthash
algorithm, here you can choose one ofchunkhash
andcontenthash
contenthash
Write the basic
loader
configuration:module: { rules: [ { use: 'babel-loader', test: /\.(ts|tsx)$/, exclude: /node_modules/, }, { use: ['style-loader', 'css-loader', 'less-loader'], test: /\.(css|less)$/, }, { type: 'asset', test: /\.(png|svg|jpg|jpeg|gif)$/i, }, ], },
Note here:
webpack5
For resources, similar: pictures, font files, etc., you can use the built-inasset
to process, instead ofurl-loader
andfile-loader
Next, because the project needs to configure the alias and omit the suffix name, we first configure the
resolve
field (I am the TypeScript+React technology stack):resolve: { extensions: ['.ts', '.tsx', '.js', '.json', '.jsx'], alias: { '@': paths.src, '@c': paths.src + '/components', '@m': paths.src + '/model', '@s': paths.src + '/services', '@t': paths.src + '/types', }, },
For plug-ins, since it is a basic configuration, only one plug-in of
clean、html
plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: './public/index.html', }), ],
babel.config.js
in the project root directoryconst { argv } = require('yargs'); const isDev = argv.mode === 'development'; const plugins = [ [ 'const-enum', { transform: 'constObject', }, ], 'lodash', '@babel/plugin-transform-runtime', //支持import 懒加载 '@babel/plugin-syntax-dynamic-import', '@babel/plugin-transform-async-to-generator', 'transform-class-properties', [ 'import', { libraryName: 'antd', libraryDirectory: 'es', style: true, // or 'css' }, 'antd', ], [ 'import', { libraryName: 'ykj-ui', libraryDirectory: 'lib/components', style: true, // or 'css' }, 'ykj-ui', ], ]; module.exports = (api) => { api.cache(true); return { presets: [ [ '@babel/preset-env', { corejs: 3.9, useBuiltIns: 'usage', }, ], [ '@babel/preset-react', { runtime: 'automatic', }, ], '@babel/preset-typescript', ], plugins: isDev ? [...plugins, 'react-refresh/babel'] : [...plugins], }; };
In this way, our basic
webpack
configuration is just fine, take a look first:- Use babel to handle
tsx ts
andes
high-level grammars - Use
loader
processless
grammar html
with plug-in and was responsible for cleaning up- Configure the alias and omit the file suffix with the
resolve
Processed static files, such as pictures, with the built-in
asset
Write
webpack.dev.js
development configurationIntroduce dependencies
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); const { HotModuleReplacementPlugin } = require('webpack'); const { merge } = require('webpack-merge'); const common = require('./webpack.base');
First introduced hot update, merge configuration, basic configuration, official react hot update dependency
Then write the configuration
const devConfig = {
mode: 'development',
devServer: {
port: 3000,
contentBase: '../dist',
open: true,
hot: true,
},
target: 'web',
plugins: [new HotModuleReplacementPlugin(), new ReactRefreshWebpackPlugin()],
devtool: 'eval-cheap-module-source-map',
};
module.exports = merge(common, devConfig);
Note: Here you have to set target: 'web'
to have the hot update effect
- The best practice of devtool in development mode is:
eval-cheap-module-source-map
In this way, our development mode configuration is set up, as long as you write a index.html
public
folder, you can start writing the react
project as before.
Start writing webpack.prod.js
production configuration
Introduce dependencies:
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const { merge } = require('webpack-merge'); const common = require('./webpack.base');
The production environment needs to be separated from the
css
tag, so there is special treatment for less and css. One ispostcss
deal with style compatibility issues, and the other isMiniCssExtractPlugin.loader
:const prodConfig = { mode: 'production', devtool: 'hidden-source-map', module: { rules: [ { test: /\.(css|less)$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader'], }, ], }, optimization: { splitChunks: { chunks: 'all', name: false, }, }, plugins: [new MiniCssExtractPlugin()], }; module.exports = merge(common, prodConfig);
So the production configuration is also prepared
The best practice of
hidden-source-map
Write scripts commands
"build": "webpack --config config/webpack.prod.js --mode production", "dev": "webpack serve --config config/webpack.dev.js --mode development",
Note: The hot update used to be
webpack-dev-server
, now it iswebpack serve
!!!
Configure code quality control process
Add dependency
yarn add lint-staged @commitlint/cli @commitlint/config-conventional -D
Write code and submit testing process
"husky": { "hooks": { "pre-commit": "lint-staged", "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } }, "lint-staged": { "src/**/*.{js,jsx,ts,tsx,json,css,less,md}": [ "prettier --write", "eslint --fix", "git add" ] }, "browserslist": [ "ie >= 10", "ff >= 30", "chrome >= 34", "safari >= 8", "opera >= 23" ] }
Add
eslint
configuration://.eslintrc.js module.exports = { root: true, parserOptions: { ecmaVersion: 7, sourceType: 'module', }, parser: '@typescript-eslint/parser', plugins: ['typescript', 'react'], env: { browser: true, node: true, es6: true, }, rules: { semi: ['error', 'always'], // 该规则强制使用一致的分号 'no-unused-vars': 'off', // 禁止未使用过的变量 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', //生产环境禁用 debugger 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', //生产环境禁用 console 'default-case': ['warn', { commentPattern: '^no default$' }], //要求 Switch 语句中有 Default 'dot-location': ['warn', 'property'], // 强制在点号之前或之后换行 eqeqeq: ['error', 'allow-null'], //要求使用 === 和 !== 'new-parens': 'warn', //要求调用无参构造函数时带括号 'no-caller': 'error', // 禁用 caller 或 callee 'no-const-assign': 'error', //不允许改变用 const 声明的变量 'no-dupe-args': 'error', //禁止在 function 定义中出现重复的参数 'no-dupe-class-members': 'error', //不允许类成员中有重复的名称 'no-dupe-keys': 'warn', //禁止在对象字面量中出现重复的键 'no-extend-native': 'warn', //禁止扩展原生对象 'no-extra-bind': 'warn', //禁止不必要的函数绑定 'no-fallthrough': 'error', //禁止 case 语句落空 'no-func-assign': 'warn', //禁止对 function 声明重新赋值 'no-implied-eval': 'error', //禁用隐式的 eval() 'no-label-var': 'error', //禁用与变量同名的标签 'no-loop-func': 'error', //禁止循环中存在函数 'no-mixed-operators': [ 'warn', { groups: [ ['&', '|', '^', '~', '<<', '>>', '>>>'], ['==', '!=', '===', '!==', '>', '>=', '<', '<='], ['&&', '||'], ['in', 'instanceof'], ], allowSamePrecedence: false, }, ], //禁止混合使用不同的操作符 'no-multi-str': 'warn', //禁止多行字符串 (需要多行时用\n) 'no-native-reassign': 'warn', //禁止重新分配本地对象 'no-obj-calls': 'warn', //禁止将全局对象当作函数进行调用 'no-redeclare': 'error', //禁止重新声明变量 'no-script-url': 'warn', //禁用 Script URL 'no-shadow-restricted-names': 'warn', //关键字不能被遮蔽 'no-sparse-arrays': 'warn', //禁用稀疏数组 'no-this-before-super': 'warn', //在构造函数中禁止在调用 super()之前使用 this 或 super 'no-undef': 'error', //禁用未声明的变量 'no-unexpected-multiline': 'warn', //禁止使用令人困惑的多行表达式 'no-use-before-define': [ 'warn', { functions: false, classes: false, variables: false, }, ], //禁止定义前使用 'no-with': 'error', //禁用 with 语句 radix: 'error', //禁用函数内没有 yield 的 generator 函数 'rest-spread-spacing': ['warn', 'never'], //强制限制扩展运算符及其表达式之间的空格 'react/jsx-no-undef': 'error', //在 JSX 中禁止未声明的变量 'react/no-direct-mutation-state': 'error', //禁止 this.state 的直接变化 'react/jsx-uses-react': 'warn', //防止 React 被错误地标记为未使用 'no-alert': 0, //禁止使用alert confirm prompt 'no-duplicate-case': 2, //switch中的case标签不能重复 'no-eq-null': 2, //禁止对null使用==或!=运算符 'no-inner-declarations': [2, 'functions'], //禁止在块语句中使用声明(变量或函数) 'no-iterator': 2, //禁止使用__iterator__ 属性 'no-negated-in-lhs': 2, //in 操作符的左边不能有! 'no-octal-escape': 2, //禁止使用八进制转义序列 'no-plusplus': 0, //禁止使用++,-- 'no-self-compare': 2, //不能比较自身 'no-undef-init': 2, //变量初始化时不能直接给它赋值为undefined 'no-unused-expressions': 2, //禁止无用的表达式 'no-useless-call': 2, //禁止不必要的call和apply 'init-declarations': 0, //声明时必须赋初值 'prefer-const': 0, //首选const 'use-isnan': 2, //禁止比较时使用NaN,只能用isNaN() 'vars-on-top': 2, //var必须放在作用域顶部 }, };
unit test
New commands:
"test": "jest", //进行测试 "test-c": "jest --coverage" //生成测试报告
Install
jest
and other dependencies:yarn add jest-environment-enzyme ts-jest@next enzyme enzyme-adapter-react-17 enzyme-to-json @types/enzyme @types/enzyme-adapter-react-17 @types/enzyme-to-json -D
Create a new folder
test
Write the first unit test and introduce dependencies:
import App from '../src/App';
import { mount, shallow } from 'enzyme';
import React from 'react';
import toJson from 'enzyme-to-json'; //做快照
Then you can start writing unit tests happily
- In this way, a
webpack5
scaffolding build better,webpack
built something that allows us to save a lot of configuration, simpler look
After watching two things
If you think this content is very inspiring for you, I would like to invite you to help me with a few small things
1. Click "Watching, Like, Follow" so that more people can see this content (click "Watching", bug -1 😊)
2. Follow the WeChat public account "Front End Peak", let me continue to push selected good articles for you
I am Peter Tan, a front-end development engineer in a small factory. I like to do architecture, and I have a certain research on performance optimization and cross-platform development. I also like to do self-media and blockchain. Welcome to follow me
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。