Introduction to a,
1.1 Initializing a project
Create a new directory and initialize NPM
npm init
Copy the code
Webpack is running in the Node environment and we need to install the following two NPM packages
npm i -D webpack webpack-cli
// NPM i-d is short for NPM install --save-dev
// NPM i-s is short for NPM install --save
Copy the code
If the download fails, install the Taobao image:
npm install -g cnpm --registry=http://registry.npm.taobao.org
Copy the code
CNPM: cannot load file C:\Users\ HP \AppData\ NPM \cnpm.ps1, because running scripts on this system is forbidden. To run Power Shell as administrator:
set-ExecutionPolicy RemoteSigned
Copy the code
Then type A and press Enter to use CNPM, and then:
cnpm i -D webpack webpack-cli
Copy the code
You can download it successfully.
Create a new folder, SRC, then create a new file, main.js, and write a little code to test it out
console.log('Test... ')
Copy the code
To configure package.json:
"scripts": {
"build": "webpack src/main.js"
}
Copy the code
Perform:
npm run build
Copy the code
At this point, if you have generated a dist folder with main.js inside it, you have packaged it successfully.
1.2 configuration
The simple example above is just webPack’s own default configuration, but let’s implement a richer custom configuration
-
Create a new build folder with a new webpack.config.js inside
// webpack.config.js const path = require('path'); module.exports = { mode:'development'.// Development mode entry: path.resolve(__dirname,'.. /src/main.js'), // Import file output: { filename: 'output.js'.// The name of the packaged file path: path.resolve(__dirname,'.. /dist') // You do not need to create a new directory. The directory is automatically generated after the package is completed}}Copy the code
-
Change our packaging command
"scripts": { "build": "webpack --config build/webpack.config.js" } Copy the code
-
When you run the NPM run build, you’ll see that the dist directory generates the output.js file where output.js is the file that we need to actually run in the browser. Of course, that’s not all there is to it, so let’s get you up to speed on WebPack with a real case study.
1.3 Configuring an HTML Template
The js file is packaged, but it is not possible to manually introduce packaged JS into your HTML file every time.
Some of you may think that the name of the package JS file is always fixed (output.js). So you don’t have to change the name of the imported file every time? In fact, we often use this configuration in daily development:
module.exports = {
// Omit other configurations
output: {
filename: '[name].[hash:8].js'.// The name of the packaged file
path: path.resolve(__dirname,'.. /dist') // The packaged directory}} Copy the codeCopy the code
The dist directory file generated at this time is as follows
For caching (browser caching strategy), you will find that the js file is packaged with a different name each time.
1.3.1 HTML – webpack – the plugin
We need to import the webpack JS file into HTML, but it’s too cumbersome to manually change the JS file name every time, so we need a plugin to do it for us.
npm i -D html-webpack-plugin
Copy the code
Create a folder named “public” in the build class and create an index. HTML inside.
At the same time, add the following to webpack.config.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development'.// Development mode
entry: path.resolve(__dirname, '.. /src/main.js'), // Import file
output: {
filename: '[name].[hash:8].js'.// The name of the packaged file (the name of the packaged file is different each time for caching)
path: path.resolve(__dirname, '.. /dist') // The packaged directory
},
plugins: [
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'.. /public/index.html') // Introduce packaged JS to index.html under public}})]Copy the code
Using the command packaging, the dist file will appear index.html, and you can see that the js file generated by the packaging has been automatically imported into the HTML file
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<script src="main.de1ae303.js"></script></body>
</html>
Copy the code
1.3.2 How to develop multi-entry files
Generate multiple instances of htmL-Webpack-plugin to solve this problem
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode:'development'.// Development mode
entry: {
main:path.resolve(__dirname,'.. /src/main.js'),
header:path.resolve(__dirname,'.. /src/header.js')},output: {
filename: '[name].[hash:8].js'.// The name of the packaged file
path: path.resolve(__dirname,'.. /dist') // The packaged directory
},
plugins: [new HtmlWebpackPlugin({
template:path.resolve(__dirname,'.. /public/index.html'),
filename:'index.html'.chunks: ['main'] // The module name corresponding to the entry file
}),
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'.. /public/header.html'),
filename:'header.html'.chunks: ['header'] // The module name corresponding to the entry file]}}),Copy the code
After packaging, the file directory is as follows:
1.3.3 the clean – webpack – the plugin
Each time we run NPM run build, we will find that the files in the dist folder will remain. Here we recommend a plugin to help us clean the folder before packing the output
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
/ /... Omit other configurations
plugins: [/ /... Omit other plug-ins
new CleanWebpackPlugin()
]
}
Copy the code
1.4 refer to CSS
1.4.1 loader
Our entry file is main.js, so we need to introduce our CSS file in the entry.
So, we also need some loaders to parse our CSS files
npm i -D style-loader css-loader
Copy the code
If we used LESS to build the style, we would need to install two more
npm i -D less less-loader
Copy the code
The configuration file is as follows:
// webpack.config.js
module.exports = {
/ /... Omit other configurations
module: {rules:[
{
test:/\.css$/,
use:['style-loader'.'css-loader'] // Parse the principle from right to left
},
{
test:/\.less$/,
use:['style-loader'.'css-loader'.'less-loader'] // Parse the principle from right to left}}}]Copy the code
When the browser opens the HTML below, we find that CSS has been added to the HTML file through the style tag, but if there are many style files, it will be confusing to add them all to the HTML. So what we want to do is we want to take the CSS and we want to take the CSS and we want to bring it in as an external link and what do we do? This is where plug-ins come in
1.4.2 split CSS
Before WebPack 4.0, we used the extract-text-webpack-plugin to extract CSS styles from the JS file into a separate CSS file. After webpack4.0, it is recommended to use the mini-css-extract-plugin to package CSS files
npm i -D mini-css-extract-plugin
Copy the code
The configuration file is as follows
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
/ /... Omit other configurations
module: {
rules: [{test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'.'less-loader']],}},plugins: [
new MiniCssExtractPlugin({
filename: "[name].[hash].css".chunkFilename: "[id].css",}})]Copy the code
1.4.3 Splitting Multiple CSS components
To be more specific, the mini-css-extract-plugin we used above merges all the CSS styles into a single CSS file. If you want to split multiple CSS files into one to one, we need to use the extract-text-webpack-plugin, which is not currently supported by the Mini-css-extract-plugin. We need to install the @next version of the extract-text-webpack-plugin
npm i -D extract-text-webpack-plugin@next
Copy the code
webpack.config.js
const path = require('path');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
let indexLess = new ExtractTextWebpackPlugin('index.less');
let indexCss = new ExtractTextWebpackPlugin('index.css');
module.exports = {
module: {rules:[
{
test:/\.css$/,
use: indexCss.extract({
use: ['css-loader']})}, {test:/\.less$/,
use: indexLess.extract({
use: ['css-loader'.'less-loader']})}]},plugins:[
indexLess,
indexCss
]
}
Copy the code
1.4.4 Adding a browser prefix to the CSS
npm i -D postcss-loader autoprefixer
Copy the code
Configuration is as follows
// webpack.config.js
module.exports = {
module: {rules:[
{
test:/\.less$/,
use:['style-loader'.'css-loader'.'postcss-loader'.'less-loader'] // Parse the principle from right to left}}}]Copy the code
Next, we need to introduce autopreFixer to make it work, configured directly in webpack.config.js
{
test: /\.less$/,
use: indexLess.extract({
use: ['style-loader'.'css-loader', {
loader: 'postcss-loader'.options: {
plugins: [require('autoprefixer')]}},'less-loader']})// Parse the principle from right to left
},
Copy the code
1.5 Package pictures, fonts, and media
When webPack loads CSS background images, network images pointed to by img elements, or images imported using ES6 import, you need to use url-Loader or file-loader. Url-loader and file-Loader can load any file.
File-loader processes the file (mainly processing the file name and path and parsing the url of the file) and moves the file to the output directory
Url-loader is used in combination with file-Loader and has a similar function to file-Loader. Url-loader can convert images into Base64 strings and load images faster. If the image is too large, it needs to use file-Loader to load local images. Therefore, url-loader can set the number of bytes of the image, and use file-loader to load the image.
webpack.config.js
module.exports = {
// Omit the other configuration...
module: {
rules: [
// ...
{
test: /\.(jpe? g|png|gif)$/i.// Image file
use: [
{
loader: 'url-loader'.options: {
limit: 10240.fallback: {
loader: 'file-loader'.options: {
name: 'img/[name].[hash:8].[ext]'}}}}]}, {test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\? . *)? $/.// Media file
use: [
{
loader: 'url-loader'.options: {
limit: 10240.fallback: {
loader: 'file-loader'.options: {
name: 'media/[name].[hash:8].[ext]'}}}}]}, {test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/i./ / font
use: [
{
loader: 'url-loader'.options: {
limit: 10240.fallback: {
loader: 'file-loader'.options: {
name: 'fonts/[name].[hash:8].[ext]'}}}}]},]}}Copy the code
1.6 Babel Escaping JS files
In order to make our JS code compatible with more environments we need to install dependencies
npm i -D babel-loader @babel/preset-env @babel/core
Copy the code
Note the version mapping between Babel-Loader and Babel-Core
babel-loader
8. Xbabel-core
7.xbabel-loader
7. Xbabel-core
6.x
The configuration is as follows:
// webpack.config.js
module.exports = {
// Omit the other configuration...
module: {rules:[
{
test:/\.js$/,
use:{
loader:'babel-loader'.options: {presets: ['@babel/preset-env']}},exclude:/node_modules/}}},]Copy the code
The above babel-Loader will only convert ES6/7/8 syntax to ES5 syntax, but will not convert new apis such as promise, Generator, Set, Maps, Proxy, etc. At this point we need a babel-polyfill to help us convert.
npm i @babel/polyfill
Copy the code
// webpack.config.js
const path = require('path')
module.exports = {
entry: ["@babel/polyfill",path.resolve(__dirname,'.. /src/main.js')].// Import file
}
Copy the code
Ii. Build the Vue development environment
The small examples above have helped us implement the packaging of CSS, images, JS, HTML, etc. But we still need the following configurations:
2.1 Parsing the.vue file
npm i -D vue-loader vue-template-compiler vue-style-loader
npm i -S vue
Copy the code
Vue-loader parses the. Vue file vue-template-compiler is used to compile templates
The configuration is as follows:
const vueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
module: {rules: [{test:/\.vue$/,
use:['vue-loader']},]},resolve: {// Alias, easy to import files
alias: {'vue$':'vue/dist/vue.runtime.esm.js'.The '@':path.resolve(__dirname,'.. /src')},// The following files can be imported without the suffix
extensions: [The '*'.'.js'.'.json'.'.vue']},plugins: [new vueLoaderPlugin()
]
}
Copy the code
Add vue-style-loader to the loader as well
{
test: /\.css$/,
use: indexCss.extract({
use: ['vue-style-loader','style-loader', 'css-loader', {
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}]
}) // Parse the principle from right to left
},
{
test: /\.less$/,
use: indexLess.extract({
use: ['vue-style-loader','style-loader', 'css-loader', {
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}, 'less-loader']
}) // Parse the principle from right to left
},
Copy the code
2.2 Webpack-dev-server hot update
npm i -D webpack-dev-server
Copy the code
The webpack.config.js configuration is as follows
const Webpack = require('webpack')
module.exports = {
/ /... Omit other configurations
devServer: {port:3000.hot:true.contentBase:'.. /dist'
},
plugins: [new Webpack.HotModuleReplacementPlugin()
]
}
Copy the code
// package.json
"scripts": {
"build": "webpack --config build/webpack.config.js"."dev": "webpack-dev-server --config build/webpack.config.js --open"
}
Copy the code
Run NPM run dev to run the project
The complete configuration is as follows
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin') // index.html automatically introduces the packaged JS file
const { CleanWebpackPlugin } = require('clean-webpack-plugin') // Clean up the files generated in the last package
const MiniCssExtractPlugin = require("mini-css-extract-plugin") / / split CSS
const vueLoaderPlugin = require('vue-loader/lib/plugin') // Parse the.vue file
const Webpack = require('webpack')
const devMode = process.argv.indexOf('--mode=production') = = = -1; // Whether production environment
module.exports = {
mode: 'development'.// Development mode
entry: ["@babel/polyfill", path.resolve(__dirname, '.. /src/main.js')].// Entry file (compiled using @babel/polyfill)
output: {
filename: '[name].[hash:8].js'.// The name of the packaged file (the name of the packaged file is different each time for caching)
path: path.resolve(__dirname, '.. /dist') // The packaged directory
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '.. /public/index.html') // Introduce packaged JS to index.html under public
}),
new CleanWebpackPlugin(), // Clean up the js file generated by the last packaging
/ / compress CSS
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css'.chunkFilename: devMode ? '[id].css' : '[id].[hash].css'
}),
new vueLoaderPlugin(),
new Webpack.HotModuleReplacementPlugin() / / hot update].module: {
rules: [{test: /\.css$/,
use: [{
loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
options: {
publicPath: ".. /dist/css/".hmr: devMode
}
}, 'css-loader', {
loader: 'postcss-loader'.options: {
plugins: [require('autoprefixer')]}}],}, {test: /\.less$/,
use: [{
loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
options: {
publicPath: ".. /dist/css/".hmr: devMode
}
}, 'css-loader'.'less-loader', {
loader: 'postcss-loader'.options: {
plugins: [require('autoprefixer')]}}]}, {test: /\.(jpe? g|png|gif)$/i.// Image file
use: [
{
loader: 'url-loader'.options: {
limit: 10240.fallback: {
loader: 'file-loader'.options: {
name: 'img/[name].[hash:8].[ext]'}}}}]}, {test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\? . *)? $/.// Media file
use: [
{
loader: 'url-loader'.options: {
limit: 10240.fallback: {
loader: 'file-loader'.options: {
name: 'media/[name].[hash:8].[ext]'}}}}]}, {test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/i./ / font
use: [
{
loader: 'url-loader'.options: {
limit: 10240.fallback: {
loader: 'file-loader'.options: {
name: 'fonts/[name].[hash:8].[ext]'}}}}]},// Compile js with Babel
{
test: /\.js$/,
use: {
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env']}},exclude: /node_modules/
},
// Parse the.vue file
{
test: /\.vue$/,
use: ['vue-loader']]}},resolve: {
/ / alias
alias: {
'vue$': 'vue/dist/vue.runtime.esm.js'.The '@': path.resolve(__dirname, '.. /src')},// The following files can be imported without the suffix
extensions: [The '*'.'.js'.'.json'.'.vue']},devServer: {
port: 3000.hot: true.contentBase: '.. /dist'}}Copy the code
2.3 Configuring Packaging Commands
Previously we configured the package and run commands:
"scripts": {
"build": "webpack --config build/webpack.config.js"."dev": "webpack-dev-server --config build/webpack.config.js --open"
}
Copy the code
Let’s test this by creating a new main.js in SRC:
import Vue from "vue";
import App from "./App";
new Vue({
render: h= > h(App)
}).$mount('#app');
Copy the code
Create an app.vue
<template> <div id="container"> <h1>{{initData}}</h1> </div> </template> <script> export default { name: 'App', data() {return {initData: 'Vue development environment running successfully! '}; }}; </script>Copy the code
Add a box with the ID of app to the index.html in public
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
Copy the code
Run NPM run dev, if the browser appears Vue development environment ran successfully! Then congratulations, you have successfully taken the first step.
2.4 Development environment and production environment
For the actual project, we need to separate the development environment from the production environment, and we added two more files to the original webpack.config.js
-
Webpack.dev.js development environment configuration file, the development environment mainly implements hot updates, do not compress the code, complete sourceMap
-
Webpack.prod. js production environment configuration file. Production environment mainly implements code compression, CSS file extraction, reasonable sourceMap, split code. The following modules need to be installed:
cnpm i -D webpack-merge copy-webpack-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin
Copy the code
webpack-merge
Merge configurationcopy-webpack-plugin
Copying static Resourcesoptimize-css-assets-webpack-plugin
Compress CSSuglifyjs-webpack-plugin
Compression jswebpack mode
Set up theproduction
The js code is automatically compressed. In principle, it doesn’t need to be introduceduglifyjs-webpack-plugin
Repeat work. butoptimize-css-assets-webpack-plugin
The compression of CSS breaks the js compression, so we introduce it hereuglifyjs
Be compressed
webpack.config.js
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const devMode = process.argv.indexOf('--mode=production') = = = -1;
module.exports = {
entry: {
main: path.resolve(__dirname, '.. /src/main.js')},output: {
path: path.resolve(__dirname, '.. /dist'),
filename: 'js/[name].[hash:8].js'.chunkFilename: 'js/[name].[hash:8].js'
},
module: {
rules: [{test: /\.js$/,
use: {
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env']}},exclude: /node_modules/
},
{
test: /\.vue$/,
use: [{
loader: 'vue-loader'.options: {
compilerOptions: {
preserveWhitespace: false}}}]}, {test: /\.css$/,
use: [{
loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
options: {
publicPath: ".. /dist/css/".hmr: devMode
}
}, 'css-loader', {
loader: 'postcss-loader'.options: {
plugins: [require('autoprefixer')]}}]}, {test: /\.less$/,
use: [{
loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
options: {
publicPath: ".. /dist/css/".hmr: devMode
}
}, 'css-loader'.'less-loader', {
loader: 'postcss-loader'.options: {
plugins: [require('autoprefixer')]}}]}, {test: /\.(jep? g|png|gif)$/,
use: {
loader: 'url-loader'.options: {
limit: 10240.fallback: {
loader: 'file-loader'.options: {
name: 'img/[name].[hash:8].[ext]'}}}}}, {test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\? . *)? $/,
use: {
loader: 'url-loader'.options: {
limit: 10240.fallback: {
loader: 'file-loader'.options: {
name: 'media/[name].[hash:8].[ext]'}}}}}, {test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/i,
use: {
loader: 'url-loader'.options: {
limit: 10240.fallback: {
loader: 'file-loader'.options: {
name: 'media/[name].[hash:8].[ext]'}}}}}]},resolve: {
alias: {
'vue$': 'vue/dist/vue.runtime.esm.js'.The '@': path.resolve(__dirname, '.. /src')},extensions: [The '*'.'.js'.'.json'.'.vue']},plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '.. /public/index.html')}),new vueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css'.chunkFilename: devMode ? '[id].css' : '[id].[hash].css'}})]Copy the code
- webpack.dev.js
const Webpack = require('webpack')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge') // Merge the webpack.config.js configuration
module.exports = WebpackMerge(webpackConfig, {
mode: 'development'.devtool: 'cheap-module-eval-source-map'.devServer: {
port: 3000.hot: true.contentBase: '.. /dist'
},
plugins: [
new Webpack.HotModuleReplacementPlugin()
]
})
Copy the code
- webpack.prod.js
const path = require('path')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge') // Merge the configurations
const CopyWebpackPlugin = require('copy-webpack-plugin') // Copy the static resource
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') / / compress CSS
const UglifyJsPlugin = require('uglifyjs-webpack-plugin') Js / / compression
module.exports = WebpackMerge(webpackConfig, {
mode: 'production'.devtool: 'cheap-module-source-map'.plugins: [
new CopyWebpackPlugin([{
from: path.resolve(__dirname, '.. /public'),
to: path.resolve(__dirname, '.. /dist')}])],optimization: {
minimizer: [
new UglifyJsPlugin({Js / / compression
cache: true.parallel: true.sourceMap: true
}),
new OptimizeCssAssetsPlugin({})
],
splitChunks: {
chunks: 'all'.cacheGroups: {
libs: {
name: "chunk-libs".test: /[\\/]node_modules[\\/]/,
priority: 10.chunks: "initial" // Only package the third party that you relied on initially}}}}})Copy the code
2.5 Optimized WebPack configuration
It’s very practical for us to optimize the configuration, it’s really related to the size of the files you pack, how fast you pack, etc. Specific optimization can be divided into the following points:
2.5.1 Optimize the packing speed
2.5.1.1 Setting Mode and Devtool parameters properly
mode
Can be set upDevelopment, production
Two parameters. If you don’t set it,webpack4
willmode
The default value is set toproduction
production
Mode will be performedtree shaking
(remove useless code) anduglifyjs
(Code compression obfuscation)
2.5.1.2 Narrowing the File Search Scope (Configure Include exclude Alias noParse Extensions)
alias
: When our code appearsimport 'vue'
Webpack will use an upward recursive searchnode_modules
Directory. To reduce the search scope we can simply tell WebPack where to look. Which is the alias (alias
).include exclude
: Same configurationinclude exclude
You can also reducewebpack loader
Search conversion time.noParse
: when used in our codeimport jq from 'jquery'
When,webpack
The jQ library will be resolved to see if it has dependencies on other packages. But we have a similarjquery
This type of dependent library is generally considered not to reference other packages (except in particular, at your discretion). increasenoParse
Property, which tellswebpack
No parsing to increase packing speed.extensions
:webpack
Depending on theextensions
Defined suffix search files (more frequent file types are written first)
2.5.1.3 Using HappyPack to Enable Multi-Process Loader Conversion
In the WebPack build process, most of the actual time is spent on the loader parsing conversion and compression of the code. In daily development, we need to use Loader to convert js, CSS, pictures, fonts and other files, and the amount of data in the converted files is also very large. Because of the single-threaded nature of JS, these transformation operations cannot process files concurrently, but need to process files one by one. The basic principle of HappyPack is to split this part of the task into multiple sub-processes to process in parallel, which then send the results to the main process, thus reducing the overall build time
cnpm i -D happypack
Copy the code
const HappyPack = require('happypack')
const os = require('os')
const happyThreadPool = HappyPack.ThreadPool({size: os.cpus().length})
model.exports = {
module: {
rules: [{test: /\.js$/.// Pass the js file to the HappyPack instance whose ID is happyBabel
use: [{loader:'happypack/loader? id=happyBabel'}].exclude: /node_modules/}].plugin: [
new HappyPack({
id: 'happyBabel'.// Id corresponding to loader
Loaders: loaders: loaders: loaders: loaders: loaders
loaders: [{loader: 'babel-loader'.options: {
presets: [['@babel/preset-env']],
cacheDirectory: true}}].threadPool: happyThreadPool // Share the process pool}}})]Copy the code
2.5.1.4 webpack – parallel – uglify – the plugin
Webpack-parallel-uglify-plugin: enhances code compression
The loader conversion has been optimized above, so there is another difficulty in optimizing the compression time of the code.
cnpm i -D webpack-parallel-uglify-plugin
Copy the code
const ParallelUglifyPlugin = require("webpack-parallel-uglify-plugin")
module.exports = {
optimization: {
minimizer: [
new ParallelUglifyPlugin({
cacheDir: '.cache/'.uglifyJS: {
output: {
comments: false.beautify: false
},
compress: {
drop_console: true.collapse_vars: true.reduce_vars: true}}})Copy the code
2.5.1.5 Removing a Third-party Module
Remove the third party module: improve packing speed
For static dependency files that don’t change often in a development project. Similar to our elementUi, Vue family bucket, etc. Since changes are rare, we don’t want these dependencies to be integrated into every build logic. The advantage of this is that every time I change the file of my native code, WebPack only needs to package my project’s own file code, instead of compiling third-party libraries. As long as we do not upgrade third-party packages, webPack will not package these libraries, which will quickly increase the speed of packaging.
Here we use the DllReferencePlugin built into WebPack to pull out. Create a new webpack.dll.config.js code in the same directory as the WebPack configuration file
// webpack.dll.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = {
// An array of modules you want to package
entry: {
vendor: ['vue']},output: {
path: path.resolve(__dirname, 'dll/js'), // The output location of the packaged file
filename: '[name].dll.js'.library: '[name]_library'
// This should be consistent with 'name: '[name]_library',' in webpack.dllplugin.
},
plugins: [
new webpack.DllPlugin({
path: path.resolve(__dirname, '[name]-manifest.json'),
name: '[name]_library'.context: __dirname
})
]
};
Copy the code
Configure the following commands in package.json
"dll": "webpack --config build/webpack.dll.config.js"
Copy the code
Next, add the following code to our webpack.config.js
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin') // NPM I installation
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./vendor-manifest.json')}),new AddAssetHtmlPlugin(
[
{
filepath: path.resolve(__dirname, "dll/js/*.dll.js"), // Add the generated DLL file to index.html},])]};Copy the code
perform
npm run dll
Copy the code
We’ll find that vendor.dll.js generates the collection third place code we need. This way we don’t need to NPM run DLLS if we haven’t updated third party dependencies. When we run NPM run dev NPM run build directly, we see a significant improvement in our packaging speed. Because we have already extracted third-party dependencies through dllPlugin.
2.5.1.6 cache – loader
– Loader: Configure cache
We compile all the files over and over again every time we execute a build. Can this work be cached? Yes, most loaders provide cache configuration items. For example, in babel-Loader, you can enable caching by setting cacheDirectory. Babel-loader? CacheDirectory =true writes each compilation to a hard disk file (the default is node_modules/.cache/ babel-Loader at the project root, but you can customize it)
But what if the loader doesn’t support caching? We also have methods, we can use cache-Loader, and what it does is very simple, what babel-Loader does when cache is enabled, it writes the compiled results of loader to the hard disk cache. The next build will be compared, and if the file has not changed from the previous one, the cache will be used. The usage method is shown in the official Demo. Add this loader before other loaders with high performance overhead
npm i -D cache-loader
Copy the code
modeule.exports = {
module: {
rules: [{test: /\.ext$/,
use: ['cache-loader'. loaders],include: path.resolve(__dirname,'src')}]}}Copy the code
2.5.2 Optimizing the Volume of packaged Files
We have optimized the packaging speed, but the volume of the files after packaging is very large, resulting in slow page loading, waste of traffic, etc. Next, let’s continue to optimize the file volume
2.5.2.1 Introducing webpack-bundle-Analyzer to analyze packaged files
Webpack-bundle-analyzer presents the packaged bundle of content as an intuitive tree for easy interaction, letting us know what is really introduced in the package we are building
npm i -D webpack-bundle-analyzer
Copy the code
const
Copy the code
Next, configure the launch command in package.json
"analyz": "NODE_ENV=production npm_config_report=true npm run build"
Copy the code
For Windows, install the NPM i-D cross-env
"analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"
Copy the code
The NPM Run Analyz browser will then automatically open the file dependency graph page
2.5.2.2 externals
If we want to refer to a library that we don’t want to webpack, and we don’t want to use it as CMD, AMD, or Window/Global in our applications, we can configure Externals. This functionality is primarily used when creating a library, but we can also use Externals in our projects to remove static resources that do not need to be packaged from the build logic and reference them using CDN.
Sometimes we want to use a library that we introduced through script, such as jquery introduced through CDN, but we still use it as require, but we don’t want WebPack to compile it into a file. Here the official website case is clear enough, you are interested can click to understand
The webpack website example is as follows
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous">
</script>
Copy the code
module.exports = {
/ /...
externals: {
jquery: 'jQuery'}};Copy the code
import $ from 'jquery';
$('.my-element').animate(/ *... * /);
Copy the code
2.5.2.3 Tree – shaking
I mention tree-shaking separately because there is a pit. The primary role of Tree-shaking is to clean up useless parts of your code. Tree shaking is now automatically enabled in WebPack4 when we set mode to Production. But for this to work, the generated code must be an ES6 module. You cannot use other types of modules such as CommonJS streams. There is a slight problem with using Babel, because Babel’s preset defaults to translate any module type to CommonJS, which causes tree-shaking to fail. To fix this, simply set modules: false to.babelrc or to webpack.config.js
// .babelrc
{
"presets": [["@babel/preset-env",
{
"modules": false}}]]Copy the code
or
// webpack.config.js
module: {
rules: [{test: /\.js$/,
use: {
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env', { modules: false}}},exclude: /(node_modules)/}}]Copy the code