The significance of Webpack modular packaging tools

  • Package compilation: ESM has environment compatibility issues, requiring packaging tools to directly compile some files in the development phase into most environment-compatible code in the production phase.
  • Modular JS packaging: Package module files into bundle.js files to solve the problem of frequent requests for module files in browsers.
  • Supports different types of resource modules

Webpack is quick to get started

  1. Initialize to generate a package.json file

Webpack is a tool module of NPM that generates configuration files through YARN Init initialization

yarn init --yes
Copy the code
  1. Install the Webpack core module and webpack-CLI module
yarn add webpack webpack-cli --dev
Copy the code

After the installation, the corresponding webpack and webpack-cli files are in the bin directory of Modules. 3. Yarn webpack Starts packaging automatically using the index.js directory in the SRC directory. The package file defaults to dist main.js.

yarn webpack
Copy the code

Webpack custom configuration files

Create a new webpack.config.js file in the root directory

  • Entry portal
  • The output export
  • Loader is used to convert the source code of a module to JS code

Working mode

Specify the packaging mode by mode (the mode value can be set directly in the configuration file or specified by –mode in the packaging command) :

  • development

The value of process.env.node_env is set to development. Enable NamedChunksPlugin and NamedModulesPlugin.

  • production

The value of process.env.node_env is set to production. Enable FlagDependencyUsagePlugin FlagIncludedChunksPlugin, ModuleConcatenationPlugin NoEmitOnErrorsPlugin, OccurrenceOrderPlugin SideEffectsFlagPlugin and UglifyJsPlugin.

loader

Three ways of use:

  • ** Configuration: ** Specify loader in the webpack.config.js file
 module: {
    rules: [{test: /\.css$/.// If there are multiple Loaders, the execution sequence is from bottom to top
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader'.options: {
              modules: true}}]}Copy the code
  • ** Inline: ** displays the specified loader in each import statement

Use! Separate the loaders in the resource. ? Used to pass query parameters

import Styles from 'style-loader! css-loader? modules! ./styles.css';
Copy the code
  • **CLI:** specified in the shell command
webpack --module-bind jade-loader --module-bind 'css=style-loader! css-loader'
Copy the code

File resource loader

File-loader loads resource files into a specified file, usually in the dist directory by default. Load parsing takes resources from the root directory by default. Therefore, you need to set the path of the packaged input file through publicPath. The package file is the path configured on the previous concatenation when the resource is read (the final/cannot be omitted because it is the concatenated path).

output:{
	publicPath:'dist/'
}
Copy the code

In addition to file-loader, bundles and loads resources by way of path use. There is also a URL loader that converts files directly into data files and places them in a packaged file. However, some files are very large after being converted into data files, so the following processing methods are generally adopted:

  • Use Data URLs for small files to reduce the number of requests
  • Large files are separately extracted and stored to improve loading speed

Loaders generally have some additional configuration to process files that need to be processed by the corresponding loader. Url-loader limit:

{
	test:/.png$/,
	use:{
		loader:'url-loader'.options: {limit:10 * 1024 // only files smaller than 10kb are processed as data files by url-loader}}}Copy the code

General classification of common Loaders

  • Compile and transform classes: CSS-loader, babel-loader
  • File operation class: file-loader
  • Code check class: eslint-loader

Babel is used to compile ES6 into ES5 to handle new features. It is usually necessary to install the dependent core module @babel/code @babel/preset-env together

How webpack loads resources

  • Follow the ES Modules standard import declaration
  • Follow the CommonJs standard require function
  • Follow AMD standard define function and require function
  • The @import directive and URL function in the style code
  • The SRC attribute of the image tag in HTML code

How the core of WebPack works

  1. Find the package file entry through the configuration file, which is usually a JS file
  2. Deduce the dependent module in the import file using the import or require keyword
  3. The dependencies corresponding to each module are analyzed respectively to form a dependency tree that reflects the dependencies of the whole project.
  4. Recursive dependency tree, find the corresponding resource file for each node
  5. Locate the loader corresponding to each resource file based on the rules configuration and load the resources
  6. Put the results loaded by loader into the packaged result bundel.js

Webpack plugin mechanism

The Webpack plug-in is a JavaScript object with the Apply attribute. The Apply attribute is invoked by the Webpack Compiler, and the Compiler object is accessible throughout the compile life cycle.

Clean-webpack-plugin Automatically cleans the input directory plug-in. Html-webpack-plugin Outputs HTML files through Webpack. Copy-webpack-plugin copies files. Accepts an array of the file directories to be copied

Html-webpack-plugin can configure parameters such as title and meta. You can also generate HTML files in the form of template files.

The HTml-webpack-plugin will be generated by the full file relationship after the dependency tree is loaded, so rules only needs to deal with the real dependency files, and node_modules files should be excluded.

rules: [
        {
          test:/.js$/,
          exclude:/node_modules/,
          use:{
            loader:'babel-loader'.options: {presets: ['@babel/preset-env'}}}]Copy the code
plugins:[
	new HtmlWebpackPlugin({
		title:'Custom title'.meta: {viewport:'width= device-width'
		},
		template:'./src/index.html'})]Copy the code

The./ SRC /index.html template file is output using lodash template syntax

<h><%= htmlWebpackPlugin.options.title %></h>
Copy the code

Each htmlWebpackPlugin instance object generates a corresponding page file. If multiple pages are required, multiple objects can be instantiated. Filename specifies the name of the page file.

Plugin is implemented through the hook mechanism

Automatic compilation

— In Watch mode, files will be automatically compiled and packaged when they change

webpack --watch
Copy the code

Automatically refresh the browser

Browser-sync is installed first. Browser-sync is run on the cli. When files change, the browser is automatically refreshed.

The idea is to listen to the –flies specified file, refresh the browser when it changes, and render the index.html file in the dist directory. Therefore, index. HTML cannot be deleted each time it is packaged. If the CleanWebpackPlugin plugin is used, you need to configure not to delete the index file.

new CleanWebpackPlugin({cleanStaleWebpackAssets: false})
Copy the code
browser-sync  dist --files "* * / *"
Copy the code

webpack dev serve

Provides HTTP Server for development, integration with auto-compile and auto-refresh browser features. Install it using YARN Add

Tips: Be aware of compatibility issues with the WebPack version, it is best to install the lower version. The combination of WebPack4. X, webpack-cli3. X, and webpack-dev-server2.

yarn add webpack-dev-server --dev
Copy the code

Command line operation

yarn webpack-dev-server --config ./webpack.config.js --open
Copy the code

By default, the files generated by packaging are server resource files that are directly accessible to the server. However, other static resource files require additional configuration if they are also required as server files. The location of the static resource file is set with devServerde contentBase.

module.exports = {
	sevServer: {contentBase:'./public'}}Copy the code

Source Map

Source Map, as the name implies, is used to Map the relationship between packaged and transformed code and Source code. Devtool is used to set development tool Settings.

devtool:'source-map'
Copy the code

There are several key words that distinguish the DevTool mode:

  • Eval – Whether to use EVAL to execute module code
  • Cheap -Source Map contains row information
  • Module – Whether you can get the source code before Loader processing

General selection rules:

  • Development environment: cheap-module-eval-source-map
  • Production environment: None

The HMR module is hot replaced

There are several ways to implement HMR:

  • Add the –hot argument to the command line runtime
webpack-dev-server --hot
Copy the code
  • Enable it through the configuration file

1. Configure devServer to enable hot update

devServer:{
      hot:true
    }
Copy the code

2. Use webPack built-in plug-ins

const webpack = require('webpack')
module.exports = {
	plugins: [new webpack.HotModuleReplacementPlugin()
	]
}
Copy the code

HMR optimized use

Because the replacement logic is irregular, the HMR in WebPack also needs to handle the replacement logic manually.

If already through HotModuleReplacementPlugin enabled modules Hot Replacement (Hot Module Replacement), then it will be exposed to the Module interface. Under the Hot properties.

Tips: Files after additional processing are no longer refreshed automatically, but instead perform the configured hot replace logic.

Accept accepts updates from a given dependency module and triggers a callback function to respond to those updates.

module.hot.accept(
  dependencies, // Can be a string or an array of strings
  callback // The function that fires when the module is updated
)

Copy the code

Matters needing attention:

  1. Handling HMR code errors causes an automatic refresh

Solution: Set hotOnly of devServer to true. Processing HMR errors does not backflush. 2. When HMR is not enabled, HMR API error solution: check whether hot plug-in module. Hot is enabled before HMR processing code

Configurations in different environments

Under normal circumstances, development environment pursues development efficiency, production environment pursues rendering speed, and different environments have different packaging requirements. Different configurations should be made for different environments. There are two main implementation modes:

1. Export configuration files based on different environments. 2

1. Export configuration files based on different environments (small – and medium-sized projects)

The WebPack configuration file supports exporting a function that takes two arguments. Env environment arguments, all arguments passed by argv.

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')


module.exports = (env,argv) = > {
  const config = {
    mode:"development".entry:'./src/main.js'.output: {filename:'js/bundle.js'
    },
    devtool:'source-map'.module: {rules: [{test:/.js$/,
          exclude:/node_modules/,
          use:{
            loader:'babel-loader'.options: {presets: ['@babel/preset-env'}}}, {test:/.css$/,
          use:[
            'style-loader'.'css-loader'] {},test:/.png$/,
          use:{
            loader:'url-loader'.options: {limit:10 * 1024 // Images smaller than 10KB will be converted to Data URLs. Images larger than 10KB will still need to be processed by file-loader, so it will also need to be installed}}}]},plugins: [new HtmlWebpackPlugin({
        title:'Webpack'.template:'./src/index.html'
      }),
      new webpack.HotModuleReplacementPlugin()
    ]
  }

  if(env === 'production'){
    config.mode = 'production'
    config.devtool = false
    config.plugins = [
      ...config.plugins,
      new CleanWebpackPlugin(),
      // new CopyWebpackPlugin({patterns: [{ from: "public", to: "public" }] }]}return config
}
Copy the code

2. Each environment corresponds to a configuration file

There is usually a common configuration. Merge common Settings into different configuration files using the Webpack-Merge module.

  1. Install the Webpack-Merge module
  2. Merge generic and environment-specific configurations in a separate configuration file using webpack-Merge.
Merge ([common,{environment configuration}])Copy the code

DefinePlugin

There are many default optimizations for production environments. DefinePlugin is a built-in webPack plug-in that needs to be imported before it can be used.

const webpack = require('webpack')

module.exports = {
	mode:'none'.entry:'./src/main.js'.output: {filename:'bundle.js'
	},
	plugins: [new webpack.DefinePlugin({
			API_BASE_URL:JSON.stringify('http://api.com')]}})Copy the code

Production mode optimization

optimization:{
	usedExports:true.// Export only used members
	minimize:true.// Compress useless code
	concatenateModules:true.// Merge modules.
	sideEffects:true.// Are there any side effects
	splitChunks: {// Public module extraction
		chunks:'all'},minimizer: [// Code compression configuration
		new TerserWebpackPlugin()//js compression plugin
		new OptimizeCssAssetsWebpackPlugin()// CSS compression plug-in]}Copy the code

Tree Shaking

This function is automatically enabled in production mode. In other patterns, optimization options can be centrally configured through optimization. As far as possible, combine all modules and output them into one function, which not only improves the operation efficiency, but also reduces the volume of the code

Tree Shaking is prerequisite for ES Modules and only handles ESM. If the babel-Loader converts new features using CommonJs, Tree Shaking will fail. Babel’s conversion to ESM can be configured to be turned off.

{
	test:/\.js$/,
	use:{
		loader:'babel-loader'.options:[
			presets:[
				['@bable/preset-env', {modules:false}]]]}}Copy the code

SideEffects side effects

The side effect check is also automatically enabled in production mode. Side effects: What a module does when it executes other than exporting members, generally used to flag NPM packages for side effects. SideEffects set to false in package.json has no sideEffects and unused modules will not be packaged. If a module does anything other than export members, it has sideEffects, and the files with sideEffects should be added to the sideEffects array to prevent useful modules from being deleted by mistake.

/ / package. The json file
"sideEffects": ['./src/global.css'.'./src/extend.js'
]
Copy the code

Code Splitting

Subcontract, load on demand.

  • Multiple entry packing
  • Dynamic import

Multiple entry packing

Generally used for multi-page programs. Each page corresponds to a package entry, and the common parts are extracted separately. The extraction of common modules is also set up in Optimization. Entry is configured as an object, and each attribute of the object corresponds to a packaging entry. Multiple wenport files will correspond to multiple egress and HTMLL files, which need to be synchronized.

entry:{
	index:'./src/index.js'.album:'./src/album.js'
},
output: {filename: [name]. Bundle. Js},plugins: [new HtmlWebpackPlugin({
		title:'Multi Entry'.template:'./src/index.html'.filename:'index.html'.chunks: ['index']// Set the package file referenced
	}},
	new HtmlWebpackPlugin({
		title:'Multi Entry'.template:'./src/album.html'.filename:'album.html'.chunks: ['album']// Set the package file referenced}}]Copy the code

Dynamic import

Dynamically import modules by importing (modules).then (). Dynamically imported modules can use magic comments to name bundles generated by subcontracting. Dynamically imported modules with the same bundle name will be packaged into the same bundle file.

import(/*webpackChunkName:'posts'*/'./posts').then(({default:posts}) = > {
  document.body.append(posts())
})
Copy the code

MiniCssExtracPlugin

Extracting the CSS to a single file is recommended only when the style file is too large. Extracting the CSS to a single file increases the number of requests. When the CSS is packaged as a separate file, you do not need to use style-loader to inject the CSS file into the JS file through the style label. Instead, use the loader provided with MiniCssExtracPlugin to inject the CSS file through the link mode.

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

Compression of individual CSS files

Using the plugin: optimization-CSS-assets-webpack-plugin is recommended in Optimization so that the plugin is used only when minimizer is turned on. Once minimizer is set, the default compression configuration needs to be manually configured, so the default JS compression will not work and needs to be manually configured.

Output file name Hash

Typically, the server’s static resource cache is enabled when the front-end resource files are deployed. The cache expiration time is difficult to control. Therefore, you are advised to use Hash file names in production mode. The cache is invalid only when the file changes and resources are requested again.

There are three Hash levels:

[hash:num]// Can intercept the hash value of the specified num length
Copy the code
  • Hash: A project-level hash that changes whenever the project file changes.
  • Chunkhash Package-level hash: The chunkhash will change when the same chunk file is changed
  • Contenthash Specifies the file level hash