SkFeTeam Author: Li Jian

The introduction

As a front-end developer, meeting business requirements on time and in good quality is just a basic condition. Knowing some webPack-related configurations can not only help us improve our technical capabilities (not limited to meeting business requirements), but also help us to better maintain projects and build web sites suitable for our team.

I hope this article can let you have an intuitive understanding of webpack4 related configuration items, in the form of examples to help you better and faster grasp the relevant knowledge points.

Webpack4 introduction

  • Webpack is a JS application wrapper that bundles the various modules in an application into one or more bundles. With loaders and plugins, it can change, compress, and optimize a wide variety of files. It takes in different resources, such as JS, CSS, images, fonts, HTML files, and so on, and outputs them into files that the browser can parse properly.
  • On August 25, 2018, WebPack 4 was officially released. Compared with Webpack 3, it brought a lot of new feature updates and improvements, making WebPack configuration easier
  • Webppack4 is one of the mainstream packaging tools at present. Compared with other packaging tools, such as gulp and rollup, Webpack4 has advantages: high community activity, many users and fast official update iteration.

Webpack4 configuration items

The preparatory work

  • Install Node, webpack, and create a new folder – NPM initialization
// WebPack installation is generally not -g global installation, because there are several projects running at the same time, sometimes the webpack versions of these projects are not the same, so they are local installation according to the project, only effective in independent projects.
npm install webpack-cli webpack --save-dev 
// The project name, version number, and description are all set by default. If you need to change them, you can change them in package.json.
npm init/npm init -y 
Copy the code

Mode attribute

  • The mode attribute can be set to: Development (code compression)/production(code compression) can provide more detailed error logs and prompts during the development mode. When the production environment is packaged, webpack can focus on the packaging of the project, eliminating the running code in the development stage, so that the package file of the packaged production environment is smaller.

entry/output

  • Entry and packaged successful exit – basic configuration
// Webpack will look for the webpack.config.js file by default
// To use path, you need to import it first
const path = require('path')
module.exports = {
    mode: 'development'.// Development modeEntry:'./index.js'.// Specify the entry file
    output: {
        filename: 'bundle.js'.// Define a name for the successfully packaged file
        path: path.resolve(__dirname,'dist'),//__dirname-- in the same directory as webpack.config.js, the generated package file is in the dist directory
    }
}
entry: {
    main: './src/index'.sub: './src/index'
}
output: {
    publicPath: ' 'If you need to add a domain name, you can configure filename as follows:'[name].js'Path: resolve.path(__dirname,'dist')}Copy the code
  • Code demo – 1
npx webpack -v
npx webpack index.js
// In package.js script you can configure to run the package command
"script": {
    "build": "webpack"
}
npm run build
Copy the code
  • Json, NPM webpack index.js, Hash — unique Hash value, version — Webpack version, Time — Time spent packaging, built, Asset — packaged file, Size refers to the size of the package file, chunks refers to the ID value of each package file, chunk Names refers to the package name, and main refers to the package entry file

loader

  • What is loader? Webpack cannot process files with non-JS suffix, so it needs to use Loader. Loader is actually a package solution. So webPack relies on loader to execute the package.
  • File-loader To pack the loader, add the image/font packing rule in webpack.config.js
//webpack.config.js
module.exports = {
    ...
    module: {
    // Array types of rules -- There are many different types of packing rules
        rules: [
            {
                test: /\.(jpg|png|jpeg)$/.use: {
                    loader: 'file-loader'.options: {
                    //placehold-- placeholder name-- file name, hash--hash value, ext- file suffix
                        name: '[name]_[hash].[ext]'.// Pack the image into the image folder in dist
                        outputPath: "./image"}}}, {test:/\.(eot|ttf|svg)$/.use: {
                    loader: 'file-loader'. }}]}}Copy the code
  • Url-loader contains the function of file-loader to package images. When no configuration items are added, the image is packaged as base64 characters by default and placed in the packaged JS file. The advantage is that the image is loaded after loading the JS file, which reduces the HTTP request. The disadvantage is that when the image file is too large, the packaged JS file put into the image will be too large. Therefore, when loading the technical JS file, it takes a long time to load and stays on the blank page for a long time. Therefore, add the configuration item LIMIT.
Rules: [{test: / \. (JPG | jpeg | PNG) $/,use: {
          loader: 'url-loader'.options: {
              filename: '[name]_[hash].[ext]'.outputPath: './image'.limit: 20480.//==20480 bytes == 20KB
              // If it is larger than 20KB, it is packaged as an image and placed in the dist directory. If it is smaller than 20KB, it is packaged as a Base64 string and placed in the packaged JS file}}}]Copy the code
  • Code demo – 2 – before and after using url with limit configuration
// To use file-loader,url-loader must be installed
npm install file-loader --save-dev
npm install url-loader --save-dev
Copy the code

style-loader css-loader sass-loader postcss-loader

  • Similarly, when packing CSS and SCSS, Webpack does not know how to pack, so it needs to use relevant loader to perform packaging. Css-loader and style-loader should be installed at the same time. Css-loader is only responsible for processing CSS files. After the CSS content file is processed and merged, you need to use the style-loader to attach to the page header, so that the style packaging will take effect on the page, similarly if the sass file, Sass-loader and Node-sass should also be installed, because sass-loader relies on Node-sass to parse SASS files. Therefore, the execution sequence is as follows: First, Sass-Loader parses SCSS files into CSS files. Then csS-loader processes these parsed CSS files, and then style-loader attaches these contents to the header part of the page. Postcss-loader is added with vendor prefix, which is implemented first.
/ / install the loader
npm install style-loader css-loader sass-loader node-sass postcss-loader --save-dev
Postcss-loader: postcss-loader: postCSs-loader
//autoprefixer
npm install autoprefixer -D
// To use postCSs-loader, you need to add a configuration file
//postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')]}//webpack.config.js
module: {
    rules: [{test: /\.css$/.use: [
                "style-loader"The <! --"css-loader", -- - > {loader: "css-loader".options: {
                        // Add a CSS file to the CSS file, so that configuration items can be used for each layer to go (down-up, right-left)
                        importLoader: 2.// Config supports CSS modularity, avoiding style rendering global, name. class name calls<! --modules:true-- >}}"postcss-loader"] {},test: /\.scss$/.use: ["style-loader"The <! --"css-loader", -- - > {loader: "css-loader".options: {
                        importLoader: 2The <! --modules:true-- >}},"sass-loader"."postcss-loader"]]}}Copy the code
  • Code demo – 3

plugins

  • html-webpack-plugin: We can also create an HTML template in the SRC directory. Then we can set the configuration items. We can automatically generate HTML from this HTML template and put it in the dist directory
  • Clean-webpack-plugin: Removes the dist directory that was packaged before the package
// First install html-webpack-plugin hlean-webpack-plugin
npm install html-webpack-plugin clean-webpack-plugin -D

/ / in webpack. Config. Js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new CleanWebpackPlugin('./dist')]}Copy the code
  • TypeError: CleanWebpackPlugin is not a constructor

// So you must use the object structure to refer to this plug-in
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// The plugin should use the default configuration. If parameters are passed in, they must be in the form of objects
new CleanWebpackPlugin()/ new CleanWebpackPlugin({})
Copy the code

SourceMap configuration

  • What is this? This configuration helps us to make a mapping between the packaging and the source code. When there is a problem with packaging, we do not need to know which line of the packaging file is wrong, but which line of the source code is wrong.
//webpack.config.js
module.exports = {
    // Basic configuration
    devtool: "source-map"
    // Can prompt a comprehensive error message, specific to which row and column characters, and the mapping file will be packaged into the package file
    devtool: "inline-source-map"
    // The development environment configuration is recommended
    devtool: "cheap-module-eval-source-map"
    // Production environment
    devtool: "cheap-module-source-map"
}
Copy the code

webpackDevServer

  • It can listen for changes to files and simulate server features that automatically package files and refresh pages when the contents of the SRC directory change.
// Install webpack-dev-server first
npm install webpack-dev-server -D

//package.json
"scripts": {
    "watch": "webpack --watch"."start": "webpack-dev-server",}//webpack.config.js
devServer: {
    contentBase: './dist'.// Directory loaded by the local server
    open: true.// Start a local server with port 8080 by default.
    port: "".// The port can be customized. }Copy the code

Hot Module Replace – HMR: Hot update Module

  • Using webpack-dev-server to start the project will help us to start a local server, and it will automatically help us to pack the package files in memory, which is faster and better performance.
  • Webpack own plug-in – a hot update module HotModuleReplacementPlugin, but in the process of CSS and js, meet in CSS hot update, js need more code, because the CSS – loader has been written for us, like hot update vue framework is also, The React framework is also handled with the Preset configuration of Babel
// weebpack.config.js
const webpack = require('webpack');

module.exports = {
    devServer: {
        contentBase: './dist'.port: 8080.open: true.hot: true.//-- Enable hot update
        hotOnly: true.// Prevents the browser from automatically refreshing the page, even if the hot update function does not work
    }
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]
}
//js
if(module.hot) {
    module.hot.accept('./number', () = > {document.body.removeChild(document.getElementById('id'))
        number()// Re-execute the module function})}Copy the code
  • Code demo – 5
  • sourceMap

Babel handles ES6 syntax

  • Es6 syntax is not currently supported for common browsers, but es5 syntax code is supported, so you need to use the Babel plugin to do the conversion. Here you can check the official Babel documentation – here you omit ten thousand steps – there is a choice of usage scenarios – select webPack usage scenarios
// Install the plugin --@babel/core is the Babel core library
npm install babel-loader @babel/core -D
// Also, babel-loader is just a bridge over Webpack, and does not escape the code. It is needed to use @babel/preset-env for syntax conversion
npm install @babel/preset-env -D
// Install @babel/polyfill -- it is used to help the browser with the lower version to make up for the missing variables and functions. At the same time, you can configure options to make up for the lower version of the missing variables and functions according to the business code, so that the packaging code can be simplified. Because it will pollute the whole world
npm install @babel/polyfill -D
// create a.babelrc file in which the options configuration can be placed
{
    presets: [["@babel/preset-env",
            {
                "targets": {
                    "chrome": "67"
                },
                "useBuiltIns": "usage"// Load as needed}}]]//webpack.config.js
test: /\.js$/.exclude: /node_modules/.loader: "babel-loader"The <! --options: {--><! -- presets: [['@babel/preset-env',{targets: {chrome: "67",},useBuiltIns: 'usage'}]]-->
<! -} -- >
//test code --es6
import '@babel/polyfill'
const arr = [
new Promise(() => {}),
new Promise(() => {})
]
arr.map(item => {
    console.log(item)
})
Copy the code

Webpack implements packaging of the React framework code

  • The @babel/preset-env plugin is needed to preset es6 syntax after the React framework code is converted.
// Use the install plugin
npm install react react-dom --save-dev
npm install @babel/preset-react --save-dev
//.babelrc to reference the plug-in
presets:[
    "@babel/preset-react"
]
//js--test-code
import React ,{ Component } from 'react'
import ReactDom from 'react-dom'
class App extends Compnent {
    render() {
        return(<div>herllo world</div>)
    }
}
ReactDom.render(<App/>.document.getElementById('root'));
Copy the code

Tree shaking

  • This is a feature of Webpack, when introducing a module, you don’t need to introduce all the code, only need to introduce the required code – – shake the tree meaning, all unnecessary leaves to shake.
  • But Tree Shaking in WebPack only supports esModule imports.
//webpack.config.js
module.exports = {
    plugins: [].optimization: {
        usedExports:true// This configuration is required only in the development environment, not in the production environment}}// Package. json the development environment will keep this code
"sideEffects": ['*.css']-- Ignore related modules not to do tree shakingCopy the code

Development and production mode of packaging, webpack. Dev. Js, webpack. Pord. Js, webpack.com mon. Js – can put the files in the build file

// Need to download webpack-merge
npm install webpack-merge -D
//dev
const webpack = require('webpack');
const devConfig = {
    mode: 'development'.devtool: 'cheap-module-source-map'.devServer: {
        contentBase: '.. /dist'.// Directory loaded by the local server
        open: true.// Automatically open the browser when the package is complete
        // port: 8080,
        hot: true.// Enable module hot update
        hotOnly: true.// Prevents the page from refreshing, even if the hot update function fails
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ], 
    optimization: {
        usedExports:true,}}module.exports = devConfig;
//pord
const pordConfig = {
mode: 'production'.//production 
}
module.exports = pordConfig;
//common
const path = require('path');
const merge = require('webpack-merge')
const devConfig = require('./webpack.dev.js');
const prodConfig = require('./webpack.prod.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const commonConfig = {
    entry: {
        main: './src/index.js'
    },
    module: {
        // Array types of rules -- There are many different types of packing rules
        rules: [
            / / {
            // test: /\.(jpg|png|jpeg)$/,
            // use: {
            // loader: 'file-loader',
            // options: {
            // //placehold-- placeholder name-- file name, hash--hash value, ext- file suffix
            // name: '[name]_[hash].[ext]',
            // // package the image into the image folder in the dist directory
            // outputPath: "./image"
            / /}
            / /}
            // },
            {
                test: /\.js$/.exclude:/node_modules/.loader: 'babel-loader'
            },
            {
                test: /\.(jpg|png|jpeg)$/.use: {
                    loader: 'url-loader'.options: {
                    //placehold-- placeholder name-- file name, hash--hash value, ext- file suffix
                        name: '[name]_[hash].[ext]'.// Pack the image into the image folder in dist
                        outputPath: "./image".limit: 204800,}}}, {test:/\.(eot|ttf|svg)$/.use: {
                    loader: 'file-loader',}}, {test: /\.css$/.use: [
                    "style-loader"."css-loader"."postcss-loader"] {},test: /\.scss$/.use: [
                    "style-loader"."css-loader"."sass-loader"."postcss-loader"]]}},plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        // * All files inside webpack's output.path directory will be removed once, but the
        // * directory itself will not be. If using webpack 4+'s default configuration,
        // * everything under <PROJECT_DIR>/dist/ will be removed.
        new CleanWebpackPlugin({ verbose: true.cleanOnceBeforeBuildPatterns: ['* * / *']})],output: {
        filename: 'bundle.js'.// Name of the file after successful packaging
        path: path.resolve(__dirname,'.. /dist'),//__dirname- represents the same root directory as web.config.js, packaged folder}}module.exports = (env) = >  {
    if(env&&env.production) {
        return merge(commonConfig,prodConfig)
    }else{
        return merge(commonConfig, devConfig)
    }
}
//package.js
"script": {
    "start": "webpack-dev-server --config ./build/webpack.common.js"."build": "webpack --env.production --config ./build/webpack.common.js"."dev": "webpack --env.development --config ./build/webpack.common.js"
}
Copy the code
  • Code demo -6

Webpack and Code Splitting:

  • Code splitting is a very important feature of WebPack. It allows you to split code into different files and load them on demand or in parallel, which optimizes load performance and improves user experience.
  • In fact, code splitting is only implemented in Webpack. There are two methods: synchronous code splitting only needs to be configured in Optimization. Asynchronous code splitting is the default configuration of WebPack code splitting, but it needs Babel plug-in for translation. Browsers do not support this syntax for asynchrony.
// install babel-plugin-dynamic-import-webpack
npm install babel-plugin-dynamic-import-webpack -D
// splitChunks need to be configured in Optimization to synchronize code splitting
//-- configure a plugins in.babelrc.
presets: [], 
plugins: ["dynamic-import-webpack"]
//webpack.common.js
optimization: {
    splitChunks: {
        chunks: 'all'// Split synchronous and asynchronous code simultaneouslyChunks:'aysnc'// Split asynchronous code}}//test-code--index.js
function getComponent() { 
    return import('lodash').then(({default: _}) = > {
        var element = document.createElement('div');
        element.innerHTML = _.join(['dell'.'lee'].'_');
        return element
    })
}
getComponent().then(element= > {
    document.body.appendChild(element);
})
Copy the code
  • In the underlying configuration of splitChunksPlugin, the asynchronous code is automatically packaged into a file 0.js, where you need to specify the name of the file to import the asynchronous code. You can use magic comments. The plugin @babel/plugin-syntax-dynamic-import is needed to convert the asynchronous code, instead of using babel-plugin-dynamic-import-webpack, /WebpackChuunkName: ‘lodash’/,
  • Chunks: AYSNc this asynchronous code can solve the problem of large package files, long loading time, and separation of third-party libraries and plug-ins. On-demand loading and parallel loading can be carried out when necessary to provide loading performance.
npm install @babel/plugin-syntax-dynamic-import --save-dev
splitChunks: {
    chunks: async // if async is used, only asynchronous code is split; if all is used, both asynchronous and synchronous code are split
    minSize: 30000= = =30kb // If it is larger than 30KB, it is split; if it is smaller, it is splitMaxSize:0.// If 50000=== 50KB, lodash will be split into 1MB, and 20 50KB codes will be split
    minChunks: 1.// When this module is used several times, it does not split the code
    maxAsyncRequests: 5.// There are 5 modules loaded at the same time. Five modules will help you pack for code splitting before packaging. If more than five modules are loaded at the same time, no code splitting will be done
    maxInitialRequests: 3.// The import file will introduce other libraries, and the import file can only be three. If the import file is more than three, the code will not be split
    automaticNameDelimiter: '~'.// When a file is generated, there are some concatenators in the middle of the file,
    name: true, -- -// What is the name that makes the name in cacheGroups valid
    cacheGroups: {// If it is synchronous, the chunks will go through the configuration, the cache group
        vendors: {
            test: /[\\/]node_modules[\\/]/.//-- synchronized code discovery is imported from node_modules, and the conforming group is packaged into a separate file
            priority: - 10
            filename: 'vendors.js'// Is the name of the package file
        }
        default: {
            priority: - 20.// This configuration is used to set the priority, the larger the value, the higher the priority
            reuseExistingChunk: trueIf a module A, b, if a uses B, meets the code split requirement, and then meets againdefaultFor this group, do not pack the previously packed content filename:'common.js'}}}Copy the code
  • Lazy loading – supports esModule syntax and loads on demand.
  • ChunkFilename: chunkFilename: chunkFilename: chunkFilename: chunkFilename: chunkFilename: chunkFilename: chunkFilename: chunkFilename: chunkFilename: chunkFilename
// Install the plug-in
npm install mini-css-extract-plugin --save-dev
// CSS files generated separately in the online environment need to be compressed and merged
npm install optimize-css-assets-webpack-plugin -D
//optimization
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin = require(' optimize-css-assets-webpack-plugin')
// Change the configuration
// The development environment uses the rule default
// Online environment
module: {
    rules: [
            use: ['MiniCssExtractPlugin.loader'] // Use style-loader instead of style-loader]},optimization: {minimizer: [new OptimizeCssAssetsWebpackPlugin({})]},
plugins: [new MiniCssExtractPlugin({
    filename: '[name].css'.// This configuration is referenced directly by the file
    chunkFilename: '[name].chunk.css'// This configuration item is used for indirect references
})]
output: {
    filename: '[name].js'.chunkFilename: '[name].chunk.js'.// Package files referenced indirectly by JS will go through this configuration,
    path: path.resolve(__dirname,'.. /dist')}Copy the code

I hope this article has been helpful.

For more shared articles from skFeTeam, click herehere, thank you ~