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

  1. babel-loader8. Xbabel-core 7.x
  2. babel-loader7. 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-mergeMerge configuration
  • copy-webpack-pluginCopying static Resources
  • optimize-css-assets-webpack-pluginCompress CSS
  • uglifyjs-webpack-pluginCompression js
  • webpack modeSet up theproductionThe js code is automatically compressed. In principle, it doesn’t need to be introduceduglifyjs-webpack-pluginRepeat work. butoptimize-css-assets-webpack-pluginThe compression of CSS breaks the js compression, so we introduce it hereuglifyjsBe 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

  • modeCan be set upDevelopment, productionTwo parameters. If you don’t set it,webpack4willmodeThe default value is set toproduction
  • productionMode 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_modulesDirectory. To reduce the search scope we can simply tell WebPack where to look. Which is the alias (alias).
  • include exclude: Same configurationinclude excludeYou can also reducewebpack loaderSearch conversion time.
  • noParse : when used in our codeimport jq from 'jquery'When,webpackThe jQ library will be resolved to see if it has dependencies on other packages. But we have a similarjqueryThis type of dependent library is generally considered not to reference other packages (except in particular, at your discretion). increasenoParseProperty, which tellswebpackNo parsing to increase packing speed.
  • extensions :webpackDepending on theextensionsDefined 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