concept

Essentially, WebPack is a static module wrapper for modern JavaScript applications. When WebPack works with an application, it recursively builds a dependency graph that contains every module the application needs, and then packages all of those modules into one or more bundles.

context

Context is the base directory for webPack compilation and is a string of absolute paths used to parse entry and Loader from the configuration. After the Context field is configured, Webpack uses context as the root directory when looking for files in relative paths. Context defaults to the current working directory where the webpack was launched. If you want to change the default context configuration, you can use the following configuration:

module.exports = {
    context: path.resolve(__dirname, 'src')}Copy the code

Note: Once the context is set, you need to set the path relative to the context configuration when configuring entry.

The advantage of this is that the WebPack configuration can be independent of the project directory. For example, when configuration files of the development environment and production environment are separated, webpack.config.js is generally placed in the build folder. In this case, entry is not configured relative to the build directory, but can be configured according to the context Settings.

Entry portal

Entry is the entry that indicates which module WebPack should use as a starting point for building its internal dependency graph. Once inside Entry, WebPack finds out which modules and libraries Entry depends on directly or indirectly. You can specify an entry (or entries) by configuring the Entry property in the WebPack configuration file. The default value is./ SRC.

Single entry syntax

Usage: entry: string | Array < string >

webpack.config.js

module.exports = {
	entry: './src/index.js'.// Import file
    output: { // Output file
        filename: 'bundle.js'.// The output file name
        path: path.resolve(__dirname, 'dist') // The output file address}}Copy the code

The single entry syntax for the entry property is shorthand for:

module.exports = {
	entry: { // Import file
		main: './src/index.js'
	},
    output: { // Output file
        filename: 'bundle.js'.// The output file name
        path: path.resolve(__dirname, 'dist') // The output file address}}Copy the code

Object syntax

When you want to build a multi-page application, you can use the object syntax to tell WebPack to build multiple bundles at once.

Usage: entry: {[entryChunkName: string] : string | Array < string >}

Key is a common character string

The key value in the entry can be a simple string that corresponds to the [name] variable in the output.filename configuration.

module.exports = {
	entry: {
        main: "./src/index.js".print: "./src/print.js"
      },
    output: {
        filename: "[name].bundle.js".path: path.resolve(__dirname, "dist")}}Copy the code

The packing result of the preceding configuration is as follows:

Note: If you build a multi-page application using object syntax, you will end up building multiple bundles. Therefore, you cannot specify a single file in output. Otherwise, the build will fail and an error will be reported.

Key is a string of paths

The key value in the entry can be a path string. In this case, Webpack automatically generates the path directory and uses the path as [name]. Don’t abuse it, because the path of the entry entry affects the path of the CSS file output by the mini-CSS-extract-plugin.

module.exports = {
  entry: {
    main: "./src/index.js".'path/entry/print': "./src/print.js"
  },
  output: {
    filename: "[name].bundle.js".path: path.resolve(__dirname, "dist")}}Copy the code

The corresponding packing result is:

Value is a common character string

Value is a normal string is a normal path string, that is, the developer’s own code. Refer to the above examples, here is not repeated.

Value is the NPM module

The value can be the NPM module, which is packaged as a separate entry. Such as lodash.

module.exports = {
  entry: {
    main: "./src/index.js".vendor: "lodash"
  },
  output: {
    filename: "[name].bundle.js".path: path.resolve(__dirname, "dist")}}Copy the code

The corresponding packing result is:

Separate application and third-party library entries

module.exports = {
  entry: {
    main: './src/app.js'.vendor: './src/vendor.js'
  },
  output: {
    filename: '[name].bundle.js'}};Copy the code

This allows you to store necessary libraries or files in Vendor.js that are not frequently modified, and then bundle them into separate chunks so that browsers can cache them independently, reducing load times.

Array syntax

You can specify multiple files for a single entry using arrays. Normally, the files imported into an array are not interdependent, but for some reason they need to be packaged together, and eventually Webpack exports the module.exports of the entire module as the entry of the last module in the array.

module.exports = {
  entry: {
    main: ["./src/index.js".'./src/print.js']},output: {
    filename: "[name].bundle.js".path: path.resolve(__dirname, "dist")}}Copy the code

The output export

The Output attribute tells WebPack where to export the bundles it creates and how to name them, with a default value of./dist.

The basic configuration

module.exports = {
  output: {
    filename: 'bundle.js'.path: path.resolve(__dirname, "dist")}}Copy the code

Filename: indicates the name of the configuration output file.

Path: The output path of the configuration file. It is an absolute path.

Multiple entry entry

module.exports = {
  output: {
    filename: '[name].bundle.js'.path: path.resolve(__dirname, "dist")}}Copy the code

Commonly used API

chunkFilename

ChunkFilename refers to the name of the chunk file that is not included in the entry but needs to be packed out. In general, this chunk file refers to a lazy module to load. Default to use [id].js or a value inferred from output.filename ([name] is pre-replaced with [id] or [id].) .

Webpack’s asynchronous modules (that is, modules imported via import()) have no name by default, and since there is no specified chunkFilename to display when the asynchronous module is loaded, Webpack replaces [name] with the chunk file’s [ID], an incrementing ID number. The [name] placeholder in webpack’s chunkFilename can be set by importing (/*webpackChunkName: “test123″*/ ‘index.js’).

filename

Filename is used to set the name of the output bundle. The bundle will be written to the directory specified by the output.path option.

Ordinary string

If the value of filname is a plain string, the file with the fixed name will be output. If filename is a path string, the file with the path will be output.

module.exports = {
  context: path.resolve(__dirname, 'src'),
  entry: {
    main: "./index.js"
  },
  output: {
    filename: "bundle.js".path: path.resolve(__dirname, "dist")}}Copy the code

Or the path string:

module.exports = {
  context: path.resolve(__dirname, 'src'),
  entry: {
    main: "./index.js"
  },
  output: {
    filename: "js/bundle.js".path: path.resolve(__dirname, "dist")}}Copy the code

Placeholder string

In webPack configurations, developers mostly use the form of placeholders because they are built flexibly. Common placeholders are as follows:

  • [name]: The name of the module, namely the key value of the entry (main, index, home, app, etc.).
  • [id]: module identifier, the internal chunk ID generated during webpack packaging, an incremented ID number.
  • [hash]: Hash of the module identifier.
  • [chunkhash]: Hash of chunk content.

The length of [hash] and [chunkhash] can be specified using [hash:16] (default is 20), or configured globally with output.hashDigestLength.

[hash] : Is the hash value of the entire project, which is calculated from the content compiled each time. Modifying the file will change the hash value of the entire project. Many resources are packaged in a project, but [hash] makes all resources use the same hash. If I change only one file, then packaging will change the hash value of all files, will change the hash value of files that have not been modified, and will invalidate the hash value of files that have not been modified in the browser cache, so the [hash] is affected by all the code, and will change whenever the content changes. Therefore, [Hash] does not provide persistent caching of static resources on browsers, and [Hash] can be used in development environments, not production environments.

[chunkhash] : the dependency file is parsed according to different entry files, corresponding chunks are constructed, and corresponding chunkhash is generated. If the content of an entry file changes on the dependency graph created by an entry file, then the chunkhash of the corresponding entry file will change, otherwise the chunkhash will not change, so [Chunkhash] is affected by the content of its chunk. As long as the content of the chunk changes, [Chunkhash] will change. Therefore, the common library is generally separated from other files in the project, and the common library code is split together for packaging, because the common library code changes less, so that the long-term cache of the common library can be realized.

[contenthash] : Another problem with using chunkhash is that when a JS file introduces a CSS file (import ‘xxx.css’), the chunkhash value is the same after the package is built, so if you change the contents of the JS file, even if the CSS file contents are not changed, The chunkhash of the CSS file associated with this JS will also change, invalidating the cache of the unchanged CSS file. In this case, we can use the mini-CSs-extract-plugin to extract CSS from the JS file and use contenthash to solve the problem.

path

Path is used to specify the directory where the final output of the WebPack build will be, and must be an absolute path.

publicPath

Webpack provides a very useful configuration that helps you specify a base path for all resources in your project, which is called a publicPath, publicPath. The basic path of all resources mentioned here refers to a basic path when CSS, JS, images and other resources are applied in the project. This basic path should be used in conjunction with the specified path of specific resources. Therefore, the access path of packaged resources can be expressed as follows:

Static resource access path = output.publicPath+ Resource loader or plug-in configuration path.

PublicPath is generally used to handle the resource access path when static resources are deployed to the CDN.

mode

Mode indicates the current environment of Webpack and the configuration of different environments. The default is production.

module.exports = {
  mode: 'production'
};
Copy the code

Different built-in plug-ins will be called inside WebPack to process files in different environments.

  • development: Development environment. Process.env.node_env is set to development and NamedChunksPlugin and NamedModulesPlugin are enabled.
  • production: Production environment. Will process. The env. NODE_ENV set to production, FlagDependencyUsagePlugin FlagIncludedChunksPlugin, opening ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin, UglifyJsPlugin. In production, WebPack automatically calls UglifyJsPlugin to obfuscate the code and optimize the packaged files.

loader

Loader is the module loader of Webpack. Webpack regards all resources (JS, CSS, images, etc.) as modules. However, Webpack only supports loading JS and JSON modules. While preprocessing files when importing or loading modules, Loaders handle file-level resources.

The use of the loader

There are three ways to use a Loader in Webpack:

  • Configuration (recommended) : Configure the loader in the webpack.config.js file.
  • Inline (not recommended) : Specifies the corresponding loader displayed in each import statement.
  • CLI (not recommended) : Specify loader in shell command.

Configuration mode

In Webpack, configure multiple loaders using module.rules. The following is an example:

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

Inline mode

You can specify a loader in an import statement or other import equivalent. Use the * *! ** Divides the loader, and each part of the loader is parsed relative to the current directory.

import Styles from 'style-loader! css-loader? modules! ./normal.css';
Copy the code

CLI way

Use the Loader on the CLI

webpack --module-bind 'css=style-loader! css-loader'
Copy the code

The characteristics of the loader

  • Loader supports chain transfer. The loader passes the processing result of the previous loader to the next loader for processing. A set of Loaders will execute in the opposite order defined, from bottom to top, or from right to left, in terms of space.
  • The Loader can be synchronous or asynchronous.
  • Loader runs in Node.js and can perform any operation possible.
  • Loader receives query parameters and transmits the configuration to loader.
  • The Loader can also be configured using the Options object.

The commonly used loader

babel-loader

In daily development, many people will use ES6, 7,8 or higher JS code, but the browser support for these syntax is not particularly friendly, so in order to enable the new syntax to run smoothly in the browser, you need to use Babel to convert the JS syntax into ES5 and other browser support syntax. Simply importing Babel manually would have been cumbersome and would have resulted in too large a file, so use WebPack to call Babel through babel-loader to do this transformation at packaging time.

The installation

npm i @babel-core babel-loader @babel/preset-env --save-dev
Copy the code

@babel-core is the core package of the Babel compilation library, which is responsible for parsing code. @babel/preset-env is a compilation rule for Babel, and the @babel/preset-env package tells Babel what transcoding specification to use to compile JS code.

usage

module: {
    rules: [{test: /.js$/,
            exclude: /node_modules/,
            use:{
                loader: 'babel-loader'.options: {
                    cacheDirectory: true.presets: ['@babel/preset-env'}}}]}Copy the code

The presets in options are used to configure the presets of the Babel, the encoding rules of the Babel. This allows Babel to translate ES6 code.

  • Case where babel-Loader is not used:

  • The case with babel-loader:

In contrast, it is clear that babel-Loader has converted ES6 const and arrow functions into ES5 syntax.

Other Configuration Items

  • CacheDirectory: Used to set the cache of Babel compilation results. If the file is not modified the next time the Babel is compiled, the cache will be read directly by Babel to improve Babel compilation speed. The default value is false. If set to true or null, babel-loader will use the default directory (node_modules/. Cache /babel-loader) to cache compilation results. If node_modules is not found in any root directory, It will degrade back to the default temporary file directory of the operating system. Or you can manually specify a cached directory yourself. If set to false, compilation results are not cached.

  • CacheIdentifier: The default is a string consisting of @babel/core version number, babel-loader version number, the contents of the.babelrc file (if present), and the value of the environment variable BABEL_ENV (if not degraded to NODE_ENV). You can set it to a custom value to enforce cache invalidation after identifier changes.

  • CacheCompression: The default value is true. When this value is set, each Babel Transform output is compressed using Gzip.

The advanced

Babel only interprets new syntax by default, such as arrow functions, lets, const, class, etc. New apis like Promise, Map, set, etc., will not be translated.

In order for our code to support ES6, we need to use @babel/ Polyfill. Polyfill is a SHIm for an ES6 environment. In fact, @babel/ Polyfill simply wraps core-JS and ReGenerator Runtime. Using @babel/ Polyfill will introduce the entire ES6 environment into your code. @babel/polyfill is deprecated after Babel >= 7.4.0.

npm install --save @babel/polyfill
Copy the code

The first way to use it is directly on the page:

import '@babel/polyfill'
Copy the code

But using @babel/polyfill directly has two problems:

1. @babel/ Polyfill makes the code very redundant and leads to too big a package, because Babel redefines the related function directly, rather than calls to existing functions, for each higher-level version of JS syntax transformation.

  • Introduction: before

  • After the introduction of:

To fix this, we can add the useBuiltIns parameter when configuring @babel/preset-env.

module: {
    rules: [{test: /.js$/,
            exclude: /node_modules/,
            use:{
                loader: 'babel-loader'.options: {
                    cacheDirectory: true.presets: [['@babel/preset-env', {
                        useBuiltIns: 'usage'}]}}}]}Copy the code

The useBuiltIns parameter supports three values:

  • entry: Only one @babel/polyfill is supported. Multiple references throw an error.
  • usage: will only be referenced in files using the ES6 API.
  • false: The default, which will introduce @babel/polyfill as a whole.

2. @babel/polyfill will pollute the global environment because new apis are introduced into the global environment by @babel/polyfill.

To solve this problem we introduced @babel/plugin-transform-runtime and @babel/runtime, @babel/runtime-corejs2 and @babel/runtime-corejs3.

Babel/Runtime: Polyfill suite provided by Babel, consisting of core-JS and Regenerator. The @babel/ Runtime is a collection of helper functions that ES6 transcoding requires, such as _extend.

@babel/ plugin-transform-Runtime: Transform-Runtime can automatically inject the polyfill module from @babel/ Runtime into the corresponding file.

module: {
    rules: [{test: /.js$/,
            exclude: /node_modules/,
            use:{
                loader: 'babel-loader'.options: {
                    cacheDirectory: true.presets: [['@babel/preset-env', {
                        useBuiltIns: 'usage'
                    }]],
                    "plugins": [["@babel/plugin-transform-runtime",
                            {
                                "absoluteRuntime": false."corejs": 2."helpers": true."regenerator": true."useESModules": false}]}}}]}Copy the code

The corejs option needs to be configured in the @babel/ plugin-transform-Runtime configuration, which takes three parameters:

  • falseInstall @babel/ Runtime.
  • 2: install @babel/ Runtime-corejs2
  • 3: install @babel/ Runtime-corejs3

Once you have configured @babel/plugin-transform-runtime, you can delete all @babel/polyfill because

Babel/plugin-transform-Runtime has already been processed for ES6 code.

The last

The configuration of Babel in the babel-loader configuration item can be written separately to the. Babelrc configuration file for maintenance. Note that the cacheDirectory parameter is a babel-loader configuration item, not a Babel configuration item.

Babelrc:

{
    "presets": ["@babel/preset-env"]."plugins": [["@babel/plugin-transform-runtime",
            {
                "absoluteRuntime": false."corejs": 2."helpers": true."regenerator": true."useESModules": false}}]]Copy the code

css-loader

Css-loader is the loader that Webpack uses to process the CSS in a project. It handles @import and URL () (images from CSS are imported, and urL-loader /file-loader is also required to process images). Typically used to deal with importing another CSS file via @import in one CSS file, or importing a CSS file via import/require in a JS file, csS-loader packages styles into bundle. JS, but does not insert CSS into HTML.

The installation

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

usage

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

Typically, CSS-loader and style-loader are used together.

Configuration items

  • Url: The default is true. Enable/disable url/image-set parsing. Controls the parsing of the URL () function. Absolute path urls are not parsed.

  • Import: The default is true. Enable/disable @import parsing, and the url of the absolute path in @import is moved to the runtime for processing.

  • Modules: The default value is false. Enabling/disabling the CSS module specification, set to False, improves performance because CSS Modules features are avoided.

  • ImportLoaders: Sets the number of loaders to be used before CSS-loader processes @import resource files. Such as:

module.exports = {
  module: {
    rules: [{test: /\.less$/,
        use: [
          {
            loader: 'style-loader'
          },
          {
            loader: 'css-loader'.options: {
              importLoaders: 1}},'postcss-loader'.'less-loader'}]}}Copy the code
// a.less
body {
    font-size: 14px; } / /b.less
body {
    background-color: #f00;
}
// index.less
@import "./a.less";
@import "./b.less";

body {
    color: #0f0;
}
Copy the code

When csS-loader processes the index.less file, the @import statement is executed with the value importLoaders set to 1. Therefore, a.less and B. less are submitted to postCSS-Loader first, not to less-Loader. If the value is set to 2, The a.less and B. less files are submitted to postCSs-loader and less-loader for processing. If importLoaders is not set or is set to 0, a.less and B. less are not processed by postCSs-loader and less-loader. Therefore, the purpose of the importLoaders setting is to allow @import files to be processed by the relevant loader.

style-loader

Style-loader is used to insert CSS into AN HTML file with the

The installation

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

usage

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

Configuration items

  • InjectType: Type string, default styleTag, used to set how to insert style into the DOM.

  • Attributes: Type Object, default value {}. Use to add custom attributes to the inserted tag.

  • Insert: type string/function, default value head. Use to insert a label at the specified position. By default, style-loader adds a

  • EsModule: Type Boolean, default true. In general, style-loader uses ES modules syntax to generate JS modules.

  • Modules: The type is Object. The default value is undefined. This parameter is used to configure the CSS module.

less-loader

Webpack compiles less to CSS using less-loader.

The installation

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

usage

module: {
    rules: [{test: /\.less$/,
            loader: 'less-loader'}}]Copy the code

file-loader

File-loader parses import/require() (also handles background URL () in CSS) into urls and outputs the file to the directory specified by output and returns the public URL of the file. Resources processed by file-loader are automatically replaced with public urls in other files. By default, the filename of the generated file is the hash value generated from the file content plus the extension of the original file. File-loader does nothing to the contents of the file. File-loader is typically used to process static resources such as images and fonts.

The installation

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

usage

module: {
    rules: [{test: /\.(png|jpe? g|gif)$/,
            use: [
              {
                loader: 'file-loader'.options: {
                    name: '[name].[ext]'.outputpath: 'images'}}]}Copy the code

Configuration items

  • name: The default value is [contenthash].[ext], which is used to customize the file name. The value can be a string or a function.
  • context: Default is webpack.config.js context, used to configure the custom file context.
  • publicPath: Used to configure a custom public publishing directory for files. The value can be a string or function. The default value is webpack. outputPath + outputPath.
  • outputPath: used to configure a custom output directory for files. The value can be a string or a function. Its path is set relative to the output directory of WebPack.
  • emitFile: The default value is true. If set to false, only the public URL is returned, but the corresponding file is not generated.

Difference between outputPath and publicPath

OutputPath simply tells WebPack where to output the generated results, while publicPath is the value of the URL used to embed the resource in the CSS, HTML file.

url-loader

Url-loader is used to convert files to Base64 encoded URIs. The url-loader function is similar to that of file-loader, except that the url-loader can set a limit value to determine whether to return a common URL path like file-loader, or directly encode the image in Base64 and write it to the corresponding path. Returns a Base64-encoded DataURI when the file size in bytes is less than the specified limit. Files converted to dataURIs can be accessed directly, reducing the number of HTTP requests and improving page performance. The disadvantage is that files less than the limit setting will be added to the file by base64 DataURI, which will increase the file size and reduce page loading performance.

The installation

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

usage

module: {
    rules: [{test: /\.(png|jpg|gif)$/,
            use: [
                {
                    loader: 'url-loader'.options: {
                        limit: 8192.fallback: {
                            loader: 'file-loader'.options: {
                                name: '[name].[ext]'.outputPath: 'images'.emitFile: true}}}}]}]}Copy the code

Configuration items

  • limitIf the file size is greater than or equal to this value, file-loader is used for processing by default and all query parameters are passed to it.
  • mimetype: Sets the MIME type of the file. If not specified, the file extension is used to find the corresponding MIME type.
  • fallback: Indicates the loader to be loaded when the number of files to be loaded by url-loader exceeds the limit.

plugins

Plug-ins are designed to extend the functionality of WebPack and perform related tasks throughout the lifecycle of the build process.

Commonly used the plugin

html-webpack-plugin

The html-webpack-plugin is used to generate an HTML file and automatically insert the resulting static file into it. By default, it creates an index. HTML file in the output.path directory and inserts a script tag into the file with a SRC of output.filename.

The installation

npm i --save-dev html-webpack-plugin
Copy the code

usage

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: 'index.js'.output: {
    path: __dirname + '/dist'.filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
        template: './index.html'.filename: 'index.html'}})]Copy the code

For multi-entry projects, configure several more HTML-webpack-plugins. As follows:

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: {
    index: 'index.js'.print: 'print.js'
  },
  output: {
    path: __dirname + '/dist'.filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
        template: './index.html'.filename: 'index.html'
    }),
    new HtmlWebpackPlugin({
        template: './print.html'.filename: 'print.html'}})]Copy the code

Configuration items

  • Title: is used to set the document. The title, in the index. In HTML using the < % = htmlWebpackPlugin. Options. The title % > custom page title.

  • Filename: Used to set the name of the HTML file to be generated. The default value is index. HTML. You can customize the file name or write the file path. The root path of the generated file is the output.path directory, and the JS file automatically imported is changed to the corresponding path to ensure correct import.

  • Template: The template for the HTML file to be generated. Is the path to the file, relative to the path to webpack.config.js, and affected by the webpack context. The path is the path to the context +template path.

  • Inject: Specifies where static resources packed by Webpack will be inserted into HTML. JS files will be inserted at the bottom of body when it is true or body, JS files will be inserted into tags when it is head.

  • {viewport: ‘width=device-width, initial-scale=1, shrink-to-fit=no’}.

  • Minify: Compress HTML files. Typically, compression is enabled in a build environment. A value of

    {
        collapseWhitespace:true.removeComments:true.removeRedundantAttributes:true.removeScriptTypeAttributes:true.removeStyleLinkTypeAttributes:true.useShortDoctype:true
    }
    Copy the code
  • Hash: Setting this to true will add the hash value to the end of the static resource file in the generated HTML file.

  • cache: The default value is true, which specifies whether files should be cached or not.
  • chunks: Usually used to specify that each HTML file imports only its corresponding JS file when packaging multi-entry projects, preventing unnecessary files from being imported into HTML files. The value is an array, and the elements of the array are those of the entry configuration itemkeyValue instead of the file name of the entry configuration.

clean-webpack-plugin

This plug-in is used to clear the previously packed files on the next package, which is the folder set by outpu.path.

The installation

npm i clean-webpack-plugin --save-dev
Copy the code

usage

const CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = {
  entry: 'index.js'.output: {
    path: __dirname + '/dist'.filename: 'index_bundle.js'
  },
  plugins: [
    new CleanWebpackPlugin()
  ]
}
Copy the code

mini-css-extract-plugin

This plug-in extracts CSS into a separate file, reducing the packaging size of webPack. It creates a CSS file for each JS file that contains CSS and supports on-demand loading of CSS and sourceMaps. Webpack single-entry configuration packs the extracted CSS styles into a SINGLE CSS file, while multi-entry configuration Webpack packs the extracted CSS styles into their own CSS files.

The installation

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

usage

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  plugins: [new MiniCssExtractPlugin()],
  module: {
    rules: [{test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],}]}}Copy the code

Configuration items

  • filename: Sets the file name of each output CSS, similar tooutput.filenameYou can use various hashes. use[name]When the placeholder configures filename,[name]Is the value that references the entry of the CSS.
  • chunkFilename: The file name used to set the non-entry chunk, similar tooutput.chunkFilename.
  • attributes: used to set<link>Attributes on the tag.
  • insert: Is inserted at the specified position<link>The label.

Loader configuration items

The Loader of mini-CSS-extract-Plugin has its own configuration items. As follows:

  • publicPath: The default value is webpackoutput.publicPathThe value of the. It is used to specify a custom public path for images, files, and other resources in the extracted CSS file. Most of them are CDN paths.
  • esModule: The default value is true. Sets whether to use ES modules syntax.
  • modules: Used to configure the CSS modules.

copy-webpack-plugin

Use to copy a single file or entire directory to the build directory.

The installation

npm i copy-webpack-plugin --save-dev
Copy the code

usage

A new version of the copy-webpack-plugin requires the Patterns field.

const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
  plugins: [
      new CopyWebpackPlugin([
          patterns: [
            { from: "source".to: "dest" },
            { from: "other".to: "public"},]])]}Copy the code

Configuration items

  • from: Resource of the file to be copied. It can be a path or a file path matching the glob pattern.
  • to: Specifies the path to be generated for the copied file resource.
  • context: is used to configure a path. Webpack uses context as the root directory when looking for files in relative paths.
  • filter: Filters the resources to be copied.
  • toType: sets whether files or directories are copied.
  • transform: You can modify the file before it is written to webpack.
  • cacheTransform: Configures the cache.

webpack-dev-server

Before we build the code and deploy it to production, we need a local environment to run the code we’ve developed, access the static files packaged with WebPack, and use it to invoke the front-end code. Webpack-dev-server is an official tool provided by Webpack, based on the current Webpack configuration to quickly start a static service, each change of the code saved can be automatically packaged, packaged output file only exists in memory, support automatic page refresh.

The installation

npm i webpack-dev-server --save-dev
Copy the code

Start the

Use NPM scripts
"scripts": {
  "dev": "webpack-dev-server --config webpack.config.js"
}
npm run dev
# Using the CLI
node_modules/.bin/webpack-dev-server
Copy the code

configuration

module.exports = {
  entry: {
    index: 'index.js'.print: 'print.js'
  },
  output: {
    path: __dirname + '/dist'.filename: 'index_bundle.js'
  },
  devServer: {
	contentBase: path.join(__dirname, 'dist'),
    port: 8080}}Copy the code

Configuration items

  • contentBase: Provides the directory address of static files. You are advised to use an absolute path. By default, it will use the current working directory to serve the content.
  • compress: Set to true to enable gzip compression for static files. The –compress parameter needs to be added through the command line.
  • hot: Used to enable the Hot Module Replacement (HMR) function of Webpack. To enable HMR completely, the need to configure the webpack. HotModuleReplacementPlugin, but if the NPM scripts enable webpack – dev – server, added – hot parameters at the same time, The webpack HotModuleReplacementPlugin will automatically be added. When HMR is enabled, WebPack does not allow the use of [contenthash] for JS files in the output entry.
  • inline: used to setHMRThe model. The default value is true. Set to true to inline mode. If set to false, iframe mode is used. The IFrame pattern is to embed an IFrame in a web page and inject our own code into the iframe. Inline mode is recommended.
  • open: webpack-dev-server automatically opens the browser after it starts. The default value is false.
  • port: port number monitored by webpack-dev-server.
  • public: Specifies the domain name of the static service. The default value ishttp://localhost:8080/When you use Nginx as a reverse proxy, this configuration should specify the service domain name used by the Nginx configuration.
  • publicPath: Specifies the path through which the built static file is accessed in the browser. The default value is/. For example, for a built file bundle.js, the full access path ishttp://localhost:8080/bundle.jsBut if you set itpublicPath: 'asstes/', then the complete access path ishttp://localhost:8080/assets/bundle.js. You can use the entire URL for thispublicPathValues, such aspublicPath: 'http://localhost:8080/assets/'. If you use HMR, set itpublicPathYou have to use the full URL. Recommendations will bedevServer.publicPathoutput.publicPathThe values of remain consistent.
  • proxy: Used to set the proxy. Generally used to solve cross-domain problems.
module.exports = {
  entry: {
    index: 'index.js'.print: 'print.js'
  },
  output: {
    path: __dirname + '/dist'.filename: 'index_bundle.js'
  },
  devServer: {
	proxy: {
        '/api': {
            // Proxy to port 3000 when matching API in path
            / / the http://localhost:8080/api/123 proxy to http://localhost:3000/api/123
            target: 'http://localhost: 3000'.// Rewrite the path
            / / the http://localhost:8080/api/123 proxy to http://localhost:3000/123
            pathRewrite: {
                '^/api': ' '
            }
        }
    }
  }
}
Copy the code
  • Before: Used to define additional middleware in webpack-dev-server, called before all middleware within Webpack-dev-server is executed. It can be used to intercept partial requests that return specific content, or to implement simple data Mock services.

    before(app){
      app.get('/some/path'.function(req, res) {// Returns custom JSON data when accessing the /some/path path
        res.json({ custom: 'response'})})}Copy the code
  • After: Used to define additional middleware in webpack-dev-server, called after all middleware execution within webpack-dev-server. Rarely used, usually for printing logs or doing extra processing.

externals

Externals means an external extension of Webpack. The externals option provides a way to exclude dependencies from the bundle output of webPack, preventing packages from being packaged into the bundle and instead fetching these extended dependencies externally at runtime, reducing the size of the package. With externals, webpack does not handle these dependency libraries, but can still be accessed globally in code via CMD, AMD, Window /global.

For example, load jQuery from the CDN instead of packing it into the final bundle. The configuration is as follows:

module.exports = {
  externals: {
    jquery: 'jQuery'}};Copy the code
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
Copy the code
import $ from 'jquery'
Copy the code

You can also remove the NPM package of jquery installed in the project, or do not need NPM install jquery-s.

Note: In the externals configuration object, the attribute name is the module name, and the attribute value is the variable name. Where jquery stands for the real jquery module name, jquery stands for the global variable name, which can be defined arbitrarily, such as $.

Externals Specifies the supported module context

Externals supports the following module context:

  • rootThe Library can be accessed through a global variable, such as the script tag.
  • CommonJSLibrary can be accessed as a CommonJS module.
  • CommonJS2CommonJS is the same as CommonJS but exports module.exports.default.
  • amd: Similar to CommonJS, but using the AMD module scheme.
externals : {
  lodash : {
    commonjs: "lodash".amd: "lodash".root: "_"}}Copy the code

This configuration means that the loDash library is accessed through LoDash in the AMD and CommonJS module scenarios and the global variable _ in the browser.

How to set externals for different environments

1. If it is running in a Node environment, add the prefix CommonJS or CommonJS2 to externals.

externals: {
    jquery: 'commonjs jQuery'
}
Copy the code

2. If running in a browser, there is no need to add a prefix, the default is global.

externals: {
    jquery: 'jQuery'
}
Copy the code

The module parse

Resolver is a library that finds absolute paths to modules. A module can be referenced by another module as a dependent module. Such as:

import foo from '.. /foo'
require('bar')
Copy the code

Resolver helps WebPack find the module code that needs to be imported into the bundle from each import/require statement. Webpack uses enhanced-resolve to resolve file paths.

Parsing rules

With enhanced- Resolve, WebPack can resolve three file paths:

  • An absolute path. Because you already have the absolute path to the file, no further parsing is required.
  • Relative paths. Given relative paths in import/require, Webpack concatenates context paths to generate absolute paths for modules.
  • The module path. Import the module name, first look for the current file directory, if not found, will continue to the parent directory, one by one, until the project root directory node_modules, if not found, will throw an error.

The resolve option

The Resolve option sets how modules are resolved, and WebPack provides a reasonable default configuration.

alias

Configure the alias of the module path. When import/require is used, the alias of the module path is used to make the introduction of modules easier. At the same time, webpack can retrieve modules more quickly and accurately, without recursively resolving dependencies, and improve the construction speed. The alias has a higher priority than that of other modules. Such as:

const path = require('path')
module.exports = {
    resolve: {
        alias: {
            '@src': path.resolve(__dirname, 'src/')}}}Copy the code
import foo from '@src/foo/index'
Copy the code

If you want to use exact matching, you can use $:

const path = require('path')
module.exports = {
    resolve: {
        alias: {
            '@src$': path.resolve(__dirname, 'src/')}}}Copy the code

enforceExtension

Specifies whether to force a file extension when importing/requiring. The default is false. If true, import/require files without the extension will not be allowed.

extensions

An array of strings whose elements are file extensions. Webpack tries to resolve the extensions in order of the array elements. Using this option overrides the default configuration, which means that WebPack will no longer attempt to resolve modules using the default extension. If there are multiple files with the same name but with different extensions, WebPack will parse the extension file listed at the top of the array and skip the rest of the suffixes.

module.exports = {
  resolve: {
    extensions: ['.css'.'.less'.'.js'.'.json'],}};Copy the code

Modules can be imported without an extension:

import foo from './foo/index'
Copy the code

modules

Tells WebPack which directory to search for when parsing modules. Can be an absolute path or a relative path. The default value of resolve.modules is node_modules. This configuration is not normally adjusted. Import /require using absolute paths will only be searched in the given directory.

resolve: {
  modules: ['node_modules']}Copy the code

Optimization

Optimizations for Webpack.

minimize

The default value is true. Tell WebPack to compress bundles using the TerserPlugin or other plug-in defined in Optimization.minimizer. Compressed even if mode is in development mode.

module.exports = {
  optimization: {
    minimize: false}};Copy the code

minimizer

The developer configures one or more instances of TerserPlugin to override the default compression tool. The default configuration of WebPack is generally used.

const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin({
        cache: true.parallel: true.sourceMap: true.// If source-map is used in production, it must be set to true
        terserOptions: {
          // https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions}}),],}};Copy the code

splitChunks

After WebPack4, optimization.splitchunks are used instead of commonsChunkPlugin to split and package modules, separate the code into different bundles, and then load these files on demand or in parallel to reasonably control the loading of resources. Reduce packing volume and speed.

By default, it only affects chunks that are loaded on demand. Webpack will automatically split chunks in the following scenarios:

  • The new chunk is shared by multiple chunks, or it comes from the node_modules folder.
  • The new chunk size is greater than 20KB (before min+gz).
  • When chunk is loaded on demand, the maximum number of concurrent requests is less than or equal to 30.
  • The maximum number of parallel requests for initial page loading is less than or equal to 30.

The basic use

module.exports = {
    optimization: {
        splitChunks: {
            chunks: 'async'.minSize: 30000.maxSize: 0.minChunks: 1.maxAsyncRequests: 6.maxInitialRequests: 4.automaticNameDelimiter: '~'.cacheGroups: {
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10,},default: {
                    minChunks: 2.priority: -20.reuseExistingChunk: true,}}}}}Copy the code

Configuration items

chunks

The values are all, initial, async, and the default is async.

  • Initial: the original split module. The principle is that there is a split in the case of common. In this mode, dynamically imported code will follow the split logic anyway (it can only be dynamically imported if it is split into separate files). For modules introduced synchronously, if many are in common, they are removed.

  • Async: Modules loaded asynchronously, that is, modules loaded dynamically on demand are split. Such as:

    import(/* webpackChunkName: "a" */ './a.js').then(a= > {
      console.log(a)
    })
    Copy the code
  • All: contains the preceding two scenarios.

minSize

Minimum volume of the module to be removed before compression, in bytes. Default value: 20000. Only modules larger than 20000 bytes will be removed.

maxSize

The file size generated by the package of the removed module cannot exceed the maxSize value. If the file size exceeds the maxSize value, it should be segmented, extracted and packaged into a new file. The unit is byte. The default value is 0, indicating that the size is not limited.

minChunks

Indicates the number of times the module was referenced before it was removed. The default is 1. Code that exceeds the number of minChunks is removed.

maxAsyncRequests

Represents the maximum number of parallel requests loaded on demand. The default value is 6. If the number of chunks that the bundle needs to load asynchronously is greater than or equal to six, the bundle will not be split because the increase in the number of requests is not worth the loss. Generally, use the default value.

maxInitialRequests

Indicates the maximum number of parallel requests that can be initialized. The default value is 4. If the number of chunk requests for the split import file is greater than or equal to 4, the split will not be performed. The gain is not worth the loss due to the increase in the number of requests. Generally, use the default value.

automaticNameDelimiter

A connector to specify the generated module name.

name

Specifies the name of the module to be removed. The default value is true, indicating that the file name is automatically generated.

cacheGroups

Used to define the cache group that the chunks belong to. This section describes how to remove modules. Each of these items represents a solution for removing the module. CacheGroups can inherit/override any option in splitChunks.* and have its own options such as Test, Priority, reuseExistingChunk, Enforce, etc. CacheGroups has two default groups, vendors, which package all modules from node_modules. The other is Default, which packages modules shared by more than two chunks.

  • test: Matches the resource path or name of the module to be removed, and the modules that meet the criteria are assigned to the group. A value is a function or regular expression. Omitting it will select all modules.
  • priority: Priority of the cacheGroups scheme used. A larger number indicates a higher priority. The default value is 0.
  • reuseExistingChunk: indicates whether to reuse the existing chunk. The value to false/true. When set to true, if the module to be extracted already exists in the js file generated by packaging, the module will be reused instead of being packaged as a new chunk.
  • enforce: Whether to ignore the options configured in outer splitChunks. The value to false/true. If this parameter is set to true, configuration items such as minSize, minChunks, and maxSize are ignored and customized by cacheGroups are used.

devtool

Controls how WebPack generates the source-map. You can use the SourceMapDevToolPlugin for more fine-grained control of source-Map. Devtool can be a combination of source-map, eval, inline, cheap, module, and hidden. Each of these six keywords represents a feature.

  • eval//# sourceURL is added to the end of each module to correlate the relationship between modules before and after processing. Independent.map files are not generated.
  • source-mapAfter the bundle is packaged, a separate.map file is generated and appended to the end of the bundle filesourceMappingURLIf you specify the path of the map file, the corresponding. Map file will be generated if the independent CSS file is extracted.
  • inline: does not generate a separate.map file, but appends the sourcemap content to the end of the bundle as a DataURI.
  • hiddenSource map information is not indicated at the end of the bundle file, but sourcemap is still generated so that the browser does not automatically load the sourcemap, preventing the production environment from publishing sourcemap information.
  • cheapThe generated sourcemap contains no column information and no SourcemAP information for the Loader. The generated Sourcemap maps the source code processed by the Loader.
  • module: The generated sourcemap contains loader sourcemap information, that is, the generated Sourcemap maps the source code before loader processing.

The development environment

In the development environment we set devtool to eval-cheap-module-source-map. The cheap keyword generates a more detailed sourcemap with line information. The module contains the sourcemap information generated by libraries such as Babel. At the same time, the generated bundle files are small in size, and the eval keyword makes packaging and building very fast. Eval keyword does not generate corresponding independent.map files.

The production environment

Setting devtool to hidden-source-map in production generates the detailed sourcemap, but does not expose the sourcemap.

DllPlugin and DllRefrencePlugin

The DllPlugin and DllRefrencePlugin are used to break up modules and greatly speed up builds. DllRefrencePlugin packages the modules that are not constantly changing into a bundle and generates a manifest.json file. DllRefrencePlugin uses the manifest.json file to map the name of the dependent module to the module ID. Require the corresponding module via the built-in __webpack__require__ function when needed.

Why DllPlugin and DllRefrencePlugin

In general, our code can be easily separated into business code and third-party libraries. If left untreated, all the code needs to be rebuilt at each build, which can take a lot of time. Then in most cases, a lot of third-party library code does not change (unless it’s version), then you can use the DLL, the reusability of higher third-party modules packaged in the dynamic link library, in the case of not to upgrade the library and dynamic library do not need to repack, each building only repackaged business code.

DllPlugin configuration items

  • contextJson file, which defaults to the value of webpack.context.
  • format: format manifest.json, default is false. If set to true, the manifest.json file will be formatted.
  • name: The name of the exposed dynamic link library global variable, which must be the same as output.library.
  • pathJson: The absolute path to the manifest.json file.
  • entryOnly(rarely used) : The default value is true, if true, only the entry is exposed.DllPlugin is recommended only in entryOnly: trueOtherwise tree Shaking in the DLL won’t work because all exports are available.
  • type: The type of bundle that a DLL packages.

DllRefrencePlugin configuration items

  • contextJson file, default to the value of webpack.context.
  • extensions: an extension used to resolve modules in a DLL bundle.
  • manifest: Used to import the MANIFEST. Json file generated by a DLL.

usage

When using DLLS, the build process is divided into two parts: the build of the Dll and the webpack main build. So you need to use two configuration files: webpack.config.js and webpack.dll.config.js. DLL bundles are first built using webpack.dll.config.js, and then packaged using the webPack main build.

webpack.dll.config.js

const path = require('path')
module.exports = {
    entry: {
        jquery: ['jquery']},output: {
        filename: '[name].dll.js'.path: path.resolve(__dirname, './dist/dll'),
        // The global variable name of the related DLL file
        library: '[name]_dll'
    },
    plugins: [
        new webpack.DllPlugin({
            // The global variable name of the dynamically linked library needs to be the same as that in output.library
      		// The value of this field is the value of the name field in the output manifest.json file
            name: '[name]_dll'.path: path.resolve(__dirname, 'dist'.'[name].manifest.json')]}})Copy the code

webpack.config.js

const path = require('path')
module.exports = {
    plugins: [
        new webpack.DllRefrencePlugin({
            manifest: require('./dist/jquery.manifest.json')]}})Copy the code

In the entry HTML file

Since the generated DLL exposes global functions, they need to be introduced in the HTML of the entry.

<body>
    <! -- DLL file -->
    <script src=".. /.. /dist/dll/jquery.dll.js" ></script>
</body>
Copy the code

webpack-chain

A chained API is used to modify the configuration of WebPack versions 2 to 4. Webpack-chain provides a chained or downstream API to create and modify webPack configurations, eliminating the need to maintain and modify a dead WebPack configuration object. The key part of the API can be referenced by a user-specified name. The current webpack configuration within vue-CLI is maintained through webpack-chain.

The installation

## npm
npm install --save-dev webpack-chain
## yarn
yarn add --dev webpack-chain
Copy the code

usage

const path = require('path')
// Imports the Webpack-chain module, which exports a single constructor for creating the WebPack configuration API
const Config = require('webpack-chain')
// Create a new configuration instance for a single constructor
const config = new Config()
// Change the configuration using the chained API
config
	// Modify entry configuration
	.entry('app')
	.add('src/index.js')
	// Return the upper instance object
	.end()
	// Modify the output configuration
	.output
	.path('dist')
	.filename('[name].bundle.js')

// Set the alias
config.resolve.alias
	.set('@src', path.resolve(__dirname, 'src'))

/ / use the loader
config.module
	.rule('lint')
	.include
	.add('src')
	.end()
	// Create a named rule
	.use('eslint')
	.loader('eslint-loader')
	.options({
    	rules: {
            semi: 'off'}})// Modify loader options
config.module
	.rule('compile')
	.use('babel')
	.tap(options= > {
    plugins: ['@babel/plugin-proposal-class-properties']})/ / use the plugin
// Note the use part, at this point, the plug-in instance cannot be generated by new
config
	.plugin('clean')
	.use(CleanPlugin, [['dist'] and {root: '/dir'}])

// Modify plugin parameters
config
	.plugin(name)
	.tap(args= > newArgs)

config
	.plugin('env')
	.tap(args= > [...args, 'ENV'])

// Modify plug-in initialization
config
	.plugin(name)
	.init((plugin, args) = > newPlugin(... args))// Use when for conditional configuration
config
	.when(process.env.NODE_ENV === 'production'.config= > config.plugin('minify').use(BabiliWebpackPlugin))
// Merge the configuration
config.merge({devtool: 'source-map'})

// Export configuration objects
module.exports = config.toConfig()
Copy the code

Use the toString() method to view the corresponding Webpack configuration generated by webpack-chain

config
    .module
    .rule('compile')
    .test(/\.js$/)
    .use('babel')
    .loader('babel-loader')
config.toString();
/** {module: {rules: [ /* config.module.rule('compile') */
            {
                test/\.js$/,
                use: [
                /* config.module.rule('compile').use('babel') */
                    {loader'babel-loader'}]}} */Copy the code

Overview of Webpack principle

The general process of Webpack: initialize parameters — > Start compiling — > Confirm entry — > Compile module — > Finish compiling module — > Output resources — > Output done

  • Initialization parameter: Reads and merges parameters from configuration files (default webpack.config.js) and shell statements to get the final parameters. This process also executes the plug-in instantiation statement new Plugin() in the configuration file.
  • Begin to compileInitialize the Compiler object with the parameters obtained in the previous step, load all configured plug-in plugins, and start compiling through the object’s run method. Compiler is responsible for listening to files and starting compilation.
  • Determine the entrance: Finds all entry files according to the entry in the configuration.
  • Compile the module: From the entry file, call the configured Loader to compile the module, find out the module that the module depends on, and then recurse this step until all the entry dependent files have been processed.
  • compileAfter the first four steps, you get the final result of compiling each module and the dependency diagram between them.
  • Output resources: Assemble chunks containing multiple modules one by one according to the dependency diagram between entries and modules, and convert each chunk into a separate file and add it to the output list. This is the last chance to modify the output content.
  • Output complete: After determining the output content, determine the output path and file name according to the configuration, and output the final file.