Progressive configuration of webpack4 single and multiple pages
preface
Use the version of the package
Webpack ->4.3.0 babel-loader -> 8.0.5nPM ->6.4.1 webpack-cli ->3.3.1Copy the code
Each section corresponds to a demo
Modular Unpacking 1
Reference code Demo8
What is modular unpacking? For example, we need to introduce echarts, XLSX, LoDash and other large packages in the project. If you don’t unpack the code, it will be packaged into a JS file. If a new JS package is generated every time a package is released, the user will request echarts, XLSX, LoDash and other unchanging code again when requesting the page, which will degrade the user experience. Modularized unpacking will pack these invariant dependencies into a new JS file, so that users will not request echarts, XLSX, loDash and other invariant code again every time the package is released.
Code changes
Webpack-bundle-analyzer visually displays packages referenced by packaged JS
npm i webpack-bundle-analyzer -D
Copy the code
Introduce Echarts, XLSX, loDash into the project
npm i echarts xlsx lodash -S
Copy the code
app.js
import "regenerator-runtime/runtime";
import _ from 'lodash';
import echarts from 'echarts';
import xlsx from 'xlsx';
console.log(echarts)
console.log(xlsx);
document.getElementById('app'). InnerHTML = _. Ceil (2 and 4);Copy the code
Webpack.base.conf.js configuration visualization now packages files.
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
plugins:[
new BundleAnalyzerPlugin(),
new htmlWebpackPlugin({
filename:'index.html',
template:'./index.html',
inject:trueCollapseWhitespace: isPord, // Delete whitespace and newlines minifyCSS: // collapseWhitespace: isPord, // IsPord // compression inline CSS},})],Copy the code
Run the package command
npm run build
Copy the code
The default configuration
Optimization.splitchunks is a new feature of webpack4 that does code unpacking by default.
chunks:
- All: Regardless of whether the file is introduced asynchronously or synchronously, splitChunks can be used for code unpacking.
- Async: Separates asynchronously loaded files. The files are not imported for the first time and are imported only to components that need to be imported asynchronously.
- Initial: Separates asynchronous and non-asynchronous files. If a file is imported asynchronously and non-asynchronously, it is packaged twice (note the difference with all) to separate the packages that the page needs to load the first time.
MinSize: indicates the minimum package size of a file. The unit is byte. The default value is 30000.
For example, a project has three entry files, a.js, b.js, and c.js, each with 100bytes. When we set minSize to 301, WebPack will pack them into one package, not split them into multiple packages.
AutomaticNameDelimiter: the connector.
Suppose we generate a common file named vendor, A.js, and b.js that depend on it, and we set the connector to “~”, then the resulting file is Vendor ~a~ B.js
The maximum number of parallel requests at the maxInitialRequests entry point, which defaults to 3.
If we set it to 1, each entry file will be packaged as only one file
MaxAsyncRequests Maximum number of asynchronous requests. Default: 5
If we set it to 1, each entry file will be packaged as only one file
Priority relationship.
MaxInitialRequest/maxAsyncRequests <maxSize <minSize.
CacheGroups Specifies the list of rules for splitting packages
Test can configure regex and write function as a packing rule. Other attributes can inherit splitChunks.
minChunks
Depends on the minimum number of times to be introduced before unpacking.
Simple Configuration Modification
Copy the default configuration and change chunks to ‘all’.
optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true}}}},Copy the code
Run the package command
npm run build
Copy the code
Unpacking again
Vendors ~app.js is a 1.71MB file, too big, so keep unpacking. Add a new unpacking rule
CacheGroups :{echarts:{// New ungroup rule name:'echarts'// rule name chunks:'all'Priority :10, // The priority of this rule, for example, when unpacking in webpack, // echarts packages will match the rule with the highest priority first, if this rule is met, // Import code into this rule, not into the following rule.test:/(echarts)/, // regular matching rule minChunks:1 // this rule can be used if it is introduced at least once in the code. }, vendors: {test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true}}Copy the code
Run the package command
npm run build
Copy the code
The official demo
Modular Unpacking 2
See the Demo9 section for asynchronous loading using only the default configuration of splitChunks to understand the benefits of asynchronous loading. . Use React as a development framework.
Synchronized imported unpacking
Redux -> 16.8.6 react-dom -> 16.8.6 react-router-dom -> 5.0.0Copy the code
Install the react
npm i react react-router-dom react-dom -S
Copy the code
Parsing JSX code also requires @babel/ preth-React
npm i @babel/preset-react -D
Copy the code
See Demo9 for the code details. The two routes correspond to different components.
import About from './src/view/about';
import Inbox from './src/view/inbox'; / /... <App> <Route path="/about" component={About} />
<Route path="/inbox" component={Inbox} />
</App>
Copy the code
Inbox.js introduced and used Echarts.
import React from 'react';
import echarts from 'echarts';
class Inbox extends React.Component {
componentDidMount() {
var myChart = echarts.init(document.getElementById('main'));
var option = {
tooltip: {
show: true
},
legend: {
data: ['sales']
},
xAxis: [
{
type: 'category',
data: ["Shirt".Cardigan 2."Chiffon 222".111 "pants"."High heels"."Socks"]
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
"name": "Sales"."type": "bar"."data": [5, 20, 40, 10, 10, 20]}]}; // Load data for echarts mychart.setoption (option); }render() {
return (
<div>
<h2>Inbox</h2>
<div style={{ height: '400px' }} id="main"></div>
</div>
)
}
}
export default Inbox;
Copy the code
SplitChunks use the default configuration
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true}}}Copy the code
Run the package command
npm run build
Copy the code
It was already indicated when packaging that the packaged code was too bad for performance. You can use import() or require to limit package size. Make sure that some parts of the application are lazily loaded.
WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
Copy the code
When we are on the home page, there is no/INBOX route, but the code in the/INBOX route is packaged in the app.js js. The first screen rendering is very slow. Dynamic introduction of components is required according to the official prompt. The code of corresponding components is loaded only when the route is switched to/INBOX.
Asynchronous import and unpack
The asynchronous import component requires a plug-in for Babel, @babel/plugin-syntax-dynamic-impor.
{
test: /\.(js|jsx)? $/, // regular matches, all.js files are compiled using this rule exclude: /node_modules/, // exclude folders. Loader does not translate files in this folder:"babel-loader"{// presets: [// interpreter configuration [// interpreter configuration ["@babel/preset-env", {
useBuiltIns: "usage",
corejs: 3
},
],
["@babel/preset-react"]
],
plugins: ["@babel/plugin-syntax-dynamic-import"] // Translate plug-in configuration}},Copy the code
New AsyncComponent. Js.
import React, { Component } from "react";
export default function asyncComponent(importComponent) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null
};
}
async componentDidMount() { const { default: component } = await importComponent(); // Render component this.setState({component: component}); }render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
}
return AsyncComponent;
}
Copy the code
Change the lead-in mode
//import Inbox from './src/view/inbox';
const Inbox = asyncComponent(() => import('./src/view/inbox'));
Copy the code
Run the package command
npm run build
Copy the code
npm run server
Copy the code
The home page is not loaded with 1.js
React’s dynamic import component works fine. You can also customize the chunk name according to the official document
const Inbox = asyncComponent(() => import(/* webpackChunkName: "echarts"* /'./src/view/inbox'));
Copy the code
Dependency packages can also be imported asynchronously
async componentDidMount() {
const {default:echarts}= await import('echarts');
var myChart = echarts.init(document.getElementById('main'));
}
Copy the code
conclusion
- Splitchunks. chunks: ‘all’ is recommended, and other parameters remain unchanged. ‘all’ means that both synchronous import and asynchronous import can be unpacked.
- Introduce as few plug-ins as you need, for example Echarts officially provides a method of loading on demand.
- When a plug-in is not available on the home page, try to use asynchronous loading to introduce it.
JS Tree Shaking
Reference code Demo10
Tree Shaking
Tree jitter is a term commonly used in JavaScript context to eliminate dead code. It relies on the static structure of the ES2015 module syntax, namely imports and exports. The names and concepts have been summarized and promoted by the ES2015 module bundler.
Shake the tree. Webpack4.0 automatically removes unwanted js when packing. Of course you need development to work with it: Load on demand let’s take LoDash as an example. To get a sense of how much code we’ve shaken out, let’s unpack the React package and pack it separately.
splitChunks: {
chunks: 'all',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
reactVendors: {
chunks: 'all'.test: /(react|react-dom|react-dom-router)/,
priority: 100,
name: 'react',
},
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true}}}Copy the code
Use LoDash in about.js
import React from 'react';
import _ from 'lodash';
class About extends React.Component {
render() {const s = _. Concat ([1], [2,3,1,2,3,4,6,78,41]);return (
<h3>{s}</h3>
)
}
}
export default About;
Copy the code
Run the package command
npm run build
Copy the code
lodash-es
npm i lodash-es -S
Copy the code
Change the about.js code
import React from 'react';
//import _ from 'lodash';
import { concat } from 'lodash-es';
class About extends React.Component {
render() {const s = concat([1],[2,3,1,2,3,4,6,78,41]);return (
<h3>{s}</h3>
)
}
}
export default About;
Copy the code
Run the package command
npm run build
Copy the code
Gzip compression.
Benefits of Gzip compression.
Open the nuggets home page. Find a random JS resource.
Content-encoding in Response Headers represents the resource transfer format. Note This resource uses a Gzip file. Many companies use Gzip for resource transfer, because code packaged as Gzip for transfer requires very little resource.
Gzip transport is something that the server needs to configure. Even if our upload code is not Gzip compressed, the server is configured to Gzip the resources and transfer them. For example, the Gzip configuration of Nginx.
Gzip configuration is all about server configuration. What do we do? The server actually looks for a gzip file for the resource, and if it doesn’t have one, it gzip compresses and transfers the resource. This gives you extra time to compress. If we generate gzip files through Webpack, we can reduce the time for the server to generate gzip files and reduce the server stress.
Js package compressed configurationoptimization.minimiz
The value of this property can be Boolean or array.
When the property value is Boolean
Minimiz defaults to true when mode is prduction. Automatic compression using the Terser-webpack-plugin.
When the property value is an array
Configure Gzip compression
The default configuration is not changed. Compression plugin compression-webpack-plugin is used.
npm i compression-webpack-plugin -D
Copy the code
The configuration optimization. Minimiz
minimizer: [
new CompressionPlugin({
filename: '[path].gz[query]'[path]. Gz [query] is the default name algorithm:'gzip'// Compression algorithmtest: / \. (js | | | HTML CSS SVG) $/, / / matching resources compressionOptions: {8} level:, / / compression level 9 default threshold: MinRatio: 0.8, // Only deal with resources that compress better than this ratio (minRatio = compressed size/raw size). // Example: You have a 1024B image.png file, and the compressed version is 768B, so minRatio equals 0.75. In other words, when the compressed size/raw size value is less than the minRatio value, // will process the resource. The default is 0.8. deleteOriginalAssets:false// Whether to delete the original asset. }), new TerserPlugin({ parallel:true,}),]Copy the code
npm run build
Copy the code
.zip