webpack interview knowledge points

What are the common Loaders? Which Loaders have you used?

  • raw-loader: load the original content of the file (utf-8)
  • file-loader: Output the file to a folder, and refer to the output file through the relative URL in the code (processing pictures and fonts)
  • url-loader: file-loaderSimilar to , the difference is that the user can set a threshold, and return its publicPath when it is greater than the threshold, and return the base64 encoding of the file (processing pictures and fonts) when it is less than the threshold
  • svg-inline-loader: Inject minified SVG content into code
  • image-loader: load and compress image files
  • json-loader: load JSON file (included by default)
  • handlebars-loader: Compile the Handlebars template into a function and return
  • style-loader: Inject CSS code into JavaScript, and load CSS through DOM operations
  • postcss-loader: Extended CSS syntax, using next-generation CSS, can automatically complete CSS3 prefixes with the autoprefixer plug-in
  • sass-loader: Convert SCSS/SASS code to CSS
  • css-loader: Load CSS, support modularization, compression, file import and other features
  • source-map-loader: Load additional Source Map files to facilitate breakpoint debugging
  • babel-loader: Convert ES6 to ES5
  • ts-loader: Convert TypeScript to JavaScript
  • awesome-typescript-loader: Convert TypeScript to JavaScript with better performance than ts-loader
  • eslint-loader: Check JavaScript code via ESLint
  • tslint-loader: TypeScript code checked by TSLint
  • vue-loader: load Vue.js single-file components
  • mocha-loader: Code to load Mocha test cases
  • coverjs-loader: Calculate the coverage of the test
  • i18n-loader: globalization
  • cache-loader: Can be added before some Loaders with high performance overhead, the purpose is to cache the results to disk

For more Loader, please refer to the official website

What are the common Plugins? Which Plugins have you used? (The bold part is the webpack speed-up related plug-in)

  • define-plugin: Define environment variables (specified mode will be automatically configured after Webpack4)
  • ignore-plugin: Ignore some files
  • html-webpack-plugin: Simplifies HTML file creation (depends on html-loader)
  • web-webpack-plugin: It can easily output HTML for single-page applications, which is easier to use than html-webpack-plugin
  • mini-css-extract-plugin: Separate style files, extract CSS as independent files, support on-demand loading (replace extract-text-webpack-plugin)
  • serviceworker-webpack-plugin: Add offline caching function for web applications
  • clean-webpack-plugin: directory cleanup
  • uglifyjs-webpack-plugin: Does not support ES6 compression (before Webpack4)
  • terser-webpack-plugin: Support for compressing ES6 (Webpack4)
  • webpack-parallel-uglify-plugin: Multi-process code compression to improve build speed
  • ModuleConcatenationPlugin: Enable Scope Hoisting
  • speed-measure-webpack-plugin: You can see the execution time of each Loader and Plugin (the entire packaging time, the time of each Plugin and Loader)
  • webpack-bundle-analyzer: Visualize the volume of Webpack output files (business components, dependent on third-party modules)

For more Plugin, please refer to the official website

The difference between Loader and Plugin

LoaderThe essence is a function in which the received content is converted and the converted result is returned. Because Webpack only understands JavaScript, Loader becomes a translator, preprocessing the translation of other types of resources.

PluginIt is a plug-in, whose essence is to monitor the entire packaging life cycle . Based on the event flow framework Tapable, the plug-in can extend the functions of Webpack. During the life cycle of Webpack running, many events will be broadcast. Plugin can listen to these events and pass Webpack at the right time. API provided to change the output result.

LoaderConfigured in module.rules, as the parsing rules of the module, the type is an array. Each item is an Object, which contains attributes such as test (type file), loader, and options (parameters).

PluginSeparately configured in plugins, the type is an array, each item is an instance of Plugin, and the parameters are passed in through the constructor.

Webpack build process

The running process of Webpack is a serial process, and the following processes will be executed sequentially from start to finish:

  • 初始化参数: Read and combine parameters from configuration files and Shell statements to get the final parameters
  • 开始编译: Initialize the Compiler object with the parameters obtained in the previous step, load all configured plug-ins, and execute the run method of the object to start compiling
  • 确定入口: Find all entry files according to the entry in the configuration
  • 编译模块: Starting from the entry file, call all configured Loaders to translate the module, then find out the modules that the module depends on, and then recurse this step until all the files that the entry depends on have been processed by this step
  • 完成模块编译: After translating all modules using Loader in step 4, the final translated content of each module and the dependencies between them are obtained
  • 输出资源: According to the dependency relationship between the entry and the module, assemble into a Chunk containing multiple modules, and then convert each Chunk into a separate file and add it to the output list. This step is the last chance to modify the output content
  • 输出完成: After determining the output content, determine the output path and file name according to the configuration, and write the file content to the file system

In the above process, Webpacka specific event will be broadcast at a specific time point, and the plug-in will execute specific logic after listening to the event of interest, and the plug-in can call the API provided by Webpack to change the running result of Webpack.

simply say:

  • Initialization: start the build, read and merge configuration parameters, load Plugin, instantiate Compiler
  • Compilation: Starting from the Entry, serially call the corresponding Loader for each Module to translate the content of the file, and then find the Module that the Module depends on, and compile recursively
  • Output: Combine the compiled Module into Chunk, convert the Chunk into a file, and output it to the file system

When developing with webpack, what plugins have you used to improve efficiency?

  • webpack-dashboard: It can display relevant packaging information in a more friendly way.
  • webpack-merge: Extract public configuration to reduce duplication of configuration code
  • speed-measure-webpack-plugin: SMP for short, it analyzes the time-consuming of Loader and Plugin in the Webpack packaging process, which helps to find the performance bottleneck in the construction process.
  • size-plugin: Monitor resource volume changes to detect problems as early as possible
  • HotModuleReplacementPlugin: Module Hot Replacement

What is a source map? How to use the production environment?

source mapIt is the process of mapping compiled, packaged, and compressed code back to source code. The packaged and compressed code does not have good readability. Soucre map is needed to debug the source code.

The browser will not load the map file as long as the developer tools are not opened.

Generally, there are three solutions for the online environment:

  • hidden-source-map: Use Sentry, a third-party error monitoring platform
  • nosources-source-map: Only the specific number of lines and the error stack for viewing the source code will be displayed. Security is higher than sourcemap
  • sourcemap: Through nginx settings, the .map file is only open to the whitelist (company intranet)

Note : Avoid using inline-and eval-as they increase bundle size and reduce overall performance.

Module packaging principle

WebpackTurn all parsed modules into an object, then load our things through the entry module, and then implement recursive dependencies in turn, and run all files through the entry. Webpack actually creates an environment for each module that can be exported and imported. In essence, it does not modify the execution logic of the code, and the code execution order is exactly the same as the module loading order.

Principle of file monitoring

When it is found that the source code changes, a new output file is automatically rebuilt.

There are two ways to enable Webpack to monitor mode:

  • When starting webpackthe command , bring --watchthe parameter
  • webpack.config.jsset in configurationwatch:true

Disadvantage : Need to manually refresh the browser every time

Principle : Polling to determine whether the last editing time of the file has changed. If a file changes, the listener will not be notified immediately, but will be cached first and executed aggregateTimeoutlater

module.export = {
    // 默认false,也就是不开启
    watch: true,
    // 只有开启监听模式时,watchOptions才有意义
    watchOptions: {
        // 默认为空,不监听的文件或者文件夹,支持正则匹配
        ignored: /node_modules/,
        // 监听到变化发生后会等300ms再去执行,默认300ms
        aggregateTimeout:300,
        // 判断文件是否发生变化是通过不停询问系统指定文件有没有变化实现的,默认每秒问1000次
        poll:1000
    }
}

Webpack hot update principle

WebpackThe hot update is also called hot replacement ( Hot Module Replacement), abbreviated as HMR. This mechanism can replace the old module with the newly changed module without refreshing the browser.

The core of HMR is that the client pulls the updated file from the server. To be precise, it is chunk diff (the part of the chunk that needs to be updated). In fact, a WebsocketWebpack-dev-server is maintained between (WDS) and the browser ( websocket can establish local services. Two-way communication with the browser. ), when the local file changes, the browser will be notified to update the code hot.

Specifically, when the local resource changes, WDS will push an update to the browser, and bring the hash at the time of construction, so that the client can compare with the last resource. After the client compares the difference, it will initiate Ajaxa request to obtain the changed content (file list, hash), so that the client can use this information to continue to initiate jsonpa request to WDS to obtain the incremental update of the chunk.

Subsequent parts (how to deal with incremental updates? Which states should be kept? Which ones need to be updated?) are completed HotModulePluginby provide relevant APIs for developers to process according to their own scenarios, such as react-hot-loaderand vue-loaderare implemented with the help of these APIs HMR. Details can be found here

What is a file fingerprint? how to use?

The file fingerprint is the suffix of the output file name after packaging.

  • Hash: It is related to the construction of the entire project. As long as the project file is modified, the hash value of the entire project construction will change
  • Chunkhash: related to the chunk packaged by Webpack, different entry will generate different chunkhash
  • Contenthash: Define the hash according to the content of the file. If the content of the file remains unchanged, the contenthash remains unchanged

JS file fingerprint settings

Set the filename of output, use chunkhash.

module.exports = {
    entry: {
        app: './scr/app.js',
        search: './src/search.js'
    },
    output: {
        filename: '[name][chunkhash:8].js',
        path:__dirname + '/dist'
    }
}

CSS File Fingerprint Settings

Set the filename of MiniCssExtractPlugin to use contenthash.

module.exports = {
    entry: {
        app: './scr/app.js',
        search: './src/search.js'
    },
    output: {
        filename: '[name][chunkhash:8].js',
        path:__dirname + '/dist'
    },
    plugins:[
        new MiniCssExtractPlugin({
            filename: `[name][contenthash:8].css`
        })
    ]
}

File fingerprint settings for images

Set the name of the file-loader, using hash.

Placeholder name and meaning

  • ext resource extension
  • name file name
  • path relative path to the file
  • folder The folder where the file is located
  • contenthash The content hash of the file, the default is generated by md5
  • hash The hash of the file content, the default is generated by md5
  • emoji A random emoj referring to the content of the file
const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename:'bundle.js',
        path:path.resolve(__dirname, 'dist')
    },
    module:{
        rules:[{
            test:/\.(png|svg|jpg|gif)$/,
            use:[{
                loader:'file-loader',
                options:{
                    name:'img/[name][hash:8].[ext]'
                }
            }]
        }]
    }
}

In actual projects, it is common for configuration files to have hundreds of lines. How to ensure that each loader works as expected?

You can enforceuse loaderthe action order of "forced execution", prewhich means to execute before all normal loaders and postafter all loaders. (inline is not officially recommended)

How to monitor and analyze the bundle volume?

VSCodeThere is a plug-in in Import Costthat can help us monitor the size of imported modules in real time, and also use webpack-bundle-analyzerthe bundlegenerated module composition diagram to display the occupied volume.

bundlesizeThe toolkit enables automated resource volume monitoring.

How to optimize Webpack build speed?

  • 多进程/多实例构建: HappyPack (not maintained), thread-loader
  • 多进程并行压缩
    • webpack-paralle-uglify-plugin (no longer maintained)
    • uglifyjs-webpack-plugin enables parallel parameters (ES6 is not supported)
    • terser-webpack-plugin enables parallel parameters (supports ES6)
  • DLL
    • Use DllPlugin to subpackage third-party libraries in advance, use DllReferencePlugin (index link) to reference manifest.json, let some code that will not change be packaged into static resources first, and tell webpack that these libraries are packaged in advance through the json file. Avoid wasting time on repeated compilation.
    • HashedModuleIdsPlugin can solve the module digital id problem
  • 充分利用缓存提升二次构建速度
    • babel-loader enables caching
    • terser-webpack-plugin enables caching
    • Use cache-loader or hard-source-webpack-plugin
  • 缩小构建目标/减少文件搜索范围
    • exclude (modules that do not need to be parsed)/include (modules that need to be parsed)
    • resolve.modules tells webpack the directory to search when parsing the module, indicating the absolute path of the third-party module
    • resolve.mainFields limits the name of the module entry file, and only uses the main field as the entry file description field (to reduce the search steps, it is necessary to consider the entry file description fields of all third-party modules that depend on runtime)
    • resolve.alias When importing a module from an npm package (for example, import * as React from 'react'), this option will determine which field to use in package.json to import the module. Depending on the target specified in the webpack configuration, the default value will vary
    • resolve.extensions minimizes the possibility of extension attempts
    • noParse ignores libraries that do not need to be parsed at all (do not parse but will still be packaged into the bundle, note that the ignored files should not contain modular statements such as import, require, define, etc.)
    • IgnorePlugin (completely exclude modules)
  • 动态Polyfill
    • The User Agent is identified through the Polyfill Service, and different Polyfills are issued to achieve on-demand loading and community maintenance. (The UA of some domestic wonderful browsers may not be recognized, but it can be downgraded and returned to all required polyfills)
  • Scope hoisting (「作用域提升」)
    • There will be a large number of closures in the built code, resulting in an increase in size, more function scopes created when running the code, and greater memory overhead. Scope hoisting "lifts" the imported js file to the top of its importer . Its implementation principle is: analyze the dependencies between modules, and merge the scattered modules into one function as much as possible, but the premise is that it cannot Cause code redundancy. So only those modules that are referenced once can be merged .
    • It must be ES6 syntax , because many third-party libraries still use CommonJS syntax and Scope Hoisting. To analyze the dependencies between modules, you need to configure mainFields. For third-party modules, the ES6 modular syntax pointed to in jsnext:main is preferred.
  • 提取页面公共资源
    • Use html-webpack-externals-plugin to import the basic package through CDN, not into the bundle
    • Use SplitChunksPlugin for (public script, base package, page public file) separation (Webpack4 built-in), replacing the CommonsChunkPlugin plugin
    • Base package separation
  • Tree shaking
    • Use purgecss-webpack-plugin with mini-css-extract-plugin (recommended)
    • During the packaging process, detect and mark unreferenced modules in the project, and remove them from the final bundle during resource compression (only valid for ES6 Modlue). Use ES6 Module modules as much as possible during development to improve tree shaking efficiency
    • Disable the module dependency parsing of babel-loader, otherwise Webpack will receive converted CommonJS modules, and cannot perform tree-shaking
    • Use PurifyCSS (not maintained) or uncss to remove useless CSS code

For more optimization, please refer to the official website - build performance

What is the essence of code splitting? What's the point?

The essence of code splitting is actually an intermediate state between these two extreme solutions that is more suitable for actual scenarios 源代码直接上线.打包成唯一脚本main.bundle.js

"A better user experience in exchange for an acceptable increase in server performance pressure."

  • The source code goes online directly: Although the process is controllable, there are many http requests and the performance overhead is high.
  • Packaged into a unique script: It’s fun after a shuttle, the server pressure is low, but the page is blank for a long time, and the user experience is not good.

Have you ever written Loader? Briefly describe the idea of ​​​​writing the loader?

Loader supports chain calls, so the development needs to strictly follow the "single responsibility", and each Loader is only responsible for what it needs to be responsible for.

Loader's API can be found on the official website

  • Loader runs in Node.js, we can call any API that comes with Node.js or install a third-party module to call
  • The original content passed to Loader by Webpack is a string encoded in UTF-8 format. When Loader processes binary files in some scenarios, it is necessary to tell Webpack whether the Loader needs binary data through exports.raw = true
  • Asynchronous Loader as much as possible, if the amount of calculation is small, synchronization is also possible
  • Loader is stateless, we should not keep state in Loader
  • Use the utilities provided by loader-utils and schema-utils
  • Load local Loader method
    • Npm link
    • ResolveLoader

Have you ever written a Plugin? Briefly describe the idea of ​​writing Plugin?

Webpack will broadcast many events during the running life cycle, Plugin can listen to these events, and hook in the custom functions you want to add at a specific stage. The Tapable event flow mechanism of Webpack ensures the order of the plug-ins, making the whole system scalable.

Plugin API can go to the official website to check

  • The compiler exposes hooks related to the entire lifecycle of Webpack
  • compilation exposes more granular event hooks related to modules and dependencies
  • A plugin needs to bind the apply method on its prototype to access the compiler instance
  • The compiler and compilation objects passed to each plugin are the same reference, if their properties are modified in one plugin, it will affect the subsequent plugins
  • Find the right event point to complete the desired function
    • When the emit event occurs, the final output resources, code blocks, modules and their dependencies can be read and modified (the emit event is the last opportunity to modify the resources output by Webpack)
    • watch-run is triggered when a dependent file changes
  • Asynchronous events need to call a callback function to notify Webpack to enter the next process when the plug-in finishes processing the task, otherwise it will get stuck

Let’s talk about the principle of Babel

Most JavaScript Parsers follow estreethe specification , Babelinitially based on acornthe project (lightweight modern JavaScript parser), Babel is a library that converts code that browsers cannot recognize, and Babel is roughly divided into three parts:

  • ParserParsing: convert the code into抽象语法树 (AbstractSyntaxTree,简称 AST)
    • Lexical analysis: split the code in the form of a string into 令牌(token)a stream, that is, an array of syntax units
    • Syntax analysis: convert token stream into AST
  • TransformerTransformation: Transform the generated AST into a new AST plugins/presetsaccording to the configuredParser
    • Taro is a small program syntax conversion completed by babel
  • GeneratorGenerate: Generate code from the new AST

Students who want to know how to implement a compiler step by step can move to the open source project the-super-tiny-compiler recommended by Babel official website

reference

"Hematemesis finishing" another dozen Webpack interview questions

Guess you like

Origin blog.csdn.net/Moonoly/article/details/113928160