preface

I have written about the core configuration concept and basic practice of Webpack before. Today, I mainly share the configuration and actual combat of Webpack for various situations

Webpack configuration concepts

Webpack basic practices

What do loaders and plugins do?

  • Loader: file loader, because webpack is written with node, so can only identify JS files, and loader is used to identify and convert files
  • Plugins: A plugin mechanism that broadcasts a series of events during Webpack execution. Plugins listen for these events and use the WebPack Api to process output files accordingly

Ok, start extension based on a basic practice demo from the previous chapter. If you want to start from 0, you can see the link to basic practice above.

The directory structure

webpack // Project directory
    dist // Build build directory
        bundle.js 
    index.html 
    main.js 
    utils.js 
    webpack.config.js 
    package.json 
    node_modules
    main.css
Copy the code

webpack.config.js


const path = require('path');
module.exports = {
  entry: './main.js'.// Import file
  output: {
    // Merge all dependent modules into a bundle.js file
    filename: 'bundle[hash:6].js'.// Put the output files in the dist directory
    // __dirname points to the current directory
    path: path.resolve(__dirname, './dist'),},//mode:"production",
  devServer: {// Local services
    port:"1234".// Start port
    progress:true./ / the progress bar
    open:true      // Automatically open the browser}};Copy the code

HTML plugin HTML – webpack – the plugin

For a single page SPA, we generate a dist directory every time we package. The dist directory usually contains bundled bundle.js and an entry file named index.html. Where did index.html come from?

Ok, it is actually generated by the HTML-webpack-plugin. The main principle is to create a new file based on a template file and automatically introduce bundle.js and other packaged CSS files

HTML – webpack – the plugin installation

cnpm install html-webpack-plugin -D
Copy the code

Webpack. Config. Js configuration


const path = require('path');
// Import the html-webpack-plugin
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: './main.js'.output: {
    filename: 'bundle[hash:6].js'.path: path.resolve(__dirname, './dist'),},devServer: {port:"1234".progress:true.open:true},plugins: [
   // Use plug-in mode
    new HtmlWebpackPlugin({
        template: "./index.html".// Template HTML file
        filename: "index.html".// New HTML file name after packaging
        minify: {                        // Some optimizations
            removeAttributeQuotes: true.// remove quotes
            removeEmptyAttributes: true.// Remove the empty attribute
            collapseWhitespace: true     // remove whitespace
            // There are many more}}})];Copy the code

This can be done with a plug-in that generates a new entry file in the dist directory every time it is packaged, and automatically introduces the packaged JS and CSS

Style to deal with

Actually in the work, we will write some styles, in addition to CSS, but also use some less,sass and other preprocessors, the browser itself is not recognized, in fact, is the credit of Webpack, use some loader can not recognize less or Sass conversion into CSS, Insert the style tag into the HTML, and there you go. See what it does.

Install style-loader CSS-loader less less-loader

cnpm install style-loader css-loader -D
cnpm install less less-loader -D
Copy the code

Webpack. Config. Js configuration


const path = require('path');
// Import the html-webpack-plugin
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: './main.js'.output: {
    filename: 'bundle[hash:6].js'.path: path.resolve(__dirname, './dist'),},devServer: {port:"1234".progress:true.open:true},module: { // Where the loader is mainly used
    rules: [
        // To configure the loader for packing CSS files, use defines the loader to be used, and pay attention to the sequence
        // style-loader must be placed before CSS-loader because loader is executed from right to left
        { 
            test: /\.css$/.// Matches files with a.css suffix
            use: ['style-loader'.'css-loader']]}}plugins: [
   // Use plug-in mode
    new HtmlWebpackPlugin({
        template: "./index.html".// Template HTML file
        filename: "index.html".// New HTML file name after packaging
        minify: {                        // Some optimizations
            removeAttributeQuotes: true.// remove quotes
            removeEmptyAttributes: true.// Remove the empty attribute
            collapseWhitespace: true     // remove whitespace
            // There are many more}}})];Copy the code

Another configuration of rule can be written as an object, since several other configuration items are also supported

{ 
    test: /\.(css|less)$/.// Matches files ending in.less or.css
    use: [
        {
            loader: "style-loader".options: {
                // Other related Settings}},'css-loader'.// Parse the @import path
        'less-loader' // Resolve less to CSS]},Copy the code

Explain how CSS styling works in the configuration above

  • The loader execution sequence is from right to left. Therefore, less-loader is executed to convert less to CSS
  • It is then parsed by CSS-loader and passed by @import to style-loader
  • Finally, style-loader will load the parsed CSS into the style tag and place it in the HTML head
  • Ok browser can recognize and render it

In real development, it’s not always possible to embed the style tag in the head, so we can use the plugin mechanism to separate out the CSS, package it separately and import it through the link tag

Css out of mini – Css – extract – the plugin

Install the mini – CSS – extract – the plugin

npm install mini-css-extract-plugin -D
Copy the code

Webpack. Config. Js configuration


const path = require('path');
// Import the html-webpack-plugin
const HtmlWebpackPlugin = require("html-webpack-plugin");
/ / CSS
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: './main.js'.output: {
    filename: 'bundle[hash:6].js'.path: path.resolve(__dirname, './dist'),},devServer: {port:"1234".progress:true.open:true},module: { // Where the loader is mainly used
    rules: [
        // To configure the loader for packing CSS files, use defines the loader to be used, and pay attention to the sequence
        // style-loader must be placed before CSS-loader because loader is executed from right to left
        { 
            test: /\.css$/.// Matches files with a.css suffix
            use: ['style-loader'.'css-loader']]}}plugins: [
   // Use plug-in mode
   new HtmlWebpackPlugin({
        template: "./index.html".// Template HTML file
        filename: "index.html".// New HTML file name after packaging
        minify: {                        // Some optimizations
            removeAttributeQuotes: true.// remove quotes
            removeEmptyAttributes: true.// Remove the empty attribute
            collapseWhitespace: true     // remove whitespace
            // There are many more}}),// Add a CSS extraction plug-in
    new MiniCssExtractPlugin({
        filename: "main.css".// CSS The extracted file name can be configured as a path, for example, CSS /main.css.
        // There are many configuration items, please check the documentation, only listed here}})];Copy the code

Another way to use the MiniCssExtractPlugin, for example, to remove CSS or less, is to use the MiniCssExtractPlugin in the Loader configuration rule as follows:

After the CSS conversion is complete, use the MiniCssExtractPlugin to extract it from the page with the link tag

    / / CSS examples
    { 
        test: /\.css$/, 
        use: [
            MiniCssExtractPlugin.loader,
            'css-loader'.// Parse the @import path]},/ / less sample
    { 
        test: /\.less$/, 
        use: [
            MiniCssExtractPlugin.loader,
            'css-loader'.// Parse the @import path
            'less-loader' // Resolve less to CSS]},Copy the code

extension

  • You can use postCSs-loader to prefix CSS styles for browser compatibility
  • The plugin optimize- CSS -assets-webpack-plugin is used to compress CSS, and uglip-js-plugin is used to compress JS

Convert ES6 to ES5

Bable is used here, mainly for converting JS syntax

The installation

// babel-loader Specifies the loader for Babel
// @babel/core Babel's core module
// @babel/preset-env converts ES6 to ES5
npm install  babel-loader @babel/core @babel/preset-env -D
Copy the code

Webpack. Config. Js configuration


const path = require('path');
// Import the html-webpack-plugin
const HtmlWebpackPlugin = require("html-webpack-plugin");
/ / CSS
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: './main.js'.output: {
    filename: 'bundle[hash:6].js'.path: path.resolve(__dirname, './dist'),},devServer: {port:"1234".progress:true.open:true},module: { // Where the loader is mainly used
    rules: [
        // To configure the loader for packing CSS files, use defines the loader to be used, and pay attention to the sequence
        // style-loader must be placed before CSS-loader because loader is executed from right to left
        { 
            test: /\.css$/.// Matches files with a.css suffix
            use: ['style-loader'.'css-loader']},// js => es6 convert es5
        {
            test:/\.js$/.// Matches files with the.js suffix
            use:{ // This is written as an object
                loader: 'babel-loader'.options: {
                  presets: ['@babel/preset-env'].// Convert es6 to ES5
                  plugins: [  // You can also configure plugins for a single loader, as described in the documentation
                      // Convert the class syntax to recognize some advanced syntax
                      ["@babel/plugin-proposal-class-properties", { "loose" : true}]}}}]}plugins: [
   // Use plug-in mode
   new HtmlWebpackPlugin({
        template: "./index.html".// Template HTML file
        filename: "index.html".// New HTML file name after packaging
        minify: {                        // Some optimizations
            removeAttributeQuotes: true.// remove quotes
            removeEmptyAttributes: true.// Remove the empty attribute
            collapseWhitespace: true     // remove whitespace
            // There are many more}}),// Add a CSS extraction plug-in
    new MiniCssExtractPlugin({
        filename: "main.css".// CSS The extracted file name can be configured as a path, for example, CSS /main.css.
        // There are many configuration items, please check the documentation, only listed here}})];Copy the code

The image processing

There are generally three ways to write images in development, and webPack has a corresponding way to handle these three cases

  • Create an image in JsFile - loader or url - loader
  • Introduce images to CSSThe default CSS loader converts to require
  • The IMG tag is used in HTMLhtml-withimg-loader

The installation

// file-loader will generate img images in the package build directory
// url-loader 
npm install  babel-loader file-loader url-loader -D
npm install  babel-loader html-withimg-loader -D
Copy the code

Webpack. Config. Js configuration


const path = require('path');
// Import the html-webpack-plugin
const HtmlWebpackPlugin = require("html-webpack-plugin");
/ / CSS
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: './main.js'.output: {
    filename: 'bundle[hash:6].js'.path: path.resolve(__dirname, './dist'),},devServer: {port:"1234".progress:true.open:true},module: { // Where the loader is mainly used
    rules: [
        // To configure the loader for packing CSS files, use defines the loader to be used, and pay attention to the sequence
        // style-loader must be placed before CSS-loader because loader is executed from right to left
        { 
            test: /\.css$/.// Matches files with a.css suffix
            use: ['style-loader'.'css-loader']},// js => es6 convert es5
        {
            test:/\.js$/.// Matches files with the.js suffix
            use:{ // This is written as an object
                loader: 'babel-loader'.options: {
                  presets: ['@babel/preset-env'].// Convert es6 to ES5
                  plugins: [  // You can also configure plugins for a single loader, as described in the documentation
                      // Convert the class syntax to recognize some advanced syntax
                      ["@babel/plugin-proposal-class-properties", { "loose" : true}]]}}},// Image loader processing
        { 
            test: /\.(jpg|png|gif)$/.// Match files with JPG, PNG, GIF suffixes
            use: {
                loader: 'file-loader'.// For creating images with js
                options: {esModule: false.// Compress the image path
                    outputPath: '/img/'.// Package and store in img folder, can be customized, the same as url-loader
                    publicPath: 'htpp://localhost' // Add the domain name before the path. You can also export the public configuration in outout}},Alternative file - / * url - loader loader {test: / \. (JPG | PNG | GIF) $/, / / match suffix JPG, PNG, GIF suffix file use: {loader: 'url-loader', // images do not need to be output, you can give a size limit, using base64 options: {limit:200*1024 // limit 200K use base64 format // other configuration reference document}}, */
            { 
                test: /\.html$/, matches the file with the suffix HTMLuse: 'html-withimg-loader'  // Path identification for the img tag SRC in HTML]}},plugins: [
   // Use plug-in mode
   new HtmlWebpackPlugin({
        template: "./index.html".// Template HTML file
        filename: "index.html".// New HTML file name after packaging
        minify: {                        // Some optimizations
            removeAttributeQuotes: true.// remove quotes
            removeEmptyAttributes: true.// Remove the empty attribute
            collapseWhitespace: true     // remove whitespace
            // There are many more}}),// Add a CSS extraction plug-in
    new MiniCssExtractPlugin({
        filename: "main.css".// CSS The extracted file name can be configured as a path, for example, CSS /main.css.
        // There are many configuration items, please check the documentation, only listed here}})];Copy the code

To configure the source – the map

What is source-map? Source-map is the source map, because we package it, release it, and once there’s a problem, the code gets confused and compressed, and it’s hard to locate the problem code, and source-Map is there to solve it


module.exports = {
    entry:  { / * * / has been eliminated},
    // Correspond to multiple exits
    output: { / * * / has been eliminated}
    / / 1. Source code mapping, generate a separate sourcemap file, error when directly prompted error line
    devtool: 'source-map'.// Large and complete Settings
    
    / / 2. Source map, does not produce a separate file, single will directly display the error column
    // devtool: 'eval-source-map',
    
    / / 3. No columns are generated, but a separate mapping file is generated
    // devtool: 'cheap-module-source-map', // can be retained after generation
    
    / / 4. No files are generated, and no columns are generated in the integrated repackaged files
    // devtool: 'cheap-module-source-map', // can be retained after generation
}

Copy the code

Watch Real-time packaging

This feature is actually not very practical, so let me give you a brief introduction

Install the clean-Webpack-plugin and pack in real time each time, making sure the dist directory is up to date

cnpm install clean-webpack-plugin -D Clear the dist directory before packing
// Extend two plug-ins
cnpm install copy-webpack-plugin -D  // Copy files from a directory to a specified directory
bannerPlugin // Copyright notice plugin, built-in in Webpack
Copy the code

module.exports = {
    entry:  { / * * / has been eliminated},
    // Correspond to multiple exits
    output: { / * * / has been eliminated}
    / / 1. Source code mapping, generate a separate sourcemap file, error when directly prompted error line
    devtool: 'source-map'.// Large and complete Settings
    // Enable monitoring, real-time packaging Settings
    watch: true.watchOptions: {// Set monitoring options
        poll: 1000.// Query 1000 times per second
        aggregateTimeout: 500.// Start packing after CTRL + S
        ignored: /node_modules/.// Ignore folders that do not need to be monitored
    },
    plugins: [new CleanWebpackPlugin(), // Delete dist directory before packing]}Copy the code

How does WebPack handle cross-domain

Cross domain should be a common problem in the front end, generally may be dealt with by the back end, then there is a corresponding solution in Webpack, proxy


export.modules{
    entry:  { / * * / has been eliminated},
    // Correspond to multiple exits
    output: { / * * / has been eliminated}
    // webpack.config.js
    devServer{
        // Configure the proxy
        proxy: {'/api': { // Intercepts requests containing/API in the url of the request interface
                target: 'http://localhost:3000'.// Forwards the proxy to the domain name
                pathRewrite: {'^/api':' '}, // Replace the beginning/API in the request path with empty
                changeOrigin: true.// Target is a domain name.
                secure: false.// Set a proxy that supports HTTPS}}}}Copy the code

PathRewrite is a configuration item to be aware of, because in real development, the back-end interface may not be so desirable, and it is not possible for every interface to have/API. The purpose of this configuration item is that our front-end will have/API on request, and then when the WebPack proxy proxy matches and replaces it.

Resolve Resolve third-party packages

This configuration is very interesting and is a magic tool for our development. It is directly related to the configuration of the path for importing files, images and other resources for different levels of components


export.modules{
    entry:  { / * * / has been eliminated},
    // Correspond to multiple exits
    output: { / * * / has been eliminated}
    // Parse third-party packages
    resolve: {// Parse the directory for the file search
        modules:[path.resolve('node_modules')].Import A form "... /a"
        extensions: ['.js'.'.css'.'.json'.'.vue'].// Delimit the extension, parsed in order
        
        // Set alias, import 'bootstrap' when index.js is introduced
        Improt X from "@components/ XXX "// Improt X from "@components/ XXX"
        alias: {bootstrap:'bootstrap/dist/css/bootstrap.css'.'@Components': path.resolve(__dirname, 'src/components/'),},// Other reference documents}},Copy the code

Pack multiple pages [multiple entry, multiple exit]

In fact, packaging multiple pages, relatively easy to understand, is multiple entry, corresponding to multiple exit, here to do a simple example, easy to understand


// Multi-entry configuration
entry: {
    home: './src/index.js'.other: './src/other.js'
},

// Correspond to multi-egress configuration
output: {
    // Multiple exit Settings, [name] represents multiple entry variable names home,other, one by one packaging
    filename: '[name].js'.// Name is a built-in variable that points to the entry entry configured with the corresponding key
    
    // path: path.resolve(__dirname, 'dist'),
    path: path.resolve(__dirname, 'dist'),
    
    // publicPath: 'http://localhost'
},
    
// html-webpack-plugin generates multiple files for the configuration
plugins: [
    new HtmlWebpackPlugin({
        template: "./index.html".filename: "index.html".chunks: ['home'].// Multi-page package Settings, corresponding to entry js
    }),
    // Multi-page packaging, multiple new HtmlWebpackPlugin
    new HtmlWebpackPlugin({
        template: "./other.html".filename: "other.html".chunks: ['other'].// It is also possible to import multiple js at the same time like ['other', 'home']}),]Copy the code

Ok, let’s stop here and list the various configurations and loaders and plug-ins we use frequently in development, followed by an article on webPack built-in optimizations

Small encouragement, great growth, welcome to praise