Webpackage 5 has been around for a while, but vue-CLI will not introduce webpackage 5 until version 5.0. The main concern is nodeJS polyfills. Before vuE-CLI 5.0 is stable, build it up by yourself first. Some conventions should be consistent with VUe-CLI as far as possible. The tutorial is not for beginners, you need to know the basics of Webpack such as Loader, Plugins, and Resolve

1. Initialization

Create a directory and run commands in this directory

npm init
Copy the code

You will be prompted with a few options, except that the entry file is index.js by default, so we’ll keep typing main.js with vue-cli and just press enter for the rest. A package.json file is generated in the directory

2. Set up the WebPack environment

npm i webpack webpack-merge webpack-dev-serve webpack-cli -D
Copy the code

Merge webPack-merge is used to merge webpack configuration files. For example, a project has three webpack configuration files, a basic package image style, a production environment, a development environment. The development environment needs to merge the basic configuration file and export webpack-dev-serve to provide a local serve server, Webpack5 comes with a serve but it is rumored that the log is not good, temporarily or dev serve webpack-CLI Webpack – CLI allows you to invoke Webpack from the command line

3. Create directories and files

Create the directory and file in the red box with index. HTML for consistency directly using vue-CLI index. HTML. Delete the link line to the ICO file

<! DOCTYPE html> <html lang=""> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta Name = "viewport" content = "width = device - width, initial - scale = 1.0" > < title > < % = htmlWebpackPlugin. Options. The title % > < / title > </head> <body> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <! -- built files will be auto injected --> </body> </html>Copy the code

Of course, you could define a simpler one yourself, like this

<! DOCTYPE html> <html lang=""> <body> <div id="app"></div> </body> </html>Copy the code

4. Basic configuration

Let’s start with the simplest configuration and see if WebPack works

Webpack.com mon. Js configuration

Exports =>{return {entry:'./ SRC /main.js',// stats: 'errors-only',// Display logo output:{filename: 'assets/js/[name].code.js', chunkFilename: 'assets/js/[name].bundle.js',// dynamically import separate bundles such as lodashjs with annotations import(/* webpackChunkName: "Lodash" */ 'lodash') will be packaged as lodash.bundle.js path: path.resolve(__dirname, '.. /dist'), } } }Copy the code

Webpack. Prod. Js configuration

//const webpack = require('webpack'); const { merge } = require('webpack-merge'); const common = require('./webpack.common.js'); module.exports = env =>{ let pro_config = { mode:'production', } return merge(common(env),pro_config) // merge configuration}Copy the code

main.js

console.log('this is mainjs')
Copy the code

package.json

  "scripts": {
    "build": "webpack  --config build/webpack.prod.js"
  },
Copy the code

It’s all very basic configuration, just a bit of logic. When we type NPM run build on the command line, we execute the webpack.prod.js file. In the prod configuration file, the merge plugin executes the configuration in webpack.common.js. In the common file, the entry is main.js and the package exit is the dist directory. When we run build, we should see a new directory added, as shown in the figure

5. Configure the plug-in based on service requirements

Our goal is to build a vue-CLI-like scaffolding, so we need the following plug-in

vue-loader

The vUE loader is used to convert the source code of a module, and the vue-loader is used to convert the vue code so that the browser can recognize it. In addition to the rules configuration, the vue-loader is also configured under the plugins configuration.

npm install vue@next -S
npm install vue-loader@next @vue/compiler-sfc
Copy the code

Webpack.com mon. Js file:

const path = require('path') const { VueLoaderPlugin } = require('vue-loader') module.exports = env =>{ return { Entry :'./ SRC /main.js',// Entry file Output :{filename: 'assets/js/[name].code.js', chunkFilename: 'assets/js/[name].bundle.js',// dynamically import separate bundles such as lodashjs with annotations import(/* webpackChunkName: "Lodash" */ 'lodash') will be packaged as lodash.bundle.js path: path.resolve(__dirname, '.. /dist'), }, plugins:[ new VueLoaderPlugin() ], module:{ rules:[ { test:/\.vue$/, loader:'vue-loader' }, // It applies to ordinary '.js' files as well as' <script> 'blocks in'.vue 'files]}}}Copy the code

HtmlWebpackPlugin

HtmlWebpackPlugin allows packaged JS to be automatically introduced into HTML files

npm i -D html-webpack-plugin
Copy the code

This plugin is also used in both production and development environments, so it is configured in the webpack.common.js file

const path = require('path') const { VueLoaderPlugin } = require('vue-loader') const HtmlWebpackPlugin = Module. Exports =>{return {entry:'./ SRC /main.js',// output:{filename: 'assets/js/[name].code.js', chunkFilename: 'assets/js/[name].bundle.js',// dynamically import separate bundles such as lodashjs with annotations import(/* webpackChunkName: "Lodash" */ 'lodash') will be packaged as lodash.bundle.js path: path.resolve(__dirname, '.. /dist'), }, plugins:[ new VueLoaderPlugin(), new HtmlWebpackPlugin({ template: path.join(__dirname, '../public/index.html'), filename: 'index.html, / / output filename})], the module: {rules: [{test: / \. Vue $/, loader:' vue - loader '}, // It applies to ordinary '.js' files as well as' <script> 'blocks in'.vue 'files]}}}Copy the code

bable-loader

This much is introduced, which can let you use the ES6 7 8 syntax, the official tutorial

npm install -D babel-loader @babel/core @babel/preset-env webpack
Copy the code

Add a rule to webpack.common.js

Module: {rules: [{test: /\. Vue $/, loader: "vue-loader",}, // It applies to ordinary '.js' files and '. Vue 'files in' <script> 'blocks {test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, }, ], },Copy the code

resolve

Resolve is primarily configured to resolve modules. There are two extensions and aliases in common use, and a configuration suffix that can be used without a suffix. A configuration import alias, rather than layer by layer, is configured in the webpack.common.js file

Resolve: {/ / configure modules such as parsing extensions: [' vue ', 'js',' json '], / / introduction of the documents Can not take the suffix Sequential analytical alias: {' @ ': the join ('.. // SRC '), // @import resources}},Copy the code

Resource module

Resource modules, such as PNG, SVG, JPG, and TXT, are processed by file-loader or URL-loader before WebPack5. Now WebPack5 automatically processes resource modules without manual configuration. Resources less than 8KB are treated as inline resources; otherwise, resources are treated as resources. For example, if we want to specify inline processing for images less than 6KB, otherwise resource is introduced into webpack.mon.js

{test: / \. (PNG | SVG | JPG | GIF) $/, type: 'asset', the parser: {dataUrlCondition: {maxSize: 6 * 1024, less than 6 KB image inline processing / /}}}Copy the code

5. Configure the development environment

The above is the basic configuration of Webpack.common.js. Now we customize the configuration according to the development environment.

friendly-errors-webpack-plugin

After the NPM run serve is successfully executed, you can output information on the console

const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin"); const ip = require("ip"); let port = "8082"; Module.exports = (env) => {let dev_config = {devtool: 'inline-source-map',// enable source map mode: New FriendlyErrorsPlugin({compilationSuccessInfo: {messages: [ `You application is running here http://${ip.address()}:${port} \r\nYou can also open local address http://localhost:${port}`, ], clearConsole: true, }, }), ], }; return merge(common(env), dev_config); };Copy the code

devserve

In DevServe we can specify the port, whether to support HTTPS or not, whether to punch the browser window. If you need to customize devServe, you are advised to go to the plugins website instead of pasting in the same configuration as the plugins.

DevServer: {host:" 0.0.0.0", port: port, open:"http://localhost:" + port,// proxy: {"/ API ": {target: "Http://www.xxx.com:8080/api", secure: true, / / if it is HTTPS interface, need to configure the parameters changeOrigin: true, pathRewrite: {" ^ / finchinaAPP ": "},},},},Copy the code

cache

Cache Webpack modules and chunks generated by the cache are used to speed up construction. This is only available in development mode and is cached in memory by default. To customize the cache policy, change the cache type value from memory to filesystem. For example, change the default cache directory

const path = require('path');

module.exports = {
  //...
  cache: {
    type: 'filesystem',
    cacheDirectory: path.resolve(__dirname, '.temp_cache'),
  },
};
Copy the code

CSS

Since production CSS needs to be compressed, this is done separately. Install style-loader to insert CSS into the DOM.

npm install --save-dev style-loader
Copy the code

Install csS-loader to handle @import and URL () just as JS interprets import/require().

npm install --save-dev css-loader
Copy the code

Finally, add a rule to module rules

$/. CSS $/ I, use: ["style-loader", {loader: "css-loader", options: {esModule: false, modules: {auto: false, // Modules switch, mobile multi-page mode off class Hash named localIdentName: "[local] _ [8] hash: base64:", / / custom generated class name},},},],},Copy the code

Sass – CSS processing

Most projects use CSS processors, so CSS alone is not enough. If the project uses Sass-CSS, solve this problem. Installation node – sass sass – loader

npm i node-sass -D
npm install sass-loader sass webpack --save-dev

Copy the code

Add a new rule to rulues

{ test: /.s[ac]ss$/i, use: [// generate JS string to style node 'style-loader', // convert CSS to CommonJS module 'css-loader', // compile Sass to CSS 'sass-loader',],},Copy the code

Less – CSS processing

If less-CSS is used, install a less-loader

npm install less less-loader --save-dev
Copy the code

Then under the configuration in rules, the configuration is not according to the tutorial on the official website of less-Loader, because the error is reported, the document may not be updated.

 {
          test: /\.less$/i,
          use: [
            // compiles Less to CSS
            "style-loader",
            "css-loader",
            "less-loader",
          ],
        },
Copy the code

At this point, our development environment is configured.

6. Configure the production environment

Compared with webpack5, webpack5 is more automatic. For example, it automatically clears historical files in the output directory and compresses JS files.

Extract the CSS

Use the MiniCssExtractPlugin

npm install --save-dev mini-css-extract-plugin
Copy the code

Then configure in plugins and CSS Loader

plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': Json.stringify ('production')}), // Extract CSS new MiniCssExtractPlugin({filename: 'assets/ CSS /[name].style.css', ChunkFilename: 'assets/ CSS /[name].css'}),], module: {rules: [{// Parser execution order is from bottom up (css-loader then style-loader) test: /\.css$/, use: [ MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { esModule: False, modules:{auto:false,// Modules switch, mobile multi-page mode Off class Hash named localIdentName: '[local] _ [8] hash: base64:', / / custom generated class name}}},]}, {test: / \. SCSS $/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader' ] }, { test: /\.less$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'less-loader' ] }, ] },Copy the code

Compress CSS

Webpack4 OptimizeCSSAssetsPlugin is used the webpack5 official recommended CssMinimizerWebpackPlugin

 npm install css-minimizer-webpack-plugin --save-dev
Copy the code

Then add a configuration at the module level

optimization: { minimizer: [// In webpack@5, you can extend existing minimizer (terser-webpack-plugin) by using the '... 'syntax. Uncomment the next line // '... ', new CssMinimizerPlugin(),],}Copy the code

In fact, our production environment can be configured to minimize: true.

Code separation Optimization

Optimization, the default build target for webpack5 is web. For other projects such as the Node project or the Electorn project, add a target property such as the Build Node environment

module.exports = {
  target: 'node',
};
Copy the code

For optimization in Webpack, the general focus is on optimization.splitchunks, which by default gives us a split rule

- New chunks can be shared, or modules can come from the 'node_modules' folder - new chunks are bigger than 20KB (before min+gz) - when loading chunks on demand, Maximum number of concurrent requests less than or equal to 30 - Maximum number of concurrent requests less than or equal to 30 optimization: {splitChunks: {chunks: 'async', minSize: 20000, minRemainingSize: 0, minChunks: 1, maxAsyncRequests: 30, maxInitialRequests: 30, enforceSizeThreshold: 50000, cacheGroups: { defaultVendors: { test: /[\/]node_modules[\/]/, priority: -10, reuseExistingChunk: true, }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true, }, }, }, }, }Copy the code

We can also make some adjustments according to the actual situation of the project, for example, the default 20KB start split code, change to 30KB split code, etc

SplitChunks: {minChunks: 2, // Minimum number of times a module is used cacheGroups: {vendor: {name: 'vendor', test: /[\\/]node_modules[\\/]/, chunks: 'all', priority: 2, //2>0 NodulesModules will be packed in vendor}, Commons: {name: "Commons ", //async asynchronous code segmentation Initial synchronous code segmentation all Synchronous asynchronous segmentation is enabled chunks: "all", minSize: 30000, // The segmentation is performed only when the number of imported bytes is larger than 30KB. Priority: 0, // Priority, which group to pack first, the larger the value, the higher the priority}}}Copy the code

We generally speak of optimization projects, in addition to the introduction of open source plug-ins on demand such as Echarts, Antdvue, etc., the main thing is to optimize the packaging effect by tweaking different configurations of Optimization. To delve deeper into Webpack optimization, I suggest you take a look at this.

Package volume analysis

The analysis plug-in Webpack-bundle-Analyzer needs to be installed to analyze large files of packaged code

npm install --save-dev webpack-bundle-analyzer
Copy the code

The configuration is then started only after listening for input analysis commands, otherwise it will be started every time the package is packaged

Then configure the startup command in package.json

"scripts": {
    "serve": "webpack-dev-server  --hot   --config build/webpack.dev.js",
    "dev": "webpack-dev-server --open --progress --config build/webpack.dev.js",
    "build": "webpack  --config  build/webpack.prod.js",
    "distanalyzer": "webpack --env.analyzer=true --config build/webpack.prod.js"
  },
Copy the code

At this point, we’re done.

7. Run and try it

Install the vue – the router

npm install vue-router@4
Copy the code

Simply write two pages, success!

The code is available on GitHub, click here.