Content of this article:
- Reduce webPack packaging time, how to speed up WebPack packaging
- What are some ways to make webPack print smaller packages
- Load code spliting on demand (1. Extract common code 2. Component load on demand) + (dynamic load JS resources in component)
The purpose is: fast + small + on-demand loading
One is speed, one is volume, one is what is used to load what
Reduce webPack packaging time
Optimizing Loader Configuration
For Loaders, the most important factor affecting packaging efficiency is Babel. Because Babel converts code into strings to generate aN AST, and then converts the AST into new code, the larger the project, the more code it converts, and the less efficient it is. Of course, there are ways to optimize it.
First we can optimize the file search scope of Loader
The path of the files processed by Loader, specified with the path of the files not processed. And what type of files does it apply to
module.exports = {
module: {
rules: [{// Use Babel only for js files
test: /\.js$/.loader: 'babel-loader'.// Look only in the SRC folder
include: [resolve('src')].// Not to find the path
exclude: /node_modules/}}}]Copy the code
For Babel, we definitely want it to work only on JS code, and then the code used in node_modules is all compiled, so there’s no need to go through it again.
Of course, this is not enough. We can also cache the Babel compiled files and only compile the changed code files next time, which greatly speeds up the packaging time
loader: 'babel-loader? cacheDirectory=true'Copy the code
Optimize Load configuration summary:
- For example, the path babel-Loader looks for is specified with the path it does not look for
- Cache Babel compiled files
HappyPack turns on multithreaded packaging
Since Node is single-threaded, Webpack is also single-threaded during the packaging process, especially when Loader is executing, and there are many long compilation tasks, which can lead to waiting situations.
HappyPack converts the synchronized execution of the Loader to parallel, thus making full use of system resources to speed up packaging efficiency
module: {
loaders: [
{
test: /\.js$/,
include: [resolve('src')], exclude: /node_modules/, // id'happypack/loader? id=happybabel'
}
]
},
plugins: [
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader? cacheDirectory'], // Open 4 threads: 4})]Copy the code
HappyPack summary:
- Use this plug-in to start multithreaded packaging and make full use of system resources
DllPlugin (prepackage the specified class library)
DllPlugin can pre-package and introduce specific class libraries. This approach greatly reduces the number of times the library needs to be repackaged, only when the library is updated, and it also optimizes the separation of common code into separate files.
Now let’s learn how to use DllPlugin
// In a separate file
// webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
// Libraries that want to be packaged uniformly
vendor: ['react']},output: {
path: path.join(__dirname, 'dist'),
filename: '[name].dll.js'.library: '[name]-[hash]'
},
plugins: [
new webpack.DllPlugin({
// Name must be the same as output.library
name: '[name]-[hash]'.// This property needs to be consistent with the DllReferencePlugin
context: __dirname,
path: path.join(__dirname, 'dist'.'[name]-manifest.json')]}})Copy the code
We then need to execute the configuration file to generate the dependency files, which we then need to import into the project using the DllReferencePlugin
// webpack.conf.js
module.exports = {
/ /... Omit other configurations
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
// Manifest is the json file that was packaged before
manifest: require('./dist/vendor-manifest.json'),}})]Copy the code
DllPlugin summary:
- Pre-pack and introduce custom libraries to reduce the number of times of packing libraries and speed up packaging
- At the same time, the common code is extracted into a separate file
Parallel code compression
In Webpack3, we normally use UglifyJS to compress the code, but this is single-threaded. To make it more efficient, we can use the Webpack-parallle-Uglify-plugin to run UglifyJS in parallel.
In Webpack4, we don’t need to do any of these things. We just need to set mode to Production to enable this function by default. Code compression is also a must for performance optimization. Of course, we can compress not only JS code, but also HTML and CSS code. In the process of compressing JS code, we can also implement configuration functions such as deleting console.log code.
Code parallel compression summary
- Webpack4 production mode. By default, multiple child processes (threads) are enabled. Instead of one by one compression, parallel compression is changed
Some small optimization points
There are also some small optimizations we can make to speed up packing
resolve.extensions
: indicates a list of file suffixes. The default lookup order is['.js', '.json']
If your import files do not have suffixes, you will find files in this order. We should try toReduce the length of the list of suffixes, and then list the most frequent suffixes firstresolve.alias
: Can passAlias to map a pathAllows Webpack to find the path fastermodule.noParse
If you are sure that there are no other dependencies under a file, you can use this property to make WebpackDo not scan the file, which is useful for large libraries
Reduce the size of Webpack files
Scope Hoisting
Scope colliers will analyze the dependencies between modules and try to merge the packaged modules into a function as much as possible.
Because Scope Hositing needs to analyze dependencies between modules, the source code must use ES6 modular statements or it won’t work, just like Tree Shaking
Let’s say we want to package two files
// test.js
export const a = 1
// index.js
import { a } from './test.js'
Copy the code
In this case, our packaged code would look something like this
[
/* 0 */
function (module, exports, require) {
/ /...
},
/ * 1 * /
function (module, exports, require) {
/ /...}]Copy the code
However, if we use Scope colliers, the code will be merged into one function as much as possible, so it will become similar code like this
[
/* 0 */
function (module, exports, require) {
/ /...}]Copy the code
This packaging approach generates significantly less code than the previous one. If you want to open this function in the Webpack4, only need to enable optimization. ConcatenateModules is ok.
module.exports = {
optimization: {
concatenateModules: true}}Copy the code
Scope collieries summary:
- Whenever possible, merge the packaged modules into a single function
Tree Shaking (Default for WebPack 4 production)
Tree Shaking is a term often used to remove dead-code from JS when packaging. It relies on the static structure features of imports and exports in the ES6 module system
Tree Shaking can remove unreferenced code from a project, for example
// test.js
export const a = 1
export const b = 2
// index.js
import { a } from './test.js'
Copy the code
In this case, the variable b in the test file will not be packaged into the file if it is not used in the project.
If you are using Webpack 4, this optimization feature is automatically enabled when you start the production environment.
Iii. On-demand loading + Dynamic loading + Asynchronous Loading (to be improved)
According to the need to load
Presumably everyone in the development of SPA projects, there will be a dozen or more routing pages in the project. If we package all of these pages into a single JS file, it will combine multiple requests, but it will also load a lot of unnecessary code and take longer. So in order to present the home page to the user faster, we certainly want the home page to load as small as possible, at this time we can use on-demand loading, each routing page packaged as a separate file. Of course, not only can routes be loaded on demand, but also for large libraries such as LoadAsh.
The implementation of the load on demand code will not be expanded here because the implementation is different depending on the framework used. Of course, their usage may be different, but the underlying mechanism is the same. When it is used, it downloads the corresponding file, returns a Promise, and executes a callback when the Promise is successful.
Load on Demand summary:
- Third-party component libraries are loaded on demand
- Routing pages are packaged as separate files that can be loaded on demand to speed up home page access. When other pages are accessed, the corresponding JS is loaded
Load Code Splitting on demand
build.js
In the file (filename depends on inwebpack.config.js
In the fileoutput.filename
), but in larger projects,build.js
May be too large, resulting in a long page load time. That’s when you need itcode splitting
.code splitting
That’s splitting the file into chunks(chunk)
We can define some split points(split point)
According to these split points, the file is divided into blocks and the on-demand loading is realized.
We can configure the router to load components on demand, which can reduce the size of build.js and optimize the load speed when the individual component files are large. (If the component is small, it will increase the load time by adding additional HTTP requests.)
There are two ways to load on demand:
Webpack supports defining split points through
require.ensure
Load on demand.(1) Third-party class libraries are individually packaged
Assuming that the project introduces jjquery. Js and respond.js, we can configure multiple entries in webpack.config.js to package the two third-party libraries separately.
-
Do the configuration in webpack.config.js
//webpack.config.js // Add the corresponding third-party class library to the entry: {bundle:'./src/main.js', vendor: ['the. / SRC/lib/jquery - 1.10.2. Min. Js'.'./src/lib/respond.min.js']} / / in the plugins add CommonChunkPlugin plugins: [new webpack.optimize.Com monsChunkPlugin ({name:'vendor', filename: 'vendor.bundle.js'})]Copy the code
-
Run NPM run build. At this time, two files are generated in the dist directory, namely build.js and vendor.bundle.js
(2) AMD CMD component load configuration on demand
//app.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'Use (VueRouter) // const ComA = resolve => require(['./components/A.vue' ], resolve);
// const ComB = resolve => require(['./components/B.vue' ], resolve);
// const ComC = resolve => require(['./components/C.vue'], resolve); Const ComA = resolve => require. Ensure ([], () => resolve(require())'./components/A.vue')));
const ComB = resolve => require.ensure([], () => resolve(require('./components/B.vue')));
const ComC = resolve => require.ensure([], () => resolve(require('./components/C.vue')));
const router = new VueRouter({
routes: [
{
name: 'component-A',
path: '/a',
component: ComA
},
{
name: 'component-B',
path: '/b',
component: ComB
},
{
name: 'component-C',
path: '/c',
component: ComC
}
]
})
new Vue({
el: '#app',
router: router,
render: h => h(App)
})Copy the code
-
Configure output.chunkfilename in webpack.config.js,
//webpack.config.js
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'// add chundkFilename to chunkFilename:'[name].[chunkhash:5].chunk.js'
}Copy the code
perform
npm run build
At this time,
dist
Five files are generated in the directory, and the extra three files are the corresponding
A.vue
.
B.vue
.
C.vue
These three components
summary
In this chapter, we learned how to use Webpack to optimize performance and reduce packaging time.
Versions of Webpack change quickly, and optimizations can vary from one version to the next, so I didn’t use too much code to show how to implement a feature. The point of this chapter is to learn how we can optimize, and specific code implementations can look for specific versions of the code.
This article is from the Gold Mining booklet
Summary (fast + Small + On-demand loading) :
- Fast – Packaging speed (Loader configuration optimization, specifying which path to process, which not to process, parallel compression, parallel compression, third-party dependencies to do caching do not repeat)
- Tree -shaking removes useless code + modules into a function + pages packaged as separate Js, speeding up the home page
- Load components and third-party resources on demand