Webpack has always been a pain point for front-end engineers, because of its complexity, decentralization, loader, plugin and other third parties, our learning cost has risen sharply, so that we have been ambiguous about its configuration. Today, I will take you to thoroughly understand how to configure it, and get rid of the pain point that has bothered us for a long time. This article is mainly about the basic configuration of Webpack. The module chunk of Webpack, compilation stage process, output stage process, loader writing and handwriting plugin will be introduced in the subsequent articles. In order to avoid missing it, you can follow me or save my personal blog www.ngaiwe.com

1. What is Webpack?

WebPack can be viewed as a module baler: What it does is analyze the structure of your project, find JavaScript modules and other extension languages that browsers don’t run directly (Scss, TypeScript, etc.), and package them into a format that browsers can use. And with your various needs in the project, to achieve automatic processing, the liberation of our productivity

  • Code conversion: TypeScript to JavaScript and SCSS to CSS.
  • File optimization: compress JavaScript, CSS, HTML code, compress merged images, etc.
  • Code splitting: Extract common code from multiple pages, extract code that does not need to be executed on the first screen and load it asynchronously.
  • Module merge: In a modularized project, there will be many modules and files, and you need to build functionality to merge modules into a single file.
  • Auto refresh: Listen for changes to the local source code, and automatically rebuild and refresh the browser.
  • Code validation: Verifies compliance with specifications and unit tests before submitting code to the repository.
  • Automatic release: After updating the code, automatically build the online release code and transfer it to the release system.

2. Initialize the project

mkdir webpack-start
cd webpack-start
npm init
Copy the code

3. Core concepts of Webpack

  • Entry: Entry, the first step in the build that WebPack performs will start with Entry, which can be abstracted as input
  • Module: Module, in WebpacL everything is a Module, a Module corresponds to a file, Webpack will recursively find all dependent modules from the configuration Entry
  • Chunk: code blocks. A Chunk is composed of multiple modules for merging and splitting codes
  • Loader: module converter, used to convert the original content of a module into new content as required
  • Plugin: Extension Plugin that injects extension logic at specific points in the WebPack build process to change the build result and what you want to do
  • Output: Enter the result, go through a series of processing in Webpack and get the final desired code and then Output the result

When Webpack starts, it recursively resolves all modules that Entry depends on, starting from the Module configured in the Entry. When a Module is found, the system finds the corresponding conversion rule based on the configured Loader, converts the Module, and resolves the Module dependent on the current Module. These modules are grouped by Entry, and an Entry and all its dependent modules are assigned to a group called a Chunk. Finally, Webpack converts all chunks into files for output. Webpack executes the logic defined in the Plugin at appropriate times throughout the process.

1.Entry

Context is used to solve the problem that the configuration file and the entry file are not in the same layer structure. For example, if the configuration file is in config and the entry file is in the root directory, the configuration is as follows

module.exports = { context: path.join(__dirname, '.. '), // Find the root directory entry: './main.js' // the root directory entry file}Copy the code

The simplest single page (SPA)Entry Entry brings main.js in and begins parsing based on the modules referenced and dependent in main.js

module.exports = {
  entry: './main.js'
}
Copy the code

Multi-page (MPA)Entry Entry, to introduce multiple files, of course, the general is to read the specified folder in the Entry file, and then import

entry: {
  home: "./home.js",
  about: "./about.js",
  contact: "./contact.js"
}
Copy the code

For a single page (where a string or an array of strings is passed in), chunk is named main. For multiple pages (where an object is passed in), each key is the name of chunk, describing the chunk entry point

2.Output

Object tells webPack how to export, and where to export your bundles, assets, and anything else you package or load using WebPack

  • Path: The output directory corresponds to an absolute path

    path: path.resolve(__dirname, 'dist')
    Copy the code
  • Pathinfo: Boolean Default false tells WebPack to include comments about the contained module information in the bundle. It should not be used in production environments, but is useful for development environments

  • PublicPath: it is used to process static file paths in packaged files

  • Filename: Defines the name of each output bundle that will be written to the directory specified by the output.path option. For single Entry, filename is a static name

    filename: "bundle.js"
    Copy the code

    But in Webpack we create multiple bundles using code splitting, various plug-in plugins, or multiple Entry, so we should give each bundle a unique name

    filename: "[name].bundle.js"
    Copy the code

    Use the internal chunk ID

    filename: "[id].bundle.js"
    Copy the code

    Unique hash generation

    filename: "[name].[hash].bundle.js"
    Copy the code

    Use a hash based on the content of each chunk

    filename: "[chunkhash].bundle.js"
    Copy the code
3. The Module Module

The main configuration for different modules applied in the project is in Rules, which matches the array of requested Rules. These Rules can apply loader to modules or modify the parser

  • Module.noParse: Prevents webpack parsing from parsing files that match rules successfully and ignoring large libraries to optimize performance. Ignored files should not contain calls to import, require, and define

    module.exports = { module: { rules: [], noParse: Function (content) {return/jquery | lodash /. The test (content) / / ignore the jquery file parsing and compile directly packaging}}}Copy the code
  • Rules: Array of Rules that match the request when the module is created

    • Rule conditions: For example, if file A is imported to file B, resource is /B, and issuer is /A, the locations of the file when the requested file is imported are not real. The test/include/exclude/resource to match the resource, and issuer is only the issuer matching

    • The Test/include/exclude/resource/issuer usage and difference

      module.exports = {
          modules: {
              rules: [
                {
                  test: /\.js?$/,
                  include: [
                    path.resolve(__dirname, "app")
                  ],
                  exclude: [
                    path.resolve(__dirname, "app/demo")
                  ],
                  resource:{
                    test: /\.js?$/,
                    include: path.resolve(__dirname, "app"),
                    exclude: path.resolve(__dirname, "app/demo")
                  },
                  issuer: {
                    test: /\.js?$/,
                    include: path.resolve(__dirname, "app"),
                    exclude: path.resolve(__dirname, "app/demo")
                  }
                }
              ]
        }
      }
      Copy the code

      Test: provides a regular expression or an array of regular expressions. If the absolute path matches the regular expression, this condition is met

      Include: is a string or array of strings. Files in the specified directory must follow this rule

      Exclude: Exclude is also a string or an array of strings. Files in the specified directory do not follow this rule

      Resource: is an object wrapped around text/include/exclude, as if they were written separately

      Issuer: The rule is the same as resource, but it differs from the file to which the rule is applied and all dependent files imported by the file

    • ResourceQuery: same as resource, but for matching results ‘? ‘after the path argument, can call the resource text, etc

    • OneOf: applies only the first matching rule to the resource, usually combined with resourceQuery

      { test: /\.(png|jpe? g|gif|svg)$/, oneOf: [ { resourceQuery: /inline/, loader: 'url-loader' }, { loader: 'file-loader' } ] }Copy the code
      • path/to/foo.png? Inline: matches url-loader
      • path/to/foo.png? Other: matches file-loader
      • Path /to/foo. PNG: matches file-loader
    • UseEntry: Object contains the configuration file of each Loader

      {
        loader: "css-loader",
        options: {
          modules: true
        }
      }
      Copy the code

      Options are passed to the Loader

    • Use: is a collection of useEntry, and a loader is specified for each entry

      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 1
          }
        },
        {
          loader: 'less-loader',
          options: {
            noIeCompat: true
          }
        }
      ]
      Copy the code
4. Resolve parsing

Mainly used for how modules are parsed to provide default values for Webpack

  • Alias: object is mainly used to make import and require calls easier and to set the initial path

    module.exports = { alias: { Utilities: path.resolve(__dirname, 'src/utilities/'), Templates: Path.resolve (__dirname, 'SRC /templates/')}} import import Utility from '.. /.. /utilities/utility'; // Import Utility from 'Utilities ';Copy the code
  • EnforceExtension: Boolean The default is false, indicating that the references do not need an extension. When the enforceExtension is true, the references in import and require must have an extension

  • Extensions: Array Automatic parsing does not require an extension

    Extensions: [".js", ".json"] //.js and. Json do not require extensionsCopy the code
  • Modules: Array Directory to search for when webpack parses modules. It is usually used for priority search and custom modules in non-node_modules files

    Modules: [path.resolve(__dirname, "SRC "), "node_modules"] // Search SRC directory firstCopy the code
5.Loader

By using different loaders, Webpack can convert different files into JS files, such as CSS, ES6/7, JSX, etc., generally used in module use

module: {
  rules:[
      {
        test:/\.css$/,
        use:['style-loader','css-loader'],
        include:path.join(__dirname,'./src'),
        exclude:/node_modules/
      }
  ]      
}
Copy the code

For details about loader, you need to check the official documentation API of loader you want to introduce. Handwritten Loader will be introduced in the next article

6. The Plugin plug-in

Array extends WebPack, injecting extension logic at specific points in the WebPack build process to change the build result and what you want to do. See the official documentation of the plugin you introduced, and the handwritten plugin will be introduced in a subsequent article

7.webpack-dev-server

Webpack-dev-server can be used to quickly set up local services. See webpack-dev-server

8.Devtool

Devtool is mainly used to control the packaging quality and ease of debugging in the dev environment and speed of compilation

9.Watch

Webpack can monitoring file changes, when they will revised a recompile and HotModuleReplacementPlugin have similarities, monitoring file changes hot start

4. Configuration webpack

Webpack installation command

npm install webpack webpack-cli -D
Copy the code

Webpack.config.js

The specific plugin used

  • Clean-webpack-plugin: Used to clear the official API of the output directory before packaging
  • Html-webpack-plugin: Official API for automatically generating HTML and reference outputs for resources
  • Copy-webpack-plugin: Used to copy static resources, including unreferenced resource official apis
  • Uglifyjs-webpack-plugin: official API for compressing JS files to make output JS files smaller, faster to load, less traffic, and encryption function obfuscating code
  • Extract-text-webpack-plugin: Since CSS downloads and JS can be done in parallel, when an HTML file is large, we can extract the CSS separately and load the official API
const path = require('path'); const webpack = require('webpack'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin') // npm i extract-text-webpack-plugin@next // Const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin'); let cssExtract = new ExtractTextWebpackPlugin({ filename: 'css/css.css', allChunks: true }); let lessExtract = new ExtractTextWebpackPlugin('css/less.css'); let sassExtract = new ExtractTextWebpackPlugin('css/sass.css'); //let pages = ['index', 'base']; //let pages = ['index', 'base']; // pages = pages. Map (page => new HtmlWebpackPlugin({// template: './ SRC /index.html',// ` ${page}. HTML `, / / output HTML file name/title: ${page} ` `, / / chunks: [' common '${page} ` `], / / which code block in the output HTML files into / / the hash: // minify: {// removeAttributeQuotes: true //} //}); // minify: {// removeAttributeQuotes: true //} //}); Module.exports = {// Find each Entry, then go from each Entry to the dependent module, // generate a Chunk, then write the Chunk to the file system (Assets Entry) : './src/main.js', output: { path: Path. join(__dirname, 'dist'),// The output folder, which can only be an absolute path // Name is the entry name main,hash A hash value calculated from the contents of the packed file filename: '[name].[hash].js' // File name}, resolve: {// Extensions: [".js", ".less", ".json"], alias: {/ / alias "bootstrap" : "the bootstrap/dist/CSS/bootstrap CSS"}}, monitoring the change of the source file, / / said after the source file changes, then repackaged watch: false, watchOptions: Ignored: /node_modules/, poll: 1000, aggregateTimeout: 500//}, //devtool: // devtool: 'cheap-module-source-map',// devtool: 'cheap-module-source-map',// devtool: 'cheap-module-source-map',// devtool: 'eval-source-map',// will not generate a separate file,// devtool: 'cheap-module-eval-source-map',// will not generate a separate file, only to locate the row, smaller size /* loader [ { test: require.resolve('jquery'), use: { loader: 'expose-loader', options: '$' } }, { test: /\.js/, use: { loader: 'babel-loader', query: { presets: ["env", "stage-0", "react"]}}}, {//file-loader can handle arbitrary binary files. The bootstrap the font / / url - loader can file in smaller, directly into base64 string embedded into the page test: / \. (PNG | JPG | | GIF SVG | BMP | eot | woff | woff2 | the vera.ttf) /, loader: {loader: 'url-loader', options: {limit: 5 * 1024, // Specify the output directory of the copy file outputPath: 'images/'}}}, {test: /\.css$/,// convert files to match the re // csS-loader is used to parse the URL path of the CSS file, to turn the CSS file into a module //style-loader can turn the CSS file into a style tag and insert it into the head Extract ({use: cS-loader) extract({use: cS-loader) extract({use: cS-loader) ["css-loader?minimize"] }) //loader: ["style-loader", "css-loader", "postcss-loader"] }, { test: /\.less$/, loader: lessExtract.extract({ use: ["css-loader?minimize", "less-loader"] }) //use: ["style-loader", "css-loader", "less-loader"] }, { test: /\.scss$/, loader: sassExtract.extract({ use: ["css-loader?minimize", "sass-loader"] }) // use: ["style-loader", "css-loader", "sass-loader"] }, { test: / / \. (HTML | HTM), loader: 'HTML - withimg - loader'}}], plugins: [/ / from trends module internal variable injection / / new webpack ProvidePlugin ({/ / $: 'jquery' // }), new UglifyjsWebpackPlugin(), new CleanWebpackPlugin([path.join(__dirname, 'dist')]), New HtmlWebpackPlugin({template: './ SRC /index.html',// specify an HTML template filename: 'index. HTML ', // the output HTML filename title: 'index', hash: true,// will add a query string to the imported JS to avoid caching, minify: {removeAttributeQuotes: true } }), new CopyWebpackPlugin([{ from: path.join(__dirname, 'public'), to: Path. join(__dirname, 'dist', 'public')}]), cssExtract, lessExtract, sassExtract], {contentBase: './dist', host: 'localhost', port: 8000, compress: true,// Whether gzip compression is enabled when the server returns to the browser}}Copy the code

5. To summarize

This article focuses on the basic, can build a simple Webpack configuration, advanced will be released in the subsequent article, and I hope you can read the official API and summarize the output, only the knowledge output, can better memory and learning

6. The blog

Wei Ran technology blog

If you have any questions, please leave a message or send me to [email protected]