1. The above
Recently, I met a lot of problems about project packaging and webpack. I learned about Webpack in my spare time. Although UNIVERSITY of Utah began to promote Vite recently, the webpack ecosystem is more perfect and stable. The following is the process of my systematic study of Webpack, and here to share, a rookie, I hope to exchange and learn with the big guys.
2. Webpack introduction
Webpack is a front-end resource builder, a static Module bundler. In webpack’s view, all the front-end resource files (JS /json/ CSS /img/less/…) Will be treated as modules. It will perform static analysis according to module dependencies, and package to generate the corresponding static resources (bundle.js).
3. Core concepts of Webpack
3.1 Entry
The Entry indicates which file webPack starts packing as the Entry point, analyzing and building the internal dependency diagram.
3.2 Output (Output)
Indicates where the output of resource bundles packaged by Webpack goes and how to name them.
3.3 Loader
Loader allows Webpack to handle non-javascript files (Webpack only handles JavaScript itself)
3.4 the Plugins
Plugins can be used to perform a much wider range of tasks. Plug-ins range from packaging optimization and compression to redefining variables in the environment.
3.5 Mode
4. Basic use of Webpack
4.1 the initialization
NPM init where the project filename cannot be Chinese
4.2 Downloading the WebPack
NPM install webpack webpack-cli -g
NPM install webpack webpack-cli -d
4.3 packaging
The development environment
webpack ./src/index.js -o ./dist/buddle.js --mode=development
Copy the code
The production environment
webpack ./src/index.js -o ./dist/buddle.js --mode=production
Copy the code
Packaging success
- Webpack can handle JS files and JSON files by default. In production environments, extra code obfuscates and compresses the code
4.4 Configuration File
- . Create a new webpack.config.js file in the root directory
- . In webpack.config.js
const path=require("path")
module.exports={
// Import file, import file path
entry:"./src/index.js"./ / output
output: {// Output the file name
filename:"bundle.js".// Output path, where absolute path is required
// this is equivalent to D:\ download \webpacjks\webpack and \dist
path:path.resolve(__dirname,'dist'),
// Set this to clear the contents of the last package,
clean:true
},
// Production mode
mode:'development'
}
Copy the code
4.5 Entering the package command
webpack
Copy the code
5. Use the loader
5.1 CSS packaging
Style packing can be used: cssLoader,styleloader
Download the dependent
npm i less -D
npm i style-loader css-loader less-loader -D
Copy the code
{
// Match a rule with a regular expression
test: /(\.css|\.less)$/,
use: [
// Insert the CSS text format into the HTML with the style tag, then perform the CSS rendering
// Insert the js style into the style tag
// The array is parsed from bottom to top, in reverse order
"style-loader".// Convert CSS to JS
"css-loader".// Convert less to CSS
"less-loader"],},Copy the code
5.2 CSS Compatibility
Download two packages postCSs-loader postCSs-env - NPM I postCSs-loader postCSs-preset -envCopy the code
//package.json
"browserslist": {
"development": [
"last 1 chrome version"."last 1 firefox version"."last 1 safari version"]."production": [
"0.2%" >."not dead"."not op_mini all"]}Copy the code
//webpack.config.js
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// Set the node environment variable. The default is production
process.env.NODE_ENV = "development";
module.exports = {
entry: "./src/js/index.js".output: {
filename: "js/bundle.js".path: resolve(__dirname, "dist"),},module: {
rules: [{test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
// Convert CSS to JS
"css-loader"./ / use postcss - loader
{
loader: "postcss-loader".options: {
postcssOptions: {
ident: "postcss".plugins: () = > [
// Help CSS find the configuration in package.json browserslist by loading the specified CSS style
require("postcss-preset-env")(),],},},},],},plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",}).new MiniCssExtractPlugin({
// Rename the packaged CSS and place it in a file
filename: "css/built.css",})],mode: "development"};Copy the code
5.3 Loading Resources
To load CSV, XML resources, use CSV-loader, XML-loader
npm i csv-loader xml-loader -D
Copy the code
{
// Match a rule with a regular expression
test: /(\.csv|\.tsv)$/,
use: ["csv-loader"],}, {// Match a rule with a regular expression
test: /\.xml$/,
use: "xml-loader",},// Use the import file main.js import
import xml from "./assets/index.xml"
import csv from "./assets/inde.csv"
let box2 = document.createElement("div");
box2.innerHTML=csv
document.body.appendChild(box2);
let box3 = document.createElement("div");
box3.innerHTML=xml
document.body.appendChild(box3);
Copy the code
5.4 Loading Data
To load jSON5, YAML, and TOMl files, you need yamL-loader, TOML-loader, and jSON5-loader
npm i yaml toml json5-D
Copy the code
//1. Configure in webpack.config.js
{
test: /\.yaml$/,
type: "json".parser: {parse: yaml.parse
}
},
{
test: /\.toml$/,
type: "json".parser: {
parse:toml.parse
}
},
/ / 2. The main. Use js
import yaml from "./assets/index.yaml"
import toml from "./assets/index.toml"
console.log(yaml.languages);
console.log(toml.data);
Copy the code
5.5 the Babel – loader
Convert JS es6 syntax to ES5 syntax
npm i babel-loader @babel/core @babel/preset-env @babel/polyfill core-js -D
npm i @babel/runtime -D
npm i @babel/plugin-transform-runtime -D
Copy the code
// module->rules in webpack.config.js
{
test: /\.js$/,
exclude: /node_modules/,
use:{
loader: "babel-loader".options: {
presets: ["@babel/preset-env"].plugins:[
[
'@babel/plugin-transform-runtime'[]},}},Copy the code
6. The use of plugins
6.1 HTML – webpack – the plugin
The installation
npm i html-webpack-plugin -D
Copy the code
//webapck.config.js
const {resolve}=require('path')
// Import HTML plugins
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
entry:'./src/main.js'.output: {filename:'bundle.js'.path:resolve(__dirname,'./dist')},mode:'production'.plugins: [new HtmlWebpackPlugin({
// Here is the path where the HTML file needs to be packaged
template:'./index.html'.// The name of the packaged HTML file
filename:'bundle.html'.// Where to put the imported JS, the default is in the head
inject:'body'}})]Copy the code
6.2 the mini – CSS – extract – the plugin
Out of the CSS
npm i mini-css-extract-plugin -D
Copy the code
// First introduce the plug-in
const MiniCssExtarctPlugin = require("mini-css-extract-plugin");
// instantiate the plug-in
plugins: [
new MiniCssExtarctPlugin({
// The packaged name
filename: "style/[contenthash].css",})],// Use plugins
module: {
// Configure the module resources here, but make sure the images are under assets
rules: [{// Match a rule with a regular expression
test: /(\.css|\.less)$/,
use: [
// Insert the CSS text format into the HTML with the style tag, then perform the CSS rendering
// Insert the js style into the style tag
// Use plugins
MiniCssExtarctPlugin.loader,
// Convert CSS to JS
"css-loader".// Convert less to CSS
"less-loader",],},},Copy the code
6.3 CSS – minimizer – webpack – the plugin
Compressing obfuscated CSS
npm i css-minimizer-webpack-plugin -D
Copy the code
// Import plug-ins
const CssminimizerWebpackPlugin=require("css-minimizer-webpack-plugin")
// Register plugins. This optimization is at the same level as module plugins, where plugins are not placed in plugins
optimization: {minimizer: [new CssminimizerWebpackPlugin()
]
}
// Change the development environment
mode: "production"
Copy the code
6.4 terser webpack — the plugin
By default webpack is allowed to confuse JS, but CSS -minimizer-webpack-plugin is not allowed. Another plugin, Terser-webpack-plugin, is required
npm i terser-webpack-plugin -D
Copy the code
optimization: {
minimizer: [new CssminimizerWebpackPlugin(), new TerserWebpackPlugin()],
},
Copy the code
6.5 webpack – bundle – analyzer
You can analyze webPack dependency modules
> npm i webpack-bundle-analyzer -D
Copy the code
const{ BundleAnalyzerPlugin} = require('webpack-bundle-analyzer')
plugins: [
new BundleAnalyzerPlugin()
],
Copy the code
7. Webpack performance optimization
7.1 Code Separation
7.1.1 code – spliting
This way is to configure multiple entries and modify the output package file. This way can be packaged into multiple entries and separate the code, but if the project introduces very large packages like Lodash and jquery, as long as it is used once, each entry package will be packaged, resulting in repeated packaging and bloated code
module.exports = {
entry: {
// Multi-entry packing
index:"./src/main.js".another:"./src/js/load.js"
},
output: {
// The name must be dynamic
filename: "[name].bundle.js".path: resolve(__dirname, "./dist"),
clean: true,},mode: "production",}Copy the code
7.1.2 Removing public Chunk
To reduce the waste of resources, separate the public package from each entry package to form a new chunk
Method 1: Configure Entry
entry: {
index: {import:"./src/main.js".dependOn:'shared'
},
// Public package
another: {import:"./src/js/load.js".dependOn:'shared'
},
shared:'lodash'
},
Copy the code
Mode 2: Configuration optimization
optimization: {
minimizer: [new CssminimizerWebpackPlugin()],
// Put common code in a chunk, such as Lodash, jquery packaged separately
splitChunks: {chunks:'all'}},Copy the code
7.1.3 Dynamic Import
//asyncCpmponent.js
function asyncCpmponent() {
// Dynamic import
return import("lodash").then(({ default: _}) = > {
const element = document.createElement("div");
element.innerHTML = _.join(["wo"."shi"."ws"]."");
return element;
});
}
asyncCpmponent().then((element) = >{
document.body.appendChild(element)
})
// Import the file in the entry
import "./js/asyncCpmponent.js"
Copy the code
7.2 the source map
When an error occurs, the developer can pinpoint the error code
7.3 watch mode
Every time you run the code, you can detect that js has changed and the WebPCK will restart
/ / input
webpack --watch
/ / instead of
webpack
Copy the code
7.3 webpack – dev – server
The browser can automatically update our files when they change. Webpack-dev-server doesn’t really output physical files, it just puts all the files in memory and executes
npm i webpack-dev-server -D
Copy the code
Start with NPX WebPack Serve. If you start with WebPack Serve, ensure that the local global Webpack version is the latest version
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./main.js".output: {
filename: "buddle.js".path: resolve(__dirname, "./dist"),
clean: true,},mode: "development".devtool: "source-map".plugins: [
new HtmlWebpackPlugin({
template: "./index.html".filename: "index.html",})],devServer: {static:resolve(__dirname,"./dist"),
// Set whether to compress the code on the server side, reduce the size of the data transferred, and gzip compression
compress:true.// Change the port number
port:3000.// Configure the request header file
headers: {"wx-token":'fvfet4htghrjt123'
},
// Local service proxy
proxy: {'/api':'http://localhost:8080',},/ / configure HTTPS
// https:true,
//http2
https:true.// Redirect when browser access has no routing address, or no proxy is configured
historyApiFallback:true}};Copy the code
7.4 a lazy loading
The module is not loaded when the page is loaded, while the current module is loaded when the operation is performed
//math.js
export const minus=(a,b) = >a-b
export const add=(a,b) = >a+b
Copy the code
/ / the main use js
let btn = document.createElement("button");
btn.innerHTML = "Click trigger add event";
btn.addEventListener("click".() = > {
// You can change the packaged package name in the comments section
import(/*webpackChunkName:'math*/"./js/math.js").then(({ add }) = > {
console.log(add(6.7));
});
});
document.body.appendChild(btn);
Copy the code
7.5 preload
Pack the module when the browser is idle
7.6 the cache
Optimized by hitting the cache index, the files generated by WebPack are cached by the customer service and updated as updates are obtained
7.6.1 Babel cache
On the second build, the previous cache is read
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader".options: {
presets: [["@babel/preset-env",
{
useBuiltIns: "usage".corejs: { version: 3 },
targets: { chrome: "60".firefox: "50" ,ie:'9'}},]].// Set js's Babel to true when packing
cacheDirectory:true}},Copy the code
7.6.2 File Resource Caching
Add a 10-bit hash value to the packaged JS
Focus on
● Hash: EACH wepack build generates a unique hash value. Problem: Because JS and CSS use the same hash value. If repackaged, all caches will be invalidated. ● Chunkhash: Hash value generated by chunk. If the package comes from the same chunk, the hash value will be the same. Problem: JS and CSS will still have the same hash value. CSS is in the same chunk because it was introduced in JS. Different files must have different hash values
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/* Cache: Babel cache cacheDirectory: true --> Make the second package build faster file resource cache Hash: generates a unique hash value for each Wepack build. Problem: Because JS and CSS use the same hash value. If repackaged, all caches will be invalidated. Chunkhash: Hash value generated by chunk. If the package comes from the same chunk, the hash value will be the same. Problem: JS and CSS have the same hash value. Since CSS is introduced in JS, it belongs to the same chunk as CONTenthash. Different files must have different hash values -> It is better to use */ to make code run online and cache
// Define the nodeJS environment variable: Determines which environment to use browserslist
process.env.NODE_ENV = 'production';
/ / reuse loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// You also need to define browserslist in package.json
loader: 'postcss-loader'.options: {
ident: 'postcss'.plugins: () = > [require('postcss-preset-env') (the)]}}];module.exports = {
entry: './src/js/index.js'.output: {
filename: 'js/built.[contenthash:10].js'.path: resolve(__dirname, 'build')},module: {
rules: [{// In package.json eslintConfig --> Airbnb
test: /\.js$/,
exclude: /node_modules/.// Priority execution
enforce: 'pre'.loader: 'eslint-loader'.options: {
fix: true}}, {// The following loader will only match one
// Note: No two configurations can handle the same type of file
oneOf: [{test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']},/* Normally, only one loader can process a file. When a file is to be processed by multiple Loaders, it is important to specify the order in which loader executes: esLint before Babel */
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'.options: {
presets: [['@babel/preset-env',
{
useBuiltIns: 'usage'.corejs: { version: 3 },
targets: {
chrome: '60'.firefox: '50'}}]],// Enable the Babel cache
// On the second build, the previous cache is read
cacheDirectory: true}}, {test: /\.(jpg|png|gif)/,
loader: 'url-loader'.options: {
limit: 8 * 1024.name: '[hash:10].[ext]'.outputPath: 'imgs'.esModule: false}}, {test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader'.options: {
outputPath: 'media'}}]}]},plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html'.minify: {
collapseWhitespace: true.removeComments: true}})].mode: 'production'.devtool: 'source-map'
};
Copy the code
7.6.3 Caching of third-party libraries
Cache the node_modules folder
optimization: {
minimizer: [new CssminimizerWebpackPlugin(), new TerserWebpackPlugin()],
splitChunks: {cacheGroups: {vendor: {// Here is the path where the third-party package needs to be cached
test:/[\\/]node_modules[\\/]/.// The file name after chunk packaging
name:'vendors'.// all chunks
chunks:'all'}}}},Copy the code
Generate the following files
7.7 HMR
If one module changes, only the current module is packaged, not all modules, and hot module replacement is needed to keep the code consistent with the page. If you change the code, the page will change in time
devServer:{
contentBase:resolve(__dirname,'build'),
// Start GZIP compression
compress:true.// Local boot port number
port:3000.// Automatically open the browser
open:true./ / open HMR
hot:true
}
Copy the code
-
Style files CSS /less files: HMR functionality can be used by default because style-loader is implemented internally
-
HTML files: By default, the HMR function is disabled and the HTML files cannot be hot updated
-
Js file: the HMR function can not be used by default
Js HMR:
//index.js
if (module.hot) {
// Once module.hot is true, HMR is enabled. --> Make the HMR function code work
module.hot.accept('./print.js'.function() {
// The print.js method listens for changes in the print.js file, and when changes occur, other modules are not repackaged and built.
// The following callback functions are executed
print();
});
}
Copy the code
7.8 Web Workers
The JavaScript language uses a single-threaded model, which means that all tasks can only be done on one thread, one thing at a time. The first task is not finished, the next task has to wait. With the enhancement of computer computing ability, especially the emergence of multi-core CPU, single thread brings great inconvenience and can not give full play to the computing ability of the computer.
The function of Web Worker is to create a multithreaded environment for JavaScript, allowing the main thread to create Worker threads and assign some tasks to the latter to run. While the main thread is running, the Worker thread is running in the background without interfering with each other. Wait until the Worker thread completes the calculation and returns the result to the main thread. The advantage of this is that when computationally intensive or high-latency tasks are taken on by Worker threads, the main thread (usually responsible for UI interactions) will flow smoothly and will not be blocked or slowed down.
Once a Worker thread is created, it is always running and is not interrupted by activity on the main thread, such as a user clicking a button or submitting a form. This facilitates communication that responds to the main thread at any time. However, this also causes the Worker to consume resources, so it should not be overused and should be closed once it is used.
Based on using
//app.js
const worker=new Worker(new URL("./work.js".import.meta.url))
worker.postMessage({
question:'hello ws'
})
worker.onmessage=message= >{
console.log(message.data.name);
}
Copy the code
//work.js
self.onmessage=message= >{
// This accepts data posted from app.js
console.log(message)
self.postMessage({
name:'ws'})}Copy the code
7.9 the tree – shaking
Tree shaking in Webapck is a very good performance optimization operation, it is not introduced in the project and not used packages are all packaged into the packaged file, is a good performance optimization
// Configure in webpack.connfig.js
optimization: {usedExports:true
}
Copy the code
7.10 sideEffects
Tell WebPack that currently written code has no side effects, and that webPack cannot tree-shaking remove files with side effects
//package.json
// All files have side effects, do not delete files
sideEffect:true
// All files have no side effects, delete files
sideEffect:false
// The specified file has side effects. The specified file is not deleted
sideEffect: ['*.css]
Copy the code
7.11 PWA
When the network is down, pages can still be loaded, which is equivalent to caching pages and optimizing them
Add serviceWork 7.11.1
/ / install workbox - webpack - the plugin
npm i workbox-webpack-plugin -D
Copy the code
//webpack.config.js
const { resolve } = require("path");
const WorkboxPlugin=require("workbox-webpack-plugin")
module.exports = {
entry: "./main.js".output: {
filename: "buddle.js".path: resolve(__dirname, "./dist"),
clean: true,},mode: "development".devtool: "source-map".plugins: [
new WorkboxPlugin.GenerateSW({
/ / enable serviceWorks
clientsClaim:true.// Jump out of current serviceWorks and disallow old serviceWorks
skipWaiting:true})]};Copy the code
7.11.2 registered serviceWork
//main.js
if('serviceWorker' in navigator){
window.addEventListener('load'.() = >{
// Service-worker. js is a packaged file, so we need to run webapck to package it
navigator.serviceWorker.register('/service-worker.js')
.then(res= >{
console.log('Registration successful'+res);
}).catch(err= >{
console.log('Registration failed'+err); })})}Copy the code
npx webpack serve
Turning off the service still prints, so the page content is cached by the browser
7.12 DLL
Use DLL technology for some libraries (third-party libraries: jquery, React, vue…) Packaged separately, when you run Webpack, the default is to look for the webpack.config.js configuration file
* You need to run the webpack.dlL. js file
// Create webpack.dll. Js in the SRC folder
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
[name] --> jquery
// ['jquery'] --> The library is jquery
jquery: ['jquery'],},output: {
filename: '[name].js'.path: resolve(__dirname, 'dll'),
library: '[name]_[hash]' // What is the name of the contents exposed in the packaged library
},
plugins: [
// Package to generate a manifest.json --> provide and jquery mapping
new webpack.DllPlugin({
name: '[name]_[hash]'.// The exposed content name of the mapping library
path: resolve(__dirname, 'dll/manifest.json') // Output file path})].mode: 'production'
};
Copy the code
Run webpack --config webpack.dill.jsCopy the code
/ / download
npm i add-asset-html-webpack-plugin -D
Copy the code
//webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports = {
entry: './src/js/index.js'.output: {
filename: 'built.js'.path: resolve(__dirname, 'build')},plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
// Tell Webpack which libraries are not included in the package, and change their names when used
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')}),// Package a file and import the resource automatically in HTML
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')})],mode: 'production'
};
Copy the code
directory
7.13 shimming
Shimming can globally import third-party packages so that they can be used without having to import packages in files, and in some modules this does not refer to window. In commonJs modules this does not refer to window, so you need to change the reference of this to import third-party packages
7.13.1 Setting Global Variables
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
// WebPack is introduced here
const webpack=require('webpack')
module.exports = {
entry: "./src/main.js".output: {
filename: "scripts/[name].[contenthash].js".path: resolve(__dirname, "./dist"),},mode: "development".plugins: [
new HtmlWebpackPlugin({
// Here is the path where the HTML file needs to be packaged
template: "./index.html".// The name of the packaged HTML file
filename: "bundle.html".// Where to put the imported JS, the default is in the head
inject: "body",}).new webpack.ProvidePlugin({
_:'lodash'})]};Copy the code
//src/main.js
// This can be used without introducing Lodash
console.log(_.join(['ws'.'love'.'qy'].'_'))
Copy the code
7.13.2 Fine particle size
If this is included in an imported third-party package, it may not point to the window, so you need to change the this point
Use imports – loader
npm i imports-loader -D
Copy the code
module: {rules:[
{
test: require.resolve('./src/main.js'),
use: 'imports-loader? wrapper=window',}}]Copy the code
7.13.3 Global exposure
Use exports – loader
npm i exports-loader -D
Copy the code
module: {rules:[
{
test: require.resolve('./src/main.js'),
use: 'imports-loader? wrapper=window'}, {test: require.resolve('./src/golobalWays.js'),
// Use the exports-loader, which is of type commonJs, to expose attributes one by one,
// Expose an object with multiple. The second argument is the object's property value/method, and the third argument is the object's property/method name
use: 'exports-loader? type=commonjs&exports=ws,multiple|files.output|output',}}]Copy the code
8. Resource module
File directory
Resource is used to package exported images in PNG and JPG formats, inline is used to export images in BASE64 formats such as SVG, and source is used to export source code
//webpack.config.js
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/main.js".output: {
filename: "bundle.js".path: resolve(__dirname, "./dist"),
clean: true.// You can also enter the name of the packaged assets file
assetModuleFilename: "images/[contenthash][ext]",},mode: "production".plugins: [
new HtmlWebpackPlugin({
// Here is the path where the HTML file needs to be packaged
template: "./index.html".// The name of the packaged HTML file
filename: "bundle.html".// Where to put the imported JS, the default is in the head
inject: "body",})],devServer: {
contentBase: resolve(__dirname, "dist"),
// Start GZIP compression
compress: true.// Local boot port number
port: 3000.// Automatically open the browser
open: true,},module: {
// Configure the module resources here, but make sure the images are under assets
rules: [{test: /\.png$/,
type: "asset/resource".generator: {
filename: "images/[contenthash][ext]",}}, {// Inline will not be packaged into the dist directory
test: /\.svg$/,
type: "asset/inline"}, {//source is used to read data
test: /\.txt$/,
type: "asset/source"}, {//source is used to read data
test: /\.jpg$/,
type: "asset".parser: {
// Beyond this maximum value, base64 is converted
dataUrlCondition: {
maxSize: 25 * 1024,},},},],},};Copy the code
After the configuration is complete, import resources as modules
//main.js
const { add } = require("./js/add.js");
import img from "./assets/line.png";
import svg from "./assets/egg.svg";
import txt from "./assets/index.txt"
console.log(add(1.6));
//resource
let img1 = document.createElement("img");
img1.src = img;
document.body.appendChild(img1);
//inline
let img2 = document.createElement("img");
img2.src = svg;
document.body.appendChild(img2);
//source
let box = document.createElement("h1");
box.textContent=txt
document.body.appendChild(box);
Copy the code
By default, WebPack will load the resource size. When the resource size is less than 8K, it will generate a base64 link, which is inline mode. If the resource size is greater than 8K, it will switch to resource mode. This 8K is adjustable and requires a parser to be configured under webpack.config.js-module-rules
How to load the iconfont font
You can load fonts in Webpack using the type: Resource configuration
//1. Configure it under module->rules
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: "asset/resource"
}
//2. Add it to the CSS
@font-face {
font-family: 'iconfont'; src: url(.. /assets/iconfont.ttf) format('truetype');
}
.icon{
font-family: 'iconfont';
font-size: 30px;
}
//3. Use fonts in main.js
/ / introduction
import './style/index.css'
let box1 = document.createElement("h1");
/ / use
box1.className='icon'
box1.innerHTML=''
document.body.appendChild(box1);
Copy the code
9. Split production and development environments
9.1 Common Path
output: {
filename: "scripts/[name].[contenthash].js".path: resolve(__dirname, "./dist"),
clean: true.// You can also enter the name of the packaged assets file
assetModuleFilename: "images/[contenthash][ext]".// Configure the public path
publicPath:'http://localhost:8080/'
},
Copy the code
When you pack it, the path will add this path
9.2 Environment Variables
You need to know whether the user is in production or development
module.exports = (env) = > {
return {
entry: {
index: "./src/main.js".another: "./src/js/load.js",},output: {
filename: "scripts/[name].[contenthash].js".path: resolve(__dirname, "./dist"),
clean: true.// You can also enter the name of the packaged assets file
assetModuleFilename: "images/[contenthash][ext]".publicPath: "http://localhost:8080/",},// Determine what environment the user entered
mode: env.production ? "production" : "development",}}Copy the code
9.3 WebPack File Splitting
// The public module webpack.common.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtarctPlugin = require("mini-css-extract-plugin");
const toml = require("toml");
const yaml = require("yaml");
module.exports = {
entry: {
index: "./src/main.js".another: "./src/js/load.js",},output: {
path: path.resolve(__dirname, ".. /dist"),
clean: true.// You can also enter the name of the packaged assets file
assetModuleFilename: "images/[contenthash][ext]",},plugins: [
new HtmlWebpackPlugin({
// Here is the path where the HTML file needs to be packaged
template: "./index.html".// The name of the packaged HTML file
filename: "bundle.html".// Where to put the imported JS, the default is in the head
inject: "body",}).new MiniCssExtarctPlugin({
// The packaged name
filename: "style/[contenthash].css",})],module: {
// Configure the module resources here, but make sure the images are under assets
rules: [{// Match a rule with a regular expression
test: /(\.css|\.less)$/,
use: [
// Insert the CSS text format into the HTML with the style tag, then perform the CSS rendering
// Insert the js style into the style tag
// The array is parsed from bottom to top, in reverse order
MiniCssExtarctPlugin.loader,
// Convert CSS to JS
"css-loader".// Convert less to CSS
"less-loader",]}, {// Match a rule with a regular expression
test: /(\.csv|\.tsv)$/,
use: ["csv-loader"],}, {// Match a rule with a regular expression
test: /\.xml$/,
use: "xml-loader"}, {test: /\.png$/,
type: "asset/resource".generator: {
filename: "images/[contenthash][ext]",}}, {// Inline will not be packaged into the dist directory
test: /\.svg$/,
type: "asset/inline"}, {//source is used to read data
test: /\.txt$/,
type: "asset/source"}, {//source is used to read data
test: /\.jpg$/,
type: "asset".parser: {
dataUrlCondition: {
maxSize: 25 * 1024,},},}, {test: /\.yaml$/,
type: "json".parser: {
parse: yaml.parse,
},
},
{
test: /\.toml$/,
type: "json".parser: {
parse: toml.parse,
},
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: "asset/resource"}, {test: /\.(woff|woff2|eot|ttf|otf)$/,
type: "asset/resource"}, {test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader".options: {
presets: ["@babel/preset-env"].plugins: [["@babel/plugin-transform-runtime"],},},},],},optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors".chunks: "all",},},},},};Copy the code
Development Environment Configuration
//webpack.config.dev.js
const { resolve } = require("path");
module.exports = {
output: {
filename: "scripts/[name].js",},mode: "development".devServer: {
contentBase: resolve(__dirname, "dist"),
// Start GZIP compression
compress: true.// Local boot port number
port: 3000.// Automatically open the browser
open: true,},devtool: "inline-source-map"};Copy the code
Production Environment Configuration
//webpack.config.prod.js
const CssminimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
module.exports = {
output: {
filename: "scripts/[name].[contenthash].js".publicPath: "http://localhost:3000/",},mode: "production".optimization: {
minimizer: [new CssminimizerWebpackPlugin(), new TerserWebpackPlugin()],
},
performance: {
hints: false,}};Copy the code
Combine public, production, and development environments using Webpack-Merage
npm i webpack-merage -D
const { merge } = require("webpack-merge");
const commonfig = require("./webpack.config.common");
const devfig = require("./webpack.config.dev");
const prodconfig = require("./webpack.config.prod");
module.exports = (env) = > {
switch (true) {
case env.development:
return merge(commonfig, devfig);
case env.production:
return merge(commonfig, prodconfig);
default:
return new Error("error"); }};Copy the code
Change the package.json run path
"scripts": {
"start": "webpack serve --config ./config/webpack.config.js --env development"."build": "webpack -c ./config/webpack.config.js --env production"
},
Copy the code
10. Webpack configuration
10.1 Alias the Wepack file path
resolve: {
// Configure the path
alias: {
"@": resolve(__dirname, "./serve"),},// Configure the extension so that the extension can be omitted from the project
extensions: [".json".".js".".vue"],},Copy the code
10.2 External WebPack extensions
When we need to reduce the size of the bundle, we need to import files using CDN, such as jquery.
//webpack.config.js
// Indicates that the script tag is inserted
externalsType: "script".externals: {
// The first element is the link that needs to be placed in the HTML
// The second element is an object that script exposes to the browser, in this case $
jquery: ["https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"."$"],},Copy the code
11. Build a multi-page app
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: {
Lodash is a public package that needs to be removed to form a chunk
main: {
import: "./src/main.js".dependOn: "lodash".filename: "files1/[name].[contenthash].js",},main1: {
import: "./src/main1.js".dependOn: "lodash".filename: "files2/[name].[contenthash].js",},lodash: {
import: "lodash".filename: "commonFile/[name].[contenthash].js",}},output: {
// Enter the folder directory
path: resolve(__dirname, "./buddle"),
// The last directory can be cleaned up after packaging again
clean: true,},mode: "development".plugins: [
new HtmlWebpackPlugin({
template: "./src/index1.html".// The title here can be retrieved directly in HTML via ejS templates
title: "Multi-page applications".// Where to put the defined script, body or head
inject: "body".// Which JS packages are loaded on the current page
chunks: ["main"."lodash"].// Set the file name after packaging
filename: "files1/index1.html",}).new HtmlWebpackPlugin({
template: "./src/index2.html".// The title here can be retrieved directly in HTML via ejS templates
title: "Multi-page applications".// Where to put the defined script, body or head
inject: "body".// Which JS packages are loaded on the current page
chunks: ["main1"."lodash"].// Set the file name after packaging
filename: "files2/index2.html",})]};Copy the code
// This is unique to the html-webpack-plugin<! DOCTYPEhtml>
<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><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
</body>
</html>
Copy the code
12. Module federation
12.1 Basic Introduction
Microfront-end introduces the concept of microservices into front-end development. Rather than developing an application or site as a whole, the focus is on breaking it down into smaller pieces that are individually programmed and then tied together at run time.
In this way, other parts of the application can be developed using different technologies and developed by separate teams. , splitting development in this way avoids the maintenance costs associated with traditional units.
As a side effect, it enables new types of collaboration between back-end and front-end developers, as they can work as a cohesive team to focus on specific parts of the application. For example, you can have a team focus only on the search function or other critical business parts around the core function.
Starting with WebPack 5, there are built-in capabilities for developing microfronts. The modules combine and give you enough functionality to handle the workflow required for the microfront approach.
Mode of module sharing:
12.2 Basic Model
The traditional way of sharing code
Micro front-end
Module federal
Module federation, which allows me to introduce components from project b into project a, is a big new feature of webpack5
12.3 Specific Usage
There is a HomeList component in the home field. There is a header component in the nav field. The requirement is to include the header component of the nav field in the home field. The Serach project introduces the Homelist component in the home project and the Header component in the nav project
1. Expose the Header component in the NAV project
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {ModuleFederationPlugin}=require('webpack').container
module.exports = {
entry: "./index.js".output: {
filename: "scripts/[name].[contenthash].js".path: resolve(__dirname, "./dist"),},mode: "development".plugins: [
new HtmlWebpackPlugin(),
new ModuleFederationPlugin({
// Identifies the name of the module federation, which is required if the external needs to import that part of the component
name:'nav'.// Remote entry, where the current item is online
filename:'remoteEntry.js'.// Reference components exposed by other applications
remotes:{
},
// The exposed components can be used by other applications
exposes: {// Key represents the path URL that other applications will use to concatenate this component in the future
// The last value is the component path that the current application needs to expose
// The./Header can be used in other modules to find the current module
'./Header':'./src/header.js'
},
// Third-party shared modules, such as Lodash,jquery
shared:{}})],};Copy the code
2. Run the home project using webpack-dev-serve
npx webpack serve –port 3002
3. Introduce the header component of the nav project in the home project and expose its own Homelist component
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {ModuleFederationPlugin}=require('webpack').container
module.exports = {
entry: "./src/index.js".mode: "development".plugins: [
new HtmlWebpackPlugin(),
new ModuleFederationPlugin({
// Identifies the name of the module federation, which is required if the external needs to import that part of the component
name:'home'.// Remote entry, where the current item is online
filename:'remoteEntry.js'.// Reference components exposed by other applications
remotes: {// In another application, the module federally defines the name after nav
//nav is the address to import the application
// remoteentry. js is the filename from which the application is introduced
nav:'nav@http://localhost:3003/remoteEntry.js'
},
// The exposed components can be used by other applications
exposes: {// Key represents the path URL that other applications will use to concatenate this component in the future
// The last value is the component path that the current application needs to expose
'./Homelist':'./src/HomeList.js'
},
// Third-party shared modules, such as Lodash,jquery
shared:{}})],};Copy the code
//home/src/index.js
// Asynchronous import is used here
import HomeList from "./HomeList.js";
import("nav/Header").then((Header) = > {
let box = document.createElement("div");
box.appendChild(Header.default());
document.body.appendChild(box);
box.innerHTML += HomeList(4);
});
Copy the code
4. Run the nav project using webpack-dev-serve with the same port number as the remote that introduced webpack.config.js in the project
npx webpack serve –port 3003
5. The Search project introduces the configuration of the above two projects
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {ModuleFederationPlugin}=require('webpack').container
module.exports = {
entry: "./src/index.js".mode: "development".plugins: [
new HtmlWebpackPlugin(),
new ModuleFederationPlugin({
// Identifies the name of the module federation, which is required if the external needs to import that part of the component
name:'search'.// Remote entry, where the current item is online
filename:'remoteEntry.js'.// Reference components exposed by other applications
remotes: {// In another application, the module federally defines the name after nav
//nav is the address to import the application
// remoteentry. js is the filename from which the application is introduced
nav:'nav@http://localhost:3003/remoteEntry.js'.home:'home@http://localhost:3002/remoteEntry.js'
},
// The exposed components can be used by other applications
exposes:{
},
// Third-party shared modules, such as Lodash,jquery
shared:{}})],};Copy the code
// Reference and use components. Here we introduce two components, promise.all
// Use promise.all to load the two asynchronous components separately
Promise.all([import('nav/Header'), import('home/Homelist')]).then(([
// Export the default option in the component
{
default: Header
},
{
default: Homelist
}
]) = > {
document.body.appendChild(Header())
document.body.innerHTML+=Homelist(6)})Copy the code
6. Run the search project with webpack-dev-serve
npx webpack serve –port 3001
13. To summarize
Through the systematic study of Webpack5, I have mastered many improvements in front-end performance. This article is based on the systematic study of the official website. If there are any deficiencies, please give me your advice