[Vue] webpack for family bucket

overview

Webpack is a front-end resource building tool, a static module bundler. From the perspective of Webpack, all resource files (js/json/css/img/less/…) at the front end will be processed as modules. When Webpack processes the application, it will perform static analysis according to the dependencies of the modules, and package and generate the corresponding static resources.
insert image description here

Install

(wepack must rely on the node environment for normal operation, and the node environment must use the npm tool to manage various dependent packages in node in order to run normally), so to install webpack, you must first install Node.js, which comes with software package management tool npm

  • Install webpack globally (npm install [email protected] -g)
  • Partially install webpck (npm install [email protected] --save-dev) – save-dev is a development dependency, and does not need to be used after the project is packaged.

packaging explained

Webpack can help us modularize, and after dealing with various complex relationships between modules, the concept of packaging is well understood.
It is to package and merge various resource modules in webpack into multiple packages (Bundle), and in the process of packaging, resources can also be processed, such as compressing pictures, converting scss to css, and converting ES6 syntax to ES5 Grammar, converting TypeScript to JavaScript and so on. Packaging tools also include grunt/gulp
insert image description here

File and folder parsing

ist folder: used to store the files packaged later
src folder: used to store the source file we wrote
main.js: the entry file of the project.
mathUtils.js: defines some mathematical utility functions, which can be referenced and used elsewhere.
index.html: The browser opens the displayed homepage html (here refers to the final packaged file in src, that is, the contents of the dist folder).
package.json: A file generated by npm init and managed by npm packages.
insert image description here

Five core concepts of Webpack

Entry

Entry (Entry) instructs Webpack to use which file as the entry point to analyze and build the internal dependency graph and package it.

Output

Output (Output) instructs Webpack where to output the packaged resource bundles and how to name them.

Loader

Loader enables Webpack to process files in non-JavaScript languages, and Webpack itself can only understand JavaScript.

Plugins

Plugins can be used to perform a wider range of tasks, ranging from packaging and compression, to redefining variables in the environment.

Mode

Mode (Mode) instructs Webpack to use the configuration of the corresponding mode. It is divided into two modes: development and production, which are briefly described below.

  • development:
    development mode, an environment where the code can run locally, the value of process.env.NODE_ENV will be set to development, and the NamedChunksPlugin and NamedModulesPlugin plugins will be enabled at the same time;
  • production:
    production mode, which can optimize the running environment of the code. The value of process.env.NODE_ENV will be set to production, and the FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitreplaceStringsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin and UglifyJsPlugin plugins will be enabled at the same time.

webpack workflow

  1. Parameter parsing: read and merge parameters from configuration files and Shell statements to get the final parameters
  2. Find the entry file: starting from the Module configured in the Entry, recursively parse all the Modules that the Entry depends on
  3. Call the Loader to compile the file: every time a Module is found, it will find out the corresponding conversion rules according to the configured Loader
  4. Traversing the AST to collect dependencies: After converting the Module, parse out the Module that the current Module depends on
  5. Generate Chunk: Modules will be grouped in units of Entry. An Entry and all its dependent Modules are grouped into a group, which is a Chunk.
  6. Output file: Finally, Webpack will convert all Chunk into file output

Wbepack configuration

webpack.config.js file

webpack.config.js is the configuration file of webpack, which is used to instruct webpack to work. When running the webpack command, the configuration inside will be loaded. All construction tools are based on the nodejs platform, and the commonjs module is adopted by default. The basic configuration of webpack.config.js is shown in the figure.
insert image description here

devServer configuration

The development server (devServer) is used to realize automation (automatically compile, automatically open the browser, and automatically refresh the browser). It will only compile and package in memory without any file output. After installing webpack-dev-server locally, pass npx The webpack-dev-server command starts devServer, and the core code is shown in the figure.
insert image description here

Common Loader configuration

// webpack.config.js
module.exports = {
    
    
  module: {
    
    
    rules: [
     {
    
    
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
    
     test: /\.js$/, use: 'babel-loader' },
      {
    
    
        test: /\.css$/,
        use: [
          {
    
     loader: 'style-loader' },
          {
    
     loader: 'css-loader' },
          {
    
     loader: 'postcss-loader' },
        ]
      }
    ]
  }
};

Loader workflow

  1. A module Loader is configured in webpack.config.js;
  2. When the corresponding module file is encountered, the loader of the module is triggered;
  3. The loader accepts a source representing the contents of the module file;
  4. The loader uses a series of APIs provided by webapck to convert the source and get a result;
  5. Return or pass the result to the next Loader until the processing is completed.
let less = require('less');
module.exports = function (source) {
    
    
    const callback = this.async();
    //this.async() 返回一个回调函数,用于异步执行
    less.render(source, (err, result) => {
    
    
    //使用less处理对应的less文件的source
        callback(err, result.css);
    });
}

Common plugin configuration

extract-text-webpack-plugin
webpack packs css as a module into a chunk by default, and the function of extract-text-webpack-plugin is to extract css into an independent css file

const ExtractTextPlugin = require('extract-text-webpack-plugin');
new ExtractTextPlugin({
    
    
    filename: 'css/[name].css',
})
{
    
    
    test: /\.css$/,
    use: ExtractTextPlugin.extract({
    
    
        use: ['css-loader','postcss-loader','less-loader'],
        fallback: 'vue-style-loader',  #使用vue时要用这个配置
    })
},

The html-webpack-plugin
is very important. The first function is to create HTML page files to your output directory. The second function is to automatically import the chunks packaged by webpack into this HTML.

const HtmlPlugin = require('html-webpack-plugin')
new HtmlPlugin({
    
    
    filename: 'index.html',
    template: 'pages/index.html'
}

DefinePlugin
defines global constants

new webpack.DefinePlugin({
    
    
    'process.env': {
    
    
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
    },
    PRODUCTION: JSON.stringify(PRODUCTION),
    APP_CONFIG: JSON.stringify(appConfig[process.env.NODE_ENV]),
}),

UglifyJsPlugin
js compression

new webpack.optimize.UglifyJsPlugin()

Note: webpack4 has removed this plugin and replaced it with optimization.minimize

"Easy Principle"

A plug-in is like a function inserted into the production line to process resources on the production line at a specific time. webpack organizes this complex production line through Tapable. When webpack compiles the code, it will trigger a series of Tapable hook events. What the plug-in does is to find the corresponding hook and hang its own tasks on it, which is the registration event. When webpack is built, the plug-in registration event will follow The hook is triggered and executed.

The webpack plugin consists of:

  • A JavaScript named function.
  • Define an apply method on the prototype of the plug-in function.
  • Specify an event hook to bind to webpack itself.
  • Handles specific data for webpack's internal instance.
  • The callback provided by webpack is invoked after the function is completed
// 一个 JavaScript 命名函数。
function MyExampleWebpackPlugin() {
    
    
};
// 在插件函数的 prototype 上定义一个 apply 方法。
MyExampleWebpackPlugin.prototype.apply = function(compiler) {
    
    
// 指定一个挂载到 webpack 自身的事件钩子。
compiler.plugin('webpacksEventHook', function(compilation /* 处理 webpack 内部实例的特定数据。*/, callback) {
    
    
console.log("This is an example plugin!!!");
// 功能完成后调用 webpack 提供的回调。
callback();
 });
};

Package html/style/image/other resources

Packing different resources will use different loaders and plug-ins. The process of packaging html/style/picture/other resources is as follows.

Package html resources

1. Download the html-webpack-plugin plugin;

2. Introduce the html-webpack-plugin plug-in;

3. Use the html-webpack-plugin plug-in and configure it accordingly.

Packaging style resources

Different style files need to configure different loaders

1. Download loader;

2. Configure the loader, use css-loader and style-loader for css style files, and use less-loader, css-loader and style-loader for less files. Among them, the function of css-loader is to convert the css file into a commonjs module and load it into the js file, and the function of style-loader is to create a style tag, insert the style resource in js, and add it to the head to take effect.

Package image resources

1. Download url-loader, file-loader

2. Configure the loader

Package other resources

1. Download file-loader

  1. Configure the loader, configure the loader to act on other files that are not html/css/less/js

Extract css into a separate file/css compatibility processing/compress css

Extract css into a separate file

After the style file is packaged, it will be output together with the js file by default. The packaged css file can be output separately through the plug-in. The process is as follows.

1. Download the mini-css-extract-plugin plugin

2. Reference the plugin

3. Configuration

css compatibility processing

1. Download postcss-loader and postcss-preset-env

2. In the browserslist attribute in package.json, configure the compatibility of the development environment and the production environment respectively, and set the browser version that supports the style

3. Find the configuration in browserslist in package.json through postcss, and load the specified css compatibility style through configuration.

compress css

1. Download the optimize-css-assets-webpack-plugin plugin

2. Reference the plugin

3. Use the plugin

js syntax check eslint/js compatibility processing/js compression

js syntax check eslint

1. Download eslint-loader and eslint

2. Configure in eslintConfig in package.json

3. Configure eslint-loader, which only needs to detect js files and exclude third-party libraries, and only detect the source code written by yourself. At the same time, you can set fix: true in the options configuration to automatically repair eslint errors.

js compatibility processing

1. Download babel-loader, @babel/core, @babel/preset-env, do basic js compatibility processing through @babel/preset-env, and then do compatibility processing that cannot be realized before through corejs, and realize on-demand load

  1. Configure loaders

The core code of js compatibility processing is shown in the figure
insert image description here

js compression

When the mode is set to production, the js code will be automatically compressed.

Webpack performance optimization

The performance of webpack can be optimized separately from the development environment and the production environment. Among them, the development environment mainly considers optimization in terms of packaging and building speed and code debugging, and the production environment mainly considers optimizing in terms of packaging and building speed and code running performance. The following briefly introduces how to improve the construction speed through HMR in the development environment.

HMR

HMR (Hot Module Replacement), the function is that after a module changes, only this module will be updated and packaged instead of all modules. The HMR function is started by setting the hot:true attribute in devServer.

Among them, for style files, you can use the HMR function, because the style-loader implements it internally;

For js files, the HMR function cannot be used by default. The solution: modify the js code of the entry file and add the code that supports the HMR function. In addition, HMR can only process other files that are not entry js files, and it will not take effect for the entry file, because once the entry file Update, other files introduced by the entry file must be reloaded;

For html files, the HMR function cannot be used by default, and at the same time, the html file cannot be hot updated. The solution: modify the entry entry file and import the html file, which can only solve the problem that the html file cannot be hot updated.

The js file supports the core code of the HMR function as shown in the figure.
insert image description here

HMR effect

Introduce the print.js file into the entry index.js file, and after running npx webpack-devserver, the page is shown in the figure.
insert image description here

initial page

After modifying the print.js file, only the print.js file will be reloaded, but not the index.js file. The HMR effect is shown in the figure.
insert image description here

Reduce compilation scope and reduce unnecessary compilation work

That is, modules, mainFields, noParse, includes, exclude, and alias are all used.

const resolve = dir => path.join(__dirname, '..', dir);
resolve: {
    
    
    modules: [ // 指定以下目录寻找第三方模块,避免webpack往父级目录递归搜索
        resolve('src'),
        resolve('node_modules'),
        resolve(config.common.layoutPath)
    ],
    mainFields: ['main'], // 只采用main字段作为入口文件描述字段,减少搜索步骤
    alias: {
    
    
        vue$: "vue/dist/vue.common",
        "@": resolve("src") // 缓存src目录为@符号,避免重复寻址
    }
},
module: {
    
    
    noParse: /jquery|lodash/, // 忽略未采用模块化的文件,因此jquery或lodash将不会被下面的loaders解析
    // noParse: function(content) {
    
    
    //     return /jquery|lodash/.test(content)
    // },
    rules: [
        {
    
    
            test: /\.js$/,
            include: [ // 表示只解析以下目录,减少loader处理范围
                resolve("src"),
                resolve(config.common.layoutPath)
            ],
            exclude: file => /test/.test(file), // 排除test目录文件
            loader: "happypack/loader?id=happy-babel" // 后面会介绍
        },
    ]
}

webpack-parallel-uglify-plugin (optimize js compression process)

webpack-parallel-uglify-plugin能够把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程,从而实现并发编译,进而大幅提升 js 压缩速度。

const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
// ...
optimization: {
    
    
minimizer: [
new ParallelUglifyPlugin({
    
     // 多进程压缩
cacheDir: '.cache/',
uglifyJS: {
    
    
output: {
    
    
comments: false,
beautify: false
 },
compress: {
    
    
warnings: false,
drop_console: true,
collapse_vars: true,
reduce_vars: true
   }
  }
 }),
 ]
}

HappyPack in

When webpack is running in node and packaged, it is single-threaded to do one thing. HappyPack can open multiple sub-processes to execute concurrently. After the sub-processes are processed, the results are handed over to the main process.

const HappyPack = require('happypack');
module.exports = {
    
    
	entry: './src/index.js',
	output: {
    
    
		path: path.join(__dirname, './dist'),
		filename: 'main.js',
    },
    module: {
    
    
        rules: [
            {
    
    
                test: /\.jsx?$/,
                exclude: /node_modules/,
                use: 'happypack/loader?id=babel',
            },
        ]
    },
    plugins: [
        new HappyPack({
    
    
            id: 'babel',  //id值,与loader配置项对应
            threads: 4,  //配置多少个子进程
            loaders: ['babel-loader']  //用什么loader处理
        }),
    ]
}

DLL dynamic linking

The third-party library is not updated frequently, and it is hoped to be packaged separately to improve the packaging speed. To package dll, you need to create a new webpack configuration file (webpack.dll.config.js). When packaging dll, webpack makes an index and writes it in the manifest file. Then you only need to read the manifest file when packaging the project file.

const webpack = require("webpack");
const path = require('path');
const CleanWebpackPlugin = require("clean-webpack-plugin");
const dllPath = path.resolve(__dirname, "../src/assets/dll"); // dll文件存放的目录

module.exports = {
    
    
entry: {
    
    
// 把 vue 相关模块的放到一个单独的动态链接库
vue: ["babel-polyfill", "fastclick", "vue", "vue-router", "vuex", "axios", "element-ui"]
},
output: {
    
    
filename: "[name]-[hash].dll.js", // 生成vue.dll.js
path: dllPath,
library: "dll[name]"
},
plugins: [
new CleanWebpackPlugin(["*.js"], {
    
     // 清除之前的dll文件
root: dllPath,
}),
new webpack.DllPlugin({
    
    
name: "dll[name]",
// manifest.json 描述动态链接库包含了哪些内容
path: path.join(__dirname, "./", "[name].dll.manifest.json")
 }),
 ],
};

Next, you need to add the dll command in package.json.

"scripts": {
    
    
    "dll": "webpack --mode production --config build/webpack.dll.config.js"
}

After running npm run dll, the ./src/assets/dll/vue.dll-[hash].js public js and ./build/vue.dll.manifest.json resource description files will be generated. So far, the dll preparations are complete, and then Just refer to it in webpack.

externals: {
    
    
    'vue': 'Vue',
    'vue-router': 'VueRouter',
    'vuex': 'vuex',
    'elemenct-ui': 'ELEMENT',
    'axios': 'axios',
    'fastclick': 'FastClick'
},
plugins: [
    ...(config.common.needDll ? [
        new webpack.DllReferencePlugin({
    
    
            manifest: require("./vue.dll.manifest.json")
        })
    ] : [])
]

How webpack optimizes front-end performance

Third-party library on-demand loading, routing lazy loading

//The third-party ui library element, vant and other libraries provide on-demand loading methods to avoid all imports and increase the project size

import {
    
     Button, Select } from 'element-ui';

//路由懒加载
const showImage = () => import('@/components/common/showImage');

code splitting

Extract the third-party library "vendor"
module.exports = { entry: { main: './src/index.js', vendor: ['react', 'react-dom'], }, }




Dependent library separation "splitChunks"

optimization: {
    
    
  splitChunks: {
    
    
     chunks: "async", // 必须三选一: "initial" | "all"(推荐) | "async" (默认就是async)
     minSize: 30000, // 最小尺寸,30000
     minChunks: 1, // 最小 chunk ,默认1
     maxAsyncRequests: 5, // 最大异步请求数, 默认5
     maxInitialRequests : 3, // 最大初始化请求书,默认3
     automaticNameDelimiter: '~',// 打包分隔符
     name: function(){
    
    }, // 打包后的名称,此选项可接收 function
     cacheGroups:{
    
     // 这里开始设置缓存的 chunks
         priority: 0, // 缓存组优先级
         vendor: {
    
     // key 为entry中定义的 入口名称
             chunks: "initial", // 必须三选一: "initial" | "all" | "async"(默认就是async)
             test: /react|lodash/, // 正则规则验证,如果符合就提取 chunk
             name: "vendor", // 要缓存的 分隔出来的 chunk 名称
             minSize: 30000,
             minChunks: 1,
             enforce: true,
             maxAsyncRequests: 5, // 最大异步请求数, 默认1
             maxInitialRequests : 3, // 最大初始化请求书,默认1
             reuseExistingChunk: true // 可设置是否重用该chunk
         }
     }
  }
 },

Remove redundant code

「Tree-Shaking」
insert image description here

source

Webpack detailed
front-end advanced-Webpack article
If you want to understand Webpack, read this article is enough

Guess you like

Origin blog.csdn.net/weixin_44231544/article/details/132333606