There are four concepts in Webpack: import, export, plug-in and loader. It is modular and supports CMD, ADM, commonJS, import and other modular operations.

Installation instructions: when installing Webpack, you need to install a global Webpack first, and then install local dependencies in the required folder, Webpack Webpack-cil scaffolding, in the version of Webpack 3, they are integrated together. This note is for: Webpack 4.x and above

npm install webpack -g 	// Install the global webpack command first, then you can experiment with webpack command, directly package
npm install webpack webpack-cli  -D  // Install WebPack in the desired directory

webpack  // run this in CMD or vscode to package the rest of the configuration, see later
Copy the code

After the installation is complete, you need to create a new webpack-config.js configuration file in the project root directory. You can package it without creating it, because WebPack has default configuration.

If you do not have webpack installed, you cannot use webPack directly to package, of course, can also be a separate configuration script, for example:

scripts: {
    dev: webpack --config webpack-config.js
}
Copy the code

In versions 4.0 and later, a multi-entry packing command was added: webpack app.js app1.ja-o bulid.js

In Webpack, there are production mode and development mode. The default setting is development mode. Use the mode parameter to set the mode, for example:

module.exports = {
  mode: 'production' // Mode selection, production and development
};
Copy the code

Note: The mode attribute must be specified, otherwise the console will display a warning message

Entry

An entry point that indicates which module webpack should use; Once inside the entry point, WebPack finds out which modules and libraries are (directly and indirectly) dependent on the entry point.

Entry can be single entry or multiple entry (represented by an array or object). In practice, the third entry, which is the object form, is preferred for optimization and first-screen loading problems.

However, there are some minor problems with the object notation (Entry code separation); Suppose entry introduces two JS files, a.js and B.js respectively, but these two files introduce the same dependency. After packaging, code duplication will occur, which is not conducive to optimization. Therefore, SplitChunksPlugin is needed to prevent duplication or dynamic dumping. Click to see the pitfall of this approach: code separation.

module.exports = {
  entry: './app.js' / / write one
  entry: ['./app.js, main.js'] / / write two
  entry: {
    app: './app.js'.main: './main.js'
} / / writing three
};
Copy the code

Output

Represented by the (output) property, this tells WebPack to output the content it creates. The default directory is the dist folder, or you can specify a directory to export from within the project root.

const path = require('path');
module.exports = {
  entry: './path/to/my/entry/file.js'./ / the entry
  output: { / / export
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js' // Single file merge
    filename: '[name].js'.// Multiple entries multiple filesChunkFilename: [name] [contenthash]. Js,// Prevent caching, random code will only be generated after update
    publicPath: 'the CDN address' // Set the CDN server address, theoretically can be packaged directly to the CDN server, provided that there is permission}};Copy the code

If the import file is configured, use filename. If the import file is imported from another file, use chunkFilename.

In Output, the filename attribute is used to tell Webpack the name of the packaged file; Path tells Webpack the location of the folder that needs to be created. This calls a module in Node, which is the path module. __dirname is a key word in Node, which means path, absolute path

Tip: In Webpack, multiple entries can only merge files using arrays; If multiple files need to be packaged, the entry needs to use objects, and the exit uses a dynamic writing method, as shown in the code “multi-entry file”, [name].js. If the entry is an object, the exit must be a dynamic writing method, otherwise it will lead to improper packaging.

loader

Loader enables Webpack to handle non-javascript files (WebPack itself only understands JavaScript). Loader can convert all types of files into valid modules that WebPack can handle, and then you can take advantage of WebPack’s packaging capabilities to process them.

The loader execution sequence is from bottom to top and from right to left. Therefore, ensure that the sequence is correct when setting the Loader. Otherwise, a packing exception may occur.

Loader is a translator that translates and processes the code we write. The usage is as follows: Babel is used as an example

Note: In Lodaer, when regex (test) is configured, it must not be quoted, otherwise it will prompt lodaer error.

babel

Babe is a compiler that converts ES6 to ES5 with three dependencies installed. Babel can convert ES6 syntax to ES5 syntax, but the built-in APIS in ES6+ do not. So install a shim @babel/ Polyfill, which is designed to be compatible with older browsers.

babel-loader @babel/core  // Syntax conversion
@babel/preset-env  // This specifies the version of ES
@babel/polyfill // Global gasket, used to convert the built-in API to support ES5 syntax
/* Local gasket needs to be installed dependencies */
@babel/plugin-transform-runtime
@babel/runtime
Copy the code

Webpack configuration mode

module: {
  rules: [{test: /\.m? js$/.// Matches the file name extension
      exclude: /(node_modules|bower_components)/.// The directory that needs to be removed
      use: {
        loader: 'babel-loader'.options: {
          presets: ['@babel/preset-env'].// Use the gasket
          plugins: ['@babel/plugin-proposal-object-rest-spread'] / / extra}}}]}Copy the code

For the operation of the attribute use, if there are not many configuration items, you can not use the attribute use, the two are equivalent, and directly write, for example:

rules: [{
    test: /\.m? js$/.// Matches the file name extension
    loader: 'babel-loader'.// Load the loader
    exclude: /(node_modules|bower_components)/.// The directory that needs to be removed
    options: { 	/ / configuration items
   		presets: ['@babel/preset-env'].// The default syntax is not used
        presets: [["@babel/preset-env", { // The second way is to configure a Babel /polyfill gasket
        useBuiltIns: "usage"./ / on-demand loaded entry | usage
        targets: {
          chrome: "68"  // Browser targets can also follow a browser's market share}}]]}}]Copy the code

The @babel/polyfill module needs to be included in the packaged file. By default, it will package all the built-in API modules, so it needs to be loaded on demand. UseBuildIns: ‘usage’.

If usage is set, @babel/polyfill should not be introduced in the packaged file. If usage is set, it should be replaced with entry (local mode, according to file requirements).

If you are writing a plugin, you cannot use a global gasket. There are two dependencies for using a local gasket: @babel/ plugin-transform-Runtime and @babel/ Runtime.

. Babelrc Configuration method

In the root directory of the project, we need to create a single file named. Babelrc. The format is a standard JSON, so we need to use the standard JSON format.

{
	"presets": ["@babel/preset-env"]."plugins": [["@babel/plugin-transform-runtime", { 
         "absoluteRuntime": false."corejs": 2.// Corjs needs to be changed to 2, otherwise it will cause packaging exception, the official default is false, optional number and Boolean
         "helpers": true."regenerator": true."useESModules": false}}]]/ * = = = = = = = = = = = = = = = = normal mode using the configuration file name way = = = = = = = = = = = = = = = = = = = = = = = = * /
{
      "presets": [["@babel/preset-env", {
          "useBuiltIns": "usage"."targets": {
          "chrome": "68"  // Browser targets can also follow a browser's market share, or they can be: the last 100 versions}}}]]Copy the code

Exception handling: Corejs officially defaults to false, but exceptions can occur and the result is no conversion; So the corejs attribute needs to be followed by a 2, but that still doesn’t work, so you need to download an @babel/runtime dependency to change the @babel/runtime

[[‘ XXX ‘,{}]], and do not set the presets in webpack and then set them in a separate. Babelrc.

The plug-in (plugins)

To use a plugin, you simply require() it and add it to the plugins array. Most plug-ins can be customized with options. You can also use the same plug-in multiple times in a configuration file for different purposes, creating it by using the new operator.

This is the official saying, my own understanding is to extend a function for Webpack, this function is extremely powerful, can be used to deal with a variety of tasks, the use of the plug-in is as follows:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // Module installed through NPM
const webpack = require('webpack'); // Used to access built-in plug-ins
const path = require('path') // This is a built-in module for the file path, which is required to use the resolve attribute

const config = { // Multi-file configuration
  module: {
    rules: [{test: /\.txt$/.use: 'raw-loader'}},plugins: [
    new HtmlWebpackPlugin({
        template: './src/index.html'}})];module.exports = config 
Copy the code

The use of HtmlWebpackPlugin

The HtmlWebpackPlugin plugin will generate an HTML5 file for you that includes all webpack packages in the body using the Script tag. The htmL-webpack-plugin needs to be installed to use it. The basic configuration is as follows:

var HtmlWebpackPlugin = require('html-webpack-plugin'); // Import plug-ins
plugins: [
    new HtmlWebpackPlugin({ // More values can be configured, such as title
        title: 'webpack'.// Generate an HTML title
        templat: './index.html' // Configure the template file
        hash: true.// To prevent caching, add a hash value to the generated JS file, including CSS
        cache: true // Update files only when the contents are changed
        inject: true.// JS injection position, true, default bottom
        chunks:['xxx'.'Entry file name'].// Multi-entry file, JS file will be generated according to the configuration, default all references
        minify: {
        	removeAttributeQuotes: true.// Whether to remove quotes from attributes Default to false}})]Copy the code

Resources: link to NPM, htML-webpack-plugin for Webpack 4. See the original NPM link for more configurations

The clean – webpack – the use of the plugin

The clean-webpack-plugin can be used to clean the output files of the configuration, automatically checking at the start of the build command, and removing them first, thus ensuring that the files in the directory are always up to date. However, you can also customize the deletion of a directory, please click here.

const { cleanWebpackPlugin } = require('clean-webpack-plugin') // Import the package first, you need to use this method
plugins: [
	new cleanWebpackPlugin()  By default, there is no need to pass the parameter. According to the test, in the 3.X version, it can be directly imported
]
Copy the code

Multiple Loaders or plug-ins are configured

If you want to use multiple lodaers, you simply place an array of objects under the rules property

module: {
rules: [{  // The configuration of multiple loaders is as follows, each loader is an object
		test: /\.tsx? $/.use: 'ts-loader'.exclude: /node_modules/}, {test: /\.m? js$/.// Matches the file name extension
      exclude: /(node_modules|bower_components)/.// The directory that needs to be removed
      use: {
        loader: 'babel-loader'.options: {
          presets: ['@babel/preset-env'].plugins: ['@babel/plugin-proposal-object-rest-spread'}}}]}Copy the code

Note: in fact, each loader or plug-in can use a single file, this can make the Webpack file is not so large, but will cause the project root file to become too large, specific according to their own project configuration.

About the packaging of TS files

To convert the TS file, download the typescript TS-Loader dependencies. After installing the typescript TS-Loader, create a new JSON file named tsconfig.json in the project root directory.

{
  "compilerOptions": {
    "outDir": "./dist/".// The output file is not needed if WebPack is already configured
    "noImplicitAny": true."module": "es6".// What modules have been used to introduce files, mainly ES6 and commonJS
    "target": "es5".// What type of syntax needs to be compiled into, ES5
    "jsx": "react".// Use JSX syntax,
    "allowJs": true   // Whether ES syntax exists in TS file types, default true
  },
  "include": ['./src/'.'/'].// Directory of imported files, files to compile
  "exclude": /node_modules/  / / don't need to compile directories, multiple use (xx xx) | this way
}
Copy the code

The configuration for compiling typescriptWebPack is as follows:

module: {
	rules: [{
		test: /\.tsx? $/.use: 'ts-loader'.exclude: /node_modules/}},Copy the code

Lodash is a consistent, modular, high-performance JavaScript utility library for code type constraints. Use types/ Lodash in TS to constrain TS. ** LoDash is very specific. If you want to restrict the type of jquery, you need to download the corresponding LoDash dependency package.

Image packaging

Before packaging images, you need to download a loader. You can use file-loader to package images. The common configuration of WebPack is as follows:

module: {
	rules: [{
		test: /\.(png|jpg|gif)$/.use: [{
            loader: 'file-loader'.options: {
            	name: '[path][name].[ext]' // Custom name, [name] name [ext] extension, can also add obtrusion such as hash valueOutputPath:'images/'  // Generate the images/ directory for the packaged relative file (dist)}}}}]]Copy the code

Image packaging, default file name using hash obfuscation, can also be customized configuration. See the webpack official URl-loader description for details, which is only partially shown in the example.

If images need to be BASE64 packaged, a loader of url-loader needs to be downloaded. However, it should be noted that file-loade and URl-loader are processed in the same way. The only difference is that url-loader is more powerful than file-loade. The method used is exactly the same as file-loade, but url-loade has more configuration items.

module: {
	rules: [{
		test: /\.(png|jpg|gif)$/.use: [{
            loader: 'url-loade'.options: {
            	name: '[path][name].[ext]'.// Custom name, [name] name [ext] extension, can also add obtrusion such as hash valueOutputPath:'images/'.// Generate the images/ directory for the packaged relative file (dist)
                limit: '1024'.// Limit the size of the image to pack base, in bytes}}}}]]Copy the code

By default, url-loader will package images as base64 files. However, in normal cases, only small images will be formatted as Base files. Therefore, you need to configure the image size in Options

CSS Modular Packaging

When packing the CSS, you need to download a CSS-Loader and a style-loaderlodaer to compile the CSS. To use precompilation, you need to install the corresponding precompiled Loader. For example, sass requires two loaders, sass-loader and Node-sass. According to experiments, only sass-loader is required.

Css-loader is used to package CSS

Style-loader is used to attach the loader to an HTML page, usually in the HTML header

The basic configuration information is as follows (including the SASS preprocessor) :

module.exports = {
    module: {
    rules: [{
        test: /\.css$/.// /\.sass$/
        use: [ 'style-loader'.'css-loader' , 'sass-loader']]}}}Copy the code

To add a prefix to CSS3, use postCSs-loaderlodaer and autoprefixer plug-ins. Continue with the example above. The basic configuration is as follows:

module.exports = {
    module: {
    rules: [{
        test: /\.css$/.// /\.sass$/
        use: [ 'style-loader'.'css-loader' , 'sass-loader'.'postcss-loader'] / / write 1
        use: [ 'style-loader'.'css-loader' ,'sass-loader', {// Each lodaer can be configured separately
        	loader:'postcss-loader'.options: {
            	plugins: [
                	require("autoprefixer") /* Generates the browser prefix */]}}]}}Copy the code

To make it auto-prefix, create a new file in the project root directory, postcss.config.js, or in webpack.config.js, as shown in the previous code. The basic configuration information is as follows:

module.exports = {
	 plugins: [ // Plugins
     	 require('autoprefixer')// Load the module by default
         require('autoprefixer') ({// webpack or postcss.config.js configuration,
    		overrideBrowserList: 'last 100 versions'}})]Copy the code

By default, autoprefixer can only automatically add webKit prefix information. Additional parameters need to be added if additional configurations are required.

You need to add a property to package.json called Browserslist, which corresponds to an array filled with the name of the browser or node version, for example, “last 100 versions”;

If you want to configure it in Webpack, you need to replace browserslist with the overrideBrowserList property, otherwise webPack will get an error at compile time. For detailed usage of Browserslist, click here

Modularity mechanism of the CSS, simple configuration:

module.exports = {
    module: {
    rules: [{
        test: /\.css$/.// /\.sass$/ // match the suffix name
        use: [ 'style-loader', {  // Configure the required loader, loader
            loader: 'css-loader'.options: {
                modules: {
                 	 localIdentNane: '[name]_[hash:base64:10]' // Custom class name, bese needs to intercept}}},'sass-loader']]}}}Copy the code

If modularity is enabled, files must be imported in a partial way during modularity import. Otherwise, webPack will fail during compilation. Example:

import 'xxx.css'  // global import
import xxx from 'xxx.ss' // Local import

Copy the code

Package fonts: Loader uses the same file-loader used to package fonts and files

module: {
	rules: [{
		test: /\.(woff|woff2|svg|ttf|eot )$/.// Font file name extension
        use: [{
            loader: 'file-loader'.options: {
            	outputPath: 'font/'  // The generated folder, put the packaged files, in it
                name: [name].[ext]   // Change the output file name so that the original file name and suffix are default}}}}]]Copy the code

DevServer common configuration

Webpack-dev-server can be used for rapid application development, so it is called devServer for short. DevServer is designed to improve development efficiency. Instead of using devServer as a package, it provides configuration items that can be used to change the default behavior of devServer. To configure devServer, you can pass in parameters from devServer in configuration files as well as from the command line.

/* Intercepts vue CLI examples by command passing arguments */
"dev": "Webpack - dev - server - the host 0.0.0.0 - the inline - progress - config build/webpack dev. Conf., js." ".Copy the code

One caveat: devServer only works in development mode

Enabling local Services

Install the webPackdev-server plugin to help you start a local service. Although the webpackDevServer plugin is built-in, it still needs to be downloaded, but does not need to be imported. It needs to be configured in the webpack.config.js and package.json files as follows:

/* Webpack.config.js configuration */
module.exports = {
	devServer: {
		contentBase: './dist' // Configure the packing path
        open: true.// Set whether to open by default
        prot: "8080"./ / port
        hot: true , // Enable hot update}}/* package.json configuration */
"scripts": {
    "dev": "webpack-dev-server --open"
}

Copy the code

After the webpack-dev-server is configured correctly, supply the file from the dist directory. The default address is localhost:8080. You can also customize the configuration. More configuration click here, but this way, it updates all the data, so you can think of it as a page refresh.

Webpack-dev-server does not write any output files after compilation. Instead, it keeps the bundle files in memory and serves them as if they were real files installed on the server root path. If your page wants to find the bundle file in a different path, you can change this option using the option in the publicPathdev server configuration.

Webpack hot update

In the use of webpack hot update, the need to have a plugin HotModuleReplacementPlugin, abbreviation is HMR, this plugin is a built-in webpack integration plug-in, at the time of use, do not need to download, but you want to import webpack.

But HotModuleReplacementPlugin this plug-in cannot be used for production mode, a hot update is devServer events. HotModuleReplacementPlugin configuration items in it, and can be ignored, the official said it’s experimental and configuration is not recommended.

const webpack = require('webpack') 
plugins:[
 	new webpack.HotModuleReplacementPlugin({
		multiStep: true.// This will be built in two steps - first compile the hot update block, then compile the remaining normal assets
		fullBuildTimeout: Number // Time indicates the delay between enabling multiStepRequestTimeout:Number // Time (ms) The timeout used to download the list
	});   
 ]

Copy the code

. Please note that webpack HotModuleReplacementPlugin fully enabled HMR is required. If Webpack or webpack-dev-server is started with the –hot option, this plug-in is automatically added, so you may not need to add this to your webpack.config.js.

"dev": "Webpack - dev - server - the host 0.0.0.0." "  // An example of the above instructions does not require the webpack.config.js configuration

Copy the code

Webpack preload

Webpack reverse proxy

Dev-server uses a very powerful HTTP-proxy-Middleware package. For more advanced uses, see the documentation; When we were doing development, data requests could not be made due to cross-domain problems, so we needed to use the reverse proxy provided by WENpack, namely PORxy, as follows:

/* omit other code */
devServer: {
    porxy: {
    	"/api": "http://localhost:3000".// Basic usage to bind/API to target server.
        "/api": { // Use the configured usage, usage two
         	target: "http://localhost:3000".// Target server
            pathRewrite: {"^/api" : ""},  // The path is overwritten so that there is no need to pass the/API for front-end access
            secure: false.// Specifies whether to use HTTPS. By default, HTTPS is not allowed}},// Multiple apis request the same server writing method
     porxy:[{
     	context: ["/auth"."/api"].// Multiple requests
  		target: "http://localhost:3000".// Target server}}]/*** a front-end request, using axions as an example ***/
   axios.get('/api/xxx').then(red= > { xxx })  
 axios.get('// xxx').then(red= > { xxx })  // Configure requested access to ignore/API

Copy the code

If you have multiple API requests on the same server, you can use context as an array. For more information about webPack Proxy configuration, please visit webPack Proxy here for more instructions.

Webpack preload

The setting of SourceMap

Devtool is a source file mapping that allows you to quickly find code errors, but this way, you need to package them to see if there are any errors. But there is also a compromise solution, we need to set a script in package.json, which can automatically package for us, but it is a file protocol, normally, the page needs to be manually refreshed, so it is better to use devServer.

module.export = {
    /* Cheap-module-eval-source-map is used in the development environment, which is fast, including three-party modules only prompt line error */
    /* cheap-module-source-map is used in the production environment 
    /* source-map source file map inline-source-map(tells you exactly which lines are listed wrong)*/
    devtool: 'cheap-module-eval-source-map'
}
/*================================= package.json ===============================*/
"scripts": {
    "dev": "webpack --watch" 
  }

Copy the code

Devtool you can use SourceMapDevToolPlugin, rather than using this option, EvalSourceMapDevToolPlugin because it has more options. Never use both the Devtool option and the plug-in; the Devtool option adds the plug-in internally, so you end up applying the plug-in twice.

Devtool you can use SourceMapDevToolPlugin, rather than using this option, EvalSourceMapDevToolPlugin because it has more options in fact this sentence, I also don’t understand is what mean? If you need more fine-grained control, use the SourceMapDevToolPlugin plugin, but not both, for reasons explained above. Actually, personally, I think I can bring my own.

Tree Shaking configuration

Tree Shaking translates to Shaking the branches of trees. A simple example: the road of autumn, planted many trees on both sides of the road, some leaves withered and yellow, some leaves were still green, because the yellow leaves falling with the wind, in order to better solve the problem of the fallen leaves, just looking for a large equipment, holding the trunk were swinging, yellow leaves will fall down, and the rest is not easy to drop the green leaves.

But the other way around is that, for WebPack, an entry is like a tree trunk, with many modules on it, which are branches, but the dependencies are not all used, or only one function of the module is used. This is when you need to use Tree Shaking it to shake off modules that you don’t need, that is, in packaged files, the code is lean and needed. Tree-Shaking Performance Optimization Practices – Principles

Tree shaking is a term used to describe removing dead-code from a JavaScript context. It relies on static structural features in the ES2015 module system, such as import and export. The term and concept actually arose from the ES2015 module packaging tool rollup.

The new official release of WebPack 4 extends this detection capability by using the package.json “sideEffects” attribute as a tag to provide compiler with hints as to which files in the project are “pure “. This allows you to safely delete unused portions of the file.

All that said? So how do you use it in WebPack? Need to be configured in package.json

{
  "sideEffects": false.// Simple version,
  "sideEffects": [ // Use an array to remove things that do not need to be shaken.
      "@babel/polyfill"."./src/some-side-effectful-file.js"."*.css"]}Copy the code

It’s just marked “dead code”, but it needs to be deleted after compilation, so we need to switch to production mode to say –optimize-minimize; To use the configuration, the code is as follows:

mode: 'production'.// Must be production mode
optimization: {	 // Sets unused code to be deleted as a tag, that is, dead code
	usedExports: true
}

Copy the code

Summary: Tree Shaking only works in production mode, not in development mode, and only in ESmodul mode.

Separate WebPack configuration

There are a lot of WebPack configurations in vue CLI 2.x. I didn’t know why it was necessary at first, but later I learned that there are many modes in WebPack, such as: Production mode, development mode, and in between are various configuration files, common modules, etc. Here is the WebPack configuration directory for the Vue CLI.

. | - vue cli | - config | | -- dev. Env. Js | | -- index. Js | | - prod. The env. Js | | __ test. The env. Js | - build | | - build. Js | | - check - versions. Js | | -- utils. Js | | - vue - loader. Conf., js | | -- webpack. Base. Conf., js | | -- webpack. Dev. Conf., js | | __  webpack.prod.conf.js | .Copy the code

But with so many separate files, how do you eventually merge them together? Do you import directly or do you need to use plug-ins? There is a plug-in called webpack-Merge that you need to install before using it.

Js, webpack.dev.conf.js, and webpack.base.conf.js. Webpack.base.conf.js is a public file. The other two represent production patterns and development patterns. Use webpack-merge as follows:

/* ======= Take production mode as an example. Webpack.prod.conf.js ======= */
const merge = require('webpack-merge');
const common = require('./webpack.prod.conf.js');

module.exports = merge(common, { 
	mode: 'production'.devtool: 'source-map'
});

Copy the code

You still need to configure it in NPM. You can still vue cli directory as an example. Add the following content to package.json:

scripts": { "dev": "webpack-dev-server --open --progress --config build/webpack.dev.conf.js", "build": "Webpack -- config build/webpack. Prod. Conf., js"} / * - progress show the meaning of the progress bar * /Copy the code

Use of environment variables

You just want to use a file entry, configure an environment variable in it, and then produce different compilation results according to your needs. The implementation method can be as follows.

The commonConfig file, prodConfig, and devConfig are also separate files. To avoid large files, it is better to write them separately, but use an environment variable to determine the configuration.

module.export = (env) = > {
    if(env && env.production){ // Conditional judgment
        return merge(commonConfig, prodConfig); // Production mode (online mode)
    } else {
        return merge(commonConfig, devConfig); // Development mode}}Copy the code

Env && env.production = package.json = package.json = env && env.production = package.json = env && env.production = package.json = env && env.production = package.json = env && env.

scripts": { "dev": "webpack-dev-server --open --progress --config build/webpack.base.conf.js", "build": "Webpack env. Production. - config build/webpack base. Conf., js"} / * - progress show the meaning of the progress bar * /Copy the code

It is clear that dev and build start the same directory file, but add an env.production property to build. This variable is used in the conditional statement above.

Environment variables can also be used as process.env.node_env. For details about the methods provided by nodeJS, see the short book nodeJS /Vue project using process.env.

Configure Esint in Webpack

Most of the time, we need to use ESLint to help us with code checking and specification. This is often the case in a team, which makes it very convenient for team collaboration, post-maintenance, etc. However, configuring ESLint can be quite cumbersome. Customizations are also explained in the MOOCs notes, please click here for more information.

To use esLint, you need to install the esLint package. Install the following methods:

npm install eslint --save-dev // Download the esLint installation package
npx eslint --init // Run this command for detailed configuration of eslint

Copy the code

For the ESLint configuration instructions, when running NPX esLint –init, the following message will pop up:

? How would you like to use ESLint? (Use arrow keys)  // How to configure the eslint file, how do you want to use it
  To check syntax only  // Just check the syntax
> To check syntax and find problems // Check the syntax and find any problems
  To check syntax, find problems, and enforce code style // Check syntax, find problems, and enforce code styles
/* I chose to check the syntax and find the problem, and then I have the following configuration information */

? What type of modules does your project use? // What type of module do you want to use?
  JavaScript modules (import/export) / / based on ES6
> CommonJS (require/exports)	// This is mainly used in node
  None of these // None of these

  /* Because I used vue in my experiment, I needed to use esModule syntax, and then the pop-up message is as follows */
  ? Which framework does your project use? (Use arrow keys) // You want to use that frame
   React
 > Vue.js  // Because I am vue, so choose Vue
  None of these // Other frames
  
  /* When you select vue and the configuration is as follows, ask where you want to run it, you can choose more than one, use space to light, then press Enter */
  ? Where does your code run? (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Browser / / the browser
 ( ) Node    // node                                                                                  
/* When I select, the following configuration will appear of course is to use the JS file way, personal preference */
? What format do you want your config file to be in? (Use arrow keys) What file is used as the configuration file
> JavaScript
  YAML
  JSON

  /* if you want to install them */
  ? Would you like to install them now with npm? (Y/n) // the basic configuration process is complete

Copy the code

Eslintrc.js configuration file in the root directory of the project. This file is the esLint configuration file. For more configuration, please click here. More perverted is airbnb rules, very strict.

While this works in vscode(provided there is a plug-in in webpack), it doesn’t give any errors in other code editors. So you need to download an ESlint-loader as follows:

 npm install eslint-loader --save-dev

Copy the code

Once downloaded, the basic configuration is as follows, but be sure to put eslint-Loader last because loaders are executed from back to front:

module.exports = {
  module: {
    rules: [{test: /\.js$/.exclude: /node_modules/.use: ["babel-loader"."eslint-loader"}]}};Copy the code

Just this (if you don’t do the following configuration, it can only be displayed on the CMD console), but it still doesn’t work. A little extra configuration is required, as follows:

module.exports = {
  devServer: {
    overlay: true  // Pop up a layer on the browser, that is, display full screen overlay in the browser}};Copy the code

However, we all know that in the version of Vue CLI2, when the warning message is detected, it will be output in the browser console display, but THIS problem, I have not solved, there are friends who know, can tell me the following.

overlay:{
    warnings: false.errors: true
}

Copy the code

I also did a configuration according to the Vue CLI source code and found that it did not go as I expected.

Package third-party libraries (Shimming)

When I just learned vue.js, I was not familiar with it at that time. Sometimes I needed to operate DOM, but vue.js was very inconvenient to operate DOM. Sometimes I need to get all the tags in a list. At that time, I thought of using Jquery to help me manipulate THE DOM. At that time, I thought it would be ok to import them globally just like other JS files. It drives me crazy.

I learned that Webpakc itself already provides a set of shimming solutions: Using the ProvidePlugin and expose-Loader built into WebPack, I found a lot of documentation on the Internet. Although this problem was solved by using the ProvidePlugin built into Webpack, there were still some minor problems, such as esLint reporting errors. It was later discovered that using the expose-loader approach also solved this problem.

webpack.ProvidePlugin

ProvidePlugin is a built-in webpack plug-in, so you need to import Webpack before using it. Its main function is: automatically load modules without importing or requiring everywhere, which is also recommended by WebPack.

But: for the default export of the ES2015 module, you must specify the default attribute of the module because of its name; Take jquery as an example: it is essentially import $from ‘jquery’, as shown below. For more examples, please click here to see the official sample description.

const webpack = require('webpack')
/* omit other code */
plugins: [
    new webpack.ProvidePlugin({
        $: 'jquery'.$import $from 'jquery'
        JQuery: 'jquery'})]Copy the code

expose-loader

You can inject a global public module into webPack using the expose-loader method. If you import jquery with this method, you can use it globally and bind it to Windows. Therefore, you need to download the expose-loader to use it. Using jquery as an example, you can use it as follows:

module: {
  rules: [{
    test: require.resolve('jquery'), // Import the jquery module, but this method is provided by Node.js and has nothing to do with WebPack
    use: [{
      loader: 'expose-loader'.options: 'jQuery' // The name used globally, window.jquery}, {loader: 'expose-loader'.options: '$' // Use the global name, window.$}}}]]Copy the code

This approach, however, requires a local import (that is, every page needs to be imported) before global exposure, but if global injection is required, this is obviously not a good approach.

Prevent duplication (SplitChunksPlugin)

Webpack provides Code Splitting. Check out Code Splitting methods and descriptions here.

The CommonsChunkPlugin is used to avoid their repeated dependencies, but cannot be further optimized; The optimization.splitchunks attribute is removed after the Webpack4 release. The SplitChunksPlugin method uses the following:

module.exports = {
    splitChunks: {
        chunks: "all".// Both synchronous and asynchronous are split
        cacheGroups: { / / the buffer group
            vendors:false.default: false}}}Copy the code

More configurations of SplitChunksPlugin are shown below. For details, see the official documentation.

module.exports = {
  / /...
  optimization: {
    splitChunks: {
      chunks: 'async'.// Async is recommended by default. Asynchronous loading is used for partitioning. Initial synchronization is used for partitioning
      minSize: 30000.// if the number of bytes introduced by a package or module is greater than this value, code splitting is done, only for synchronous loading
      maxSize: 0.// When the minSize exceeds the specified value, the system will perform secondary packaging. This parameter is not configured by default and cannot be forcibly removed
      minChunks: 1.// The number of import counts, which can be packaged
      maxAsyncRequests: 5.// Request more than 5 parts do not split, general default value
      maxInitialRequests: 3.// The maximum number of requests that can be sent at the same time during page initialization is 3
      automaticNameDelimiter: '~'.// The vendors are the default linker for the file names that are packaged with code separation, vendors in cacheGroups
      automaticNameMaxLength: 30.// Maximum number of bytes, cannot exceed this value
      name: true.// Split name. True means that the file name is automatically generated based on the module name and the cacheGroups key
      cacheGroups: { // Cache configuration, a file that imports multiple libraries, if multiple libraries need to be packaged into a file, use this cache group
        vendors: {
          test: /[\\/]node_modules[\\/]/.// Check whether the fetching library is under node_modules
          priority: - 10.// Weight to determine which group is configured first
          name: "vendors" // Create a custom name without a suffix
        },
        default: { // If there is no previous match, this group is used, usually business code
          minChunks: 2.// Import more than 2 times before repackaging into a new file
          priority: - 20./ / weight
          reuseExistingChunk: true // When true, packaging is not repeated and automatic reuse is performed.}}}}};Copy the code

In chunks, you also need to go to the cacheGroups buffer group, separating the vendors names with vendors in the cacheGroups, and vendors in the middle with vendors in the automaticNameDelimiter example, Vendors main.js

You can define multiple cacheGroups. If all of these groups meet the requirements, the one with the most weight takes precedence.

Webpack is recommended to use an asynchronous approach for better performance.

Lazy Loding (dynamic import Lazy loading)

Webpack provides two similar techniques when it comes to dynamic code splitting. The first and preferred approach to dynamic imports is a draft of ES7 called the import() syntax. The second is to use webpack-specific require.ensure. Let’s talk about the first one:

The biggest advantage of dynamic import is to achieve lazy loading, using that module will be called that module, very suitable for ASP import, can greatly reduce the wait time, but using this need to use Babel to transfer, The plugin @babel/plugin-syntax-dynamic-import can be downloaded as follows:

{
  "plugins": ["@babel/plugin-syntax-dynamic-import"] // Add to webpack plugins using plugins
}

Copy the code

Add a lazy import to the page that returns a Promise object as follows:

/* Declaring this method requires a function */ 
function getComponent() {
	import(/* webpackChunkName: "lodash" */ 'lodash').then( _= > {
            var element = document.createElement('div');
            element.innerHTML = _.join(['Hello'.'webpack'].' ');
            return element;
		 }).catch( error= > 'An error occurred while loading the component');
 }
/* This method is not executed if it is not called
getComponent().then(component= > {
	document.body.appendChild(component);
})

Copy the code

In this way, the code will be separated. The third party module that will be dynamically entered will be typed into a separate file, while the business code written by itself will be packaged into a new file.

/* webpackChunkName: “lodash” */ ‘lodash’

module.exports = {
    splitChunks: {
        cacheGroups: { / / the buffer group
            vendors: {
              test: /[\\/]node_modules[\\/]/.// Check whether the fetching library is under node_modules
              priority: - 10.// Weight to determine which group is configured first
              name: "vendors" // Create a custom name without a suffix
        	},
            default: false}}}Copy the code

But use lazy loading, there will be a drawback, is when the user needs a module, only after the trigger, to load the corresponding module, this can cause a network latency, there is a waiting period, is not conducive to the user experience, so they need another technology, namely preload, automatic when the page loads, use the bandwidth of the idle, To load any other modules that may be needed.

Preloading

This is a new feature in WebPack 4.6.0. In popular terms, it is to automatically download other non-essential modules when the network is idle. This way greatly improves user experience and also solves the problem of waiting delay.

/* The method is the same as the lazy loading method above, but the magic string has different parameters */
import(/* webpackPrefetch: true */ 'LoginModal');

Copy the code

Using these inline directives when declaring an import allows Webpack to print a “Resource Hint”, used as above, which tells the browser:

  • Prefetch: Resources may be required in the future
  • Preload: Resources may be required currently

Difference: Preload is loaded with core code, prefetch is preloaded

The code improvements from caching are limited, so lazy-loaded code optimization is now the dominant use of performance optimization.

Webpack packaging analysis

About package Analysis, the official website provides us with a built-in plug-in called Bundle Analysis. Bundle Analysis in Code Splitting under Guider has several types, such as Webpack-chart (interactive pie chart). Please click here for details. It’s easy to configure a script in package.json, as shown in the following example:

scripts": {
	"build": "webpack  --profile --json > stats.json --env.production. --config build/webpack.base.conf.js"
}

Copy the code

You can also use webpack –profile –json > stats.json. When the package is complete, a stats.json file is generated, which is the result analysis file, and then you need to upload this file to the website for data analysis. It feels very dehumanizing and personally ugly, so you need to use the webpack-bundle-Analyzer plugin.

Webpack Bundle Analyzer is also a package analysis. Unlike Webpack-Chart, Webpack Bundle Analyzer is a very intuitive graph. It is a plug-in, so when you use it, you need to download and install it. NPM install –save-dev webpack-bundle-Analyzer.

If you use this, the console will not output packaging information, such as files, packaging time, chunk, etc., during packaging, which is also a disadvantage.

The basic configuration in WebPack is as follows. For more configuration, please click here.

// Import the plug-in
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
/ / use it
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

Copy the code

CSS code separation

By default, it is packaged in a JS file, which will cause the file to become very large, so it is necessary to separate the CSS code. To analyze the CSS code, we need to use a plug-in to help us. This is usually only done in the online version, but not in the development version. The name of the plugin is MiniCssExtractPlugin, click here for more official configuration.

npm install --save-dev mini-css-extract-plugin  // Install it first

Copy the code

Simple configuration instructions, at the time of use to style – loader is replaced by MiniCssExtractPlugin. Loader, if you need to use hot update in the development environment, needs to be for a set.

const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // Import the plug-in
module.exports = {
  plugins: [
    new MiniCssExtractPlugin({ // The same method as output, preferably with a hash value to avoid caching
      filename: '[name].css'.// The generated file name
      chunkFilename: '[id].css'.// Build time generated, mainly to prevent file update browser does not update, cache caused}),].module: {
    rules: [{test: /\.css$/.use: [{loader: MiniCssExtractPlugin.loader, / / replace style - loader
            options: { // Other configuration items
              publicPath: '.. / '.// The specified address is the same as publicPath in output
              hmr: process.env.NODE_ENV === 'development'.// Environment variables}},'css-loader',],},],},};Copy the code

Optimization-css-assets-webpack-plugin is a plugin that optimizes-csS-assets-webpack-plugin is a plugin that optimizes-css-assets-webpack-plugin is a plugin that optimizes-css-assets-webpack-plugin Set optimization.minimizer to override the default values provided by Webpack, so you need to specify JS minimalizer.

const TerserJSPlugin = require('terser-webpack-plugin'); // JS will not be compressed without adding it
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // Import the CSS separation plug-in
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // CSS code compression
module.exports = {
  optimization: { // Add a property,
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css'.chunkFilename: '[id].css',})],module: {
    rules: [{test: /\.css$/.use: [MiniCssExtractPlugin.loader, 'css-loader'],},],},};Copy the code

Setting optimization.minimizer will cause overwriting, so download the terser-webpack-plugin to compress JS. Without this plugin, CSS code will be compressed, but JS code will not be compressed.

Configure module resolution (resolve)

Resolve configures how Webpack finds the files for the modules that depend on it, starting from the configured entry module. Webpack has built-in JavaScript modular syntax parsing capabilities, which are found by default using rules agreed in the modular standard, but you can also modify the default rules to suit your needs.

The basic configuration of Resolve is as follows, and for more, check out the official tutorial here.

const path = require('path') // File path module provided by Node
module.exports = {
  resolve: {
    extensions: ['.wasm'.'.mjs'.'.js'.'.json'].// Automatically resolve the extension that can be omitted
    alias: { // Create an alias for import or require to make module import easier.
        "@": path.resolve(__dirname, '.. /src'), xyz $: path. Resolve (__dirname,'XXX.js') // Exactly match xyz}}};Copy the code

Use of vue Loader

Before setting up vue scaffolding, you need to download two Loaders, vue-Loader and vue-template-Compiler. For details about how to install vue Loader, see the official description of vue Loader.

npm install -D vue-loader vue-template-compiler / / installation

Copy the code

Issues needing attention:eachvueWhen a new version of a package is released, a corresponding version of the packagevue-template-compilerIt will also be released. The compiler version must be basicvuePackages stay in sync like thisvue-loaderRun-time compatible code is generated. This means thatEach time you upgrade the VUE package in your project, you should also upgrade the VUe-template-Compiler.

Add the most basic code in main.js, which is the most basic entry configuration information

import Vue from 'vue'

window.vm = new Vue({
  el: '#app'.render: h= > h(App),
  components: { App },
  template: '<App/>'
})


Copy the code

Generally speaking, webpack does not recognize the suffix name of the. Vue file during compilation, so we need to manually add a loader in webpack to identify the. Vue file. The basic configuration is as follows:

// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  mode: 'development'.module: {
    rules: [{test: /\.vue$/.loader: 'vue-loader'
      },
      // It will be applied to ordinary '.js' files
      // and the '
      {
        test: /\.js$/.loader: 'babel-loader'
      },
      // It applies to normal '.css 'files
      // and the '. Vue 'file' 
      {
        test: /\.css$/.use: [
          'vue-style-loader'.'css-loader']]}},plugins: [
    // Be sure to introduce this plugin to cast magic
    new VueLoaderPlugin()
  ]
}
Copy the code

Vue loader15+ uses a vue-loader/lib/plugin. This plugin does not need to be downloaded separately. This plugin is already available when using vue-loader.

Webpack Packaging Optimization (DllPlugin)

In order to use packaging optimizations faster, it is necessary to update nodeJS and Webpack versions, reduce loader conversion as much as possible, and eliminate unnecessary directories such as: node-modules folder, plug-ins should use official recommendations whenever possible. You can also use the DllPlugin built into WebPack to optimize packaging speed.

The DllPlugin plug-in is used specifically in a separate Webpack configuration to create dlL-only bundles. It creates a manifest.json file for DllReferencePlugin mapping dependencies (create one and then copy it, which improves packaging efficiency).

For more information, see the official tutorial here. This is usually to create a webpack.dll.js file that is used to configure dllPlugin. The purpose is to pack some common libraries into a single file.

const path = require('path') // Import the Node module
module.exports = {
    mode: 'production'.// Production mode
    entry: {
        vendors: ['vue'.'jquery'] // import file, custom attributes
    },
    output: {filename: '[name].dll.js'.// Output multiple files packaged into a single file
        path: path.resolve(__dirname, '.. /dll'), // Package folder directory
        library: '[name]' // Export global variables for other files}}Copy the code

However, this method does not automatically add to the HTML page, so I need an add-asset-html-webpack-plugin to help me. We packaged the webpack.dll.js file to automatically add to the HTML

 cnpm i add-asset-html-webpack-plugin -D  / / installation
Copy the code

When using webpack.dll. Js, it should be written in a public file, such as webpack.base.conf.js. The basic configuration method is as follows:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // Import the auto-generated HTML plug-in
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin'); // Automatically add plug-ins
const webpackConfig = {
  entry: 'index.js'.output: {
    path: 'dist'.filename: 'index_bundle.js',},plugins: [
    new HtmlWebpackPlugin(),// See the HtmlWebpackPlugin configuration above for more information
     // require.resolve and path.resolve are used in the same way.
    new AddAssetHtmlPlugin({ filepath: require.resolve('.. /dll/vendors.dll.js')})]};Copy the code