preface

This series as the author sent before the front-end high frequency interview arrangement of the supplement will be more inclined to high front-end interview questions, of course, everyone from the novice all the way to interested friends can see ha

“Fun: “Mention webpack is really a sad tears still remember weboack1.0 version just came out when I according to the document of a configuration item and the official website configuration is the same as all kinds of error read do not understand at that time plus just do front-end is webpack from the entry to give up Especially now when you are interviewing for a senior position in the front end you will find that interviewers like to ask about Webpack. Some of the big companies I have seen have introduced themselves and then started practicing webpack. Haha (maybe I have some architectural experience on my resume)

“Change: “At present, Webpack has reached version 4.0. Official documents and many things have been optimized. Now it is easier to use and all kinds of scaffolding basically help us configure Webpack Front-end automation packaging is a must to master at the same time as advanced front-end front-end tools must be firmly mastered

1 What is Webpack


Webpack is an automated packaging solution, also known as a modular baler. It helps us analyze the project structure, find JavaScript modules and other extension languages (Scss, TypeScript, etc.) that browsers don’t run directly, and package them into a format that browsers can use.

If there is no Webpack we manually to deal with the above things would be a lot of trouble

2 Common Configurations of WebPack

  1. Entry: Entry, the first step in the build that Webpack performs will start with Entry, which can be abstracted into input.
  2. Output: Outputs the result after Webpack has gone through a series of processes and produced the final desired code.
  3. Mode: Provides the mode configuration option to tell Webpack to use the built-in optimizations for the corresponding mode
  4. Module: Module, in Webpack everything is a Module, a Module corresponds to a file.
  5. Chunk: a Chunk is a code block. A Chunk is composed of multiple modules for code merging and splitting.
  6. Loader: module converter, used to convert the original content of a module into new content as required.
  7. Plugin: Extension Plugin that injects extension logic at specific points in the Webpack build process to change the build result or do what you want.

3 Webpack workflow

  1. Parameter parsing: Reading and merging parameters from configuration files and Shell statements to arrive at the final parameters
  2. Find the Entry file: Recursively parse all modules that Entry depends on, starting with the Module configured in Entry
  3. Call Loader to compile files: for each Module found, the corresponding conversion rule will be found based on the configured Loader
  4. Traverse the AST to collect dependencies: After converting modules, parse out the modules that the current Module depends on
  5. Generate Chunk: These modules are grouped by Entry. An Entry and all its dependent modules are grouped into a group, namely a Chunk
  6. Output files: Eventually Webpack converts all chunks into file output

Want to see the specific webpack compilation principle source students portal

4 Common Loader configuration and Workflow

// 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' },
        ]
      }
    ]
  }
};
Copy the code

Loader workflow

  1. Webpack.config. js is configured with a module Loader;
  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. Loader uses a series of apis provided by Webapck to convert the source and get a result.
  5. Result is returned or passed to the next Loader until processing is complete.

Take a look at the example of less-loader.

let less = require('less'); module.exports = function (source) { const callback = this.async(); //this.async() returns a callback function, Use less to render(source, (err, result) => {// Use less to process the source callback(err, result.css) of the corresponding less file; }); }Copy the code

5 Common Plugin configurations and simple principles

Introduction of common plug-ins for the project

  1. extract-text-webpack-plugin

By default, Webpack packs CSS into a chunk as a module, and the extract-text-webpack-plugin is used to extract CSS into separate CSS files

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', # vueCopy the code
  1. Html-webpack-plugin is an important plugin for creating HTML page files in your output directory and for automatically importing chunks of webpack into the HTML
const HtmlPlugin = require('html-webpack-plugin')
new HtmlPlugin({
    filename: 'index.html',
    template: 'pages/index.html'
}
Copy the code
  1. 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]),
}),
Copy the code
  1. UglifyJsPlugin js compressed
new webpack.optimize.UglifyJsPlugin()
Copy the code

Note: webpack4 has removed this plug-in and replaced it with optimization.minimize

  1. CommonsChunkPlugin CommonsChunkPlugin is mainly used to extract third-party libraries (such as jQuery) and public modules (public JS, CSS can be). It is often used in multi-page applications to generate public chunks and avoid repeated references.
{
    entry: {
        vendor: 'index.js'
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: ['vendor','runtime'],
            filename: '[name].js'
        }),
    ]
}
Copy the code

Note: Webpackage 4 has removed this plug-in and replaced it with optimization.splitchunks

The simple principle

A plug-in is like a function that plugs into a production line and works with resources on the production line at a specific time. Webpack organizes this complex production line through Tapable. When webPack builds, it triggers a Tapable hook event. All the plug-in does is find the corresponding hook and attach its task, the registration event, to it. When WebPack builds, the registration event will execute as the hook is triggered.

The WebPack plug-in consists of:

  • A JavaScript naming function.
  • Define an apply method on the prototype of the plug-in function.
  • Specifies an event hook bound to WebPack itself.
  • Handles specific data for webPack internal instances.
  • The callback provided by WebPack is invoked when the functionality is complete

“Custom Plug-in Examples” (see creating plug-ins for more information)

// a JavaScript naming function. function MyExampleWebpackPlugin() {

};

// Define an apply method on the prototype of the plug-in function. MyExampleWebpackPlugin. Prototype. Apply = function (compiler) {/ / specify a mount to webpack event hooks. Compiler. plugin('webpacksEventHook', function(compilation /* Handles specific data for webpack internal instances. */, callback) { console.log("This is an example plugin!!!" );

// Call the webPack callback when the function is complete. callback();Copy the code

});
};

Copy the code

6 What if WebPack is too slow to pack

  1. Reduce the 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: [// Specify the following directory to find third-party modules, Avoid webpack recursively searching the parent directory for resolve(' SRC '), resolve('node_modules'), resolve(config.mon.layoutpath)], mainFields: ['main'], // Use main only as the entry file description field to reduce search steps alias: {vue$: "vue/dist/vue.common", "@": Resolve (" SRC ") // cache SRC directory as @ symbol, avoid duplicate addressing}}, module: {noParse: / jquery | lodash /, / / ignore the file without adopting modular, so jquery or lodash will not be the loaders parsing / / noParse below: function(content) { // return /jquery|lodash/.test(content) // }, rules: [ { test: /\.js$/, include: Resolve (" SRC "), resolve(config.mon.layoutpath)], exclude: Loader: "happypack/loader? Id =happy-babel"},]}Copy the code
  1. Webpack-parallel-ugliliy-plugin plugin to optimize JS compression

Webpack-parallel-ugli-fi -plugin can decompose tasks to multiple sub-processes for concurrent execution, and then send the results to the main process after the sub-process is finished, so as to achieve concurrent compilation and greatly improve js compression speed

const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
Copy the code

/ /... Optimization: {minimizer: [new ParallelUglifyPlugin({// cacheDir: '. Cache /', uglifyJS: {output: {comments: false, beautify: false }, compress: { warnings: false, drop_console: true, collapse_vars: true, reduce_vars: true } } }), ] }

  1. HappyPack

    When webpack is run in node, it is done one thing at a time by a single thread. HappyPack can start multiple child processes to execute concurrently, and the child processes the results 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: },}, plugins: [new happypack ({id: 'Babel ', //id:' Babel ',},]}, plugins: [new happypack ({id: 'Babel ',}), //id: ['babel-loader'] loaders: ['babel-loader']}),]}Copy the code
  1. DLL dynamic linking

The third party library is not updated frequently, so we hope to pack it separately to improve the packaging speed. To pack DLLS, create a webPack configuration file (webpack.dll.config.js). When packing DLLS, Webpack makes an index, which is written in the manifest file. Then you just read the manifest file when you package 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"); // Directory for storing DLL filesCopy the code

Module.exports = {entry: {// Exports of vUE related modules into a separate dynamically linked library vue: ["babel-polyfill", "fastclick", "vue", "vue-router", "vuex", "axios", "element-ui"] }, output: { filename: [name]-[hash].dll. Js ", // Generate vue.dll. Js path: dllPath, library:"dll[name]"}, plugins: [new CleanWebpackPlugin(["*.js"], {// Clean up the DLL file root: dllPath,}), new webpack.dllplugin ({name: "dll[name]", // manifest.json describes what the dynamic link library contains. Path: path.join(__dirname, "./", "[name].dll.manifest.json")}),],};

Next, you need to add the DLL command to package.json.

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

After running NPM run DLLS, generates the. / SRC/assets/DLL/vue. DLL – [hash]. Public js and js. / build/vue. DLL. The manifest. Json resource description file, thus the DLL preparation is complete, Then reference it in the 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") }) ] : [])]Copy the code

7 How does WebPack optimize front-end performance

  1. Third-party libraries are loaded on demand and routes are loaded lazily
Import {Button, Select} from 'element-ui'; import {Button, Select} from 'element-ui';Copy the code

/ / routing lazily const showImage = () = > import (' @ / components/common/showImage);

  1. The code segment
  • Extract third-party library “Vendor”
module.exports = {
    entry: {
        main: './src/index.js',
        vendor: ['react', 'react-dom'],
    },
}
Copy the code
  • Rely on libraries to separate “splitChunks”
Optimization: {splitChunks: {chunks: "async", / / must choose three: "initial" | "all" (recommended) | "async" (the default is async) minSize: // Minimum size, 30000 minChunks: 1, // minimum chunk, default 1 maxAsyncRequests: 5, // Maximum asynchronous requests, default 5 maxInitialRequests: 3, // Maximum initialization request, default 3 automaticNameDelimiter: '~',// Pack delimiter name: Function (){}, // this option can be received by function cacheGroups:{// this option starts with chunks priority: 0, // cache group priority vendor: {/ / key to entry the entry name defined in chunks: "initial", / / must choose three: "initial" | | "all" "async" (the default is async) test. / react | lodash /, / / verify the regular rules, if conform to extract the chunk name: "vendor", / / to cache that separates the chunk name minSize: 30000, minChunks: 1, enforce: True, maxAsyncRequests: 5, // Maximum asynchronous requests (default: 1) maxInitialRequests: 3, // Maximum initial requests (default: 1) reuseExistingChunk: True // You can set whether to reuse the chunk}}}},Copy the code
  1. Remove redundant code

Tree-Shaking


Shark’s front-end fishing skills

Welcome everyone technical exchange push touch fish help all can – link