5

Preface

What is a plug-in? A functional module that focuses on processing a specific task in the compilation process of webpack can be called a plug-in.

Plugin is an extender, it enriches webpack itself, for the whole process of webpack packaging after the loader is over, it does not directly manipulate files, but works based on the event mechanism, it will monitor some nodes in the webpack packaging process, and execute A wide range of tasks.

Features of Plugin

  • Is an independent module
  • The module exposes a js function
  • Function prototype (prototype) defined on an injection compiler object apply method apply function is required by compiler objects mounted webpack event hook, hook callback can get the current compilation compilation the object, if it is asynchronous, then you can get the compiler plugin To callback callback
  • Complete the custom sub-compilation process and process the internal data of the complition
  • If the plug-in is compiled asynchronously, the callback callback will be executed after the data processing is completed.

HotModuleReplacementPlugin

Module hot update plug-in. Hot-Module-Replacement hot update is dependent on webpack-dev-server , which is the update package file or reload an entire page refresh file changes during packaging, HRM is updated only modified part.

HotModuleReplacementPlugin comes with the webpack webpack , it can be used directly in the plugins

const webpack = require('webpack')

plugins: [
  new webpack.HotModuleReplacementPlugin(), // 热更新插件
]

html-webpack-plugin

Generate html files. The webpack in entry relevant entry configuration chunk and extract-text-webpack-plugin extracted css style is inserted into the plug provided template or templateContent generating CI content specified on the basis of a html file, particularly insert mode is the style link inserted head element, script Insert it into head or body .

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

plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template: path.join(__dirname, '/index.html'),
    minify: {
      // 压缩HTML文件
      removeComments: true, // 移除HTML中的注释
      collapseWhitespace: true, // 删除空白符与换行符
      minifyCSS: true, // 压缩内联css
    },
    inject: true,
  }),
]

inject has four option values

  • true: the default value, the script tag is located at the bottom of body html
  • body: The script tag is located at the bottom of body html file (same as true)
  • head: The script tag is located in the head tag
  • false: do not insert the generated js file, just generate a html file

Multi-page application packaging

Sometimes, our application is not necessarily a single-page application, but a multi-page application, so how to use webpack for packaging.

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  entry: {
    index: './src/index.js',
    login: './src/login.js',
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[hash:6].js',
  },
  //...
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      filename: 'index.html', //打包后的文件名
    }),
    new HtmlWebpackPlugin({
      template: './public/login.html',
      filename: 'login.html', //打包后的文件名
    }),
  ],
}

If you need to configure multiple HtmlWebpackPlugin , then the filename field cannot be defaulted, otherwise the default generated index.html .

But there is a problem. index.html and login.html will find that they both introduce index.f7d21a.js and login.f7d21a.js at the same time. Usually this is not what we want. We hope that index.html only introduces index.f7d21a.js , and login.html login.f7d21a.js .

HtmlWebpackPlugin provides a chunks , which can accept an array. Configuring this parameter will only introduce the js specified in the array into the html file

module.exports = {
  //...
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      filename: 'index.html', //打包后的文件名
      chunks: ['index'],
    }),
    new HtmlWebpackPlugin({
      template: './public/login.html',
      filename: 'login.html', //打包后的文件名
      chunks: ['login'],
    }),
  ],
}

Such execution npm run build , you can see index.html only introduced index js file, and login.html also just introduced login js file.

clean-webpack-plugin

clean-webpack-plugin used to clean up the bundle file generated by the last project before packaging. It will output.path ; this plug-in is used very frequently in the production environment because the production environment often generates many bundle files through hash, if not If you clean it, a new one will be generated every time, resulting in a very large folder.

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

plugins: [
  new HtmlWebpackPlugin({
    template: path.join(__dirname, '/index.html'),
  }),
  new CleanWebpackPlugin(), // 所要清理的文件夹名称
]

extract-text-webpack-plugin

Make css into a file instead of inline. The main purpose of this plugin is to extract the CSS styles and prevent the page style loading disorder caused by packaging the styles in js.

const ExtractTextPlugin = require('extract-text-webpack-plugin')

plugins: [
  // 将css分离到/dist文件夹下的css文件夹中的index.css
  new ExtractTextPlugin('css/index.css'),
]

mini-css-extract-plugin

A plug-in that extracts CSS as a separate file, creates a CSS file for each js file that contains css, and supports on-demand loading of css and sourceMap . It can only be used in webpack4. Compared with another plug-in extract-text-webpack-plugin, it has the following features:

  • Asynchronous loading
  • No repeated compilation, better performance
  • Easier to use
  • Only for CSS

This plug-in should only be used in a production environment configuration, and loaders without the use of chain style-loader , and this plugin is not supported HMR

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.(le|c)ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../',
            },
          },
          'css-loader',
          'postcss-loader',
          'less-loader',
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css',
      chunkFilename: 'css/[id].[contenthash:8].css',
    }),
  ],
}

purifycss-webpack

Sometimes we write too much or repetitive css, which results in redundant code, which we hope to remove in the production environment.

const path = require('path')
const PurifyCssWebpack = require('purifycss-webpack') // 引入PurifyCssWebpack插件
const glob = require('glob') // 引入glob模块,用于扫描全部html文件中所引用的css

module.exports = merge(common, {
  plugins: [
    new PurifyCssWebpack({
      paths: glob.sync(path.join(__dirname, 'src/*.html')),
    }),
  ],
})

optimize-css-assets-webpack-plugin

We hope to reduce the volume of css after packaging, you can use optimize-css-assets-webpack-plugin .

const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin") // 压缩css代码

optimization: {
  minimizer: [
    // 压缩css
    new OptimizeCSSAssetsPlugin({})
  ]

UglifyJsPlugin

uglifyJsPlugin is the vue-cli to compress js files, thereby reducing the size of js files and accelerating the load speed. It uses single-threaded compression code, and the packaging time is slow, so you can close it in the development environment and open it again when deploying in the production environment.

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

plugins: [
  new UglifyJsPlugin({
    uglifyOptions: {
      compress: {
        warnings: false
      }
    },
    sourceMap: true,  //是否启用文件缓存
    parallel: true   //使用多进程并行运行来提高构建速度
  })

ParallelUglifyPlugin

Open multiple sub-processes, and assign the work of compressing multiple files to multiple sub-processes to complete. In fact, each sub-process still uses UglifyJS to compress the code, but it becomes a parallel execution.

const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')

plugins: [
  new ParallelUglifyPlugin({
    //cacheDir 用于配置缓存存放的目录路径。
    cacheDir: '.cache/',
    sourceMap: true,
    uglifyJS: {
      output: {
        comments: false,
      },
      compress: {
        warnings: false,
      },
    },
  }),
]

terser-webpack-plugin

Webpack4.0 uses the terser-webpack-plugin compression plugin by default. Before that, uglifyjs-webpack-plugin was used. The difference between the two is that the latter does not compress ES6 very well. At the same time, we can turn on the parallel parameter and use multi-process compression to speed up the compression.

const TerserPlugin = require('terser-webpack-plugin') // 压缩js代码

optimization: {
  minimizer: [
    new TerserPlugin({
      parallel: 4, // 开启几个进程来处理压缩,默认是 os.cpus().length - 1
      cache: true, // 是否缓存
      sourceMap: false,
    }),
  ]
}

NoErrorsPlugin

Report an error but do not exit the webpack process. When a compilation error occurs, use NoEmitOnErrorsPlugin to skip the output stage. This ensures that the output resource does not contain errors.

plugins: [new webpack.NoEmitOnErrorsPlugin()]

compression-webpack-plugin

All modern browsers support gzip compression. Enabling gzip compression can greatly reduce the size of transmission resources, thereby shortening the resource download time, reducing the time for the first white screen, and improving the user experience.

gzip has the best compression effect on text-based files (such as CSS, JavaScript, and HTML). It can often achieve a compression rate of up to 70-90% when compressing larger files. For already compressed resources (such as pictures) Gzip compression processing, the effect is very bad.

const CompressionPlugin = require('compression-webpack-plugin')

plugins: [
  new CompressionPlugin({
    // gzip压缩配置
    test: /\.js$|\.html$|\.css/, // 匹配文件名
    threshold: 10240, // 对超过10kb的数据进行压缩
    deleteOriginalAssets: false, // 是否删除原文件
  }),
]

Of course, this method also requires back-end configuration support.

DefinePlugin

We can DefinePlugin . We can use these variables directly in the module without any declaration. DefinePlugin is a plug-in that comes with webpack

plugins: [
  new webpack.DefinePlugin({
    DESCRIPTION: 'This Is The Test Text.',
  }),
]

// 直接引用
console.log(DESCRIPTION)

ProvidePlugin

Load modules automatically. At any time, when identifier is treated as an unassigned variable, the module will be automatically loaded, and identifier will be assigned by the output of this module. This is a plugin that comes with webpack.

module.exports = {
  resolve: {
    alias: {
      jquery: './lib/jquery',
    },
  },
  plugins: [
    //提供全局的变量,在模块中使用无需用require引入
    new webpack.ProvidePlugin({
      $: 'jquery',
      React: 'react',
    }),
  ],
}

DLLPlugin

This is only to create a dll in an additional independent webpack setting bundle(dll-only-bundle) . This plugin will generate a file named manifest.json , which is used to DLLReferencePlugin to related dependencies.

are as follows: 1608a8aaf3db26

1. Create webpack.dll.config.js

const path = require('path')
const webpack = require('webpack')
module.exports = {
  entry: {
    vendor: [
      'vue-router',
      'vuex',
      'vue/dist/vue.common.js',
      'vue/dist/vue.js',
      'vue-loader/lib/component-normalizer.js',
      'vue',
      'axios',
      'echarts',
    ],
  },
  output: {
    path: path.resolve('./dist'),
    filename: '[name].dll.js',
    library: '[name]_library',
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.resolve('./dist', '[name]-manifest.json'),
      name: '[name]_library',
    }),
    // 建议加上代码压缩插件,否则dll包会比较大。
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
      },
    }),
  ],
}

2. Add the configuration behind the plugin of webpack.prod.conf.js

new webpack.DllReferencePlugin({
  manifest: require('../dist/vendor-manifest.json'),
})

3. Add the shortcut command (build:dll) package.json

  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "lint": "eslint --ext .js,.vue src",
    "build": "node build/build.js",
    "build:dll": "webpack --config build/webpack.dll.conf.js"
  }

When packaging the production environment, the npm run build:dll command will generate the vendor-manifest.json file and vendor.dll.js file in the packaging directory. Then npm run build produces other files.

index.html under the root directory is added to the reference

<script type="text/javascript" src="./vendor.dll.js"></script>

HappyPack

HappyPack allows webpack to decompose tasks to multiple child processes for concurrent execution, and send the results to the main process after the child processes are processed. Note that HappyPack to file-loader , url-loader support unfriendly, it is not recommended to use the loader.

1. HappyPack plug-in installation

npm i -D happypack

2. Configure webpack.base.conf.js

module: {
  rules: [
    {
      test: /\.js$/,
      use: ['happypack/loader?id=babel'],
      include: [resolve('src'), resolve('test')],
      exclude: path.resolve(__dirname, 'node_modules'),
    },
    {
      test: /\.vue$/,
      use: ['happypack/loader?id=vue'],
    },
  ]
}

3. Configure in the production environment webpack.prod.conf.js

const HappyPack = require('happypack')
// 构造出共享进程池,在进程池中包含5个子进程
const HappyPackThreadPool = HappyPack.ThreadPool({ size: 5 })
plugins: [
  new HappyPack({
    // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
    id: 'babel',
    // 如何处理.js文件,用法和Loader配置中一样
    loaders: ['babel-loader?cacheDirectory'],
    threadPool: HappyPackThreadPool,
  }),
  new HappyPack({
    id: 'vue', // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
    loaders: [
      {
        loader: 'vue-loader',
        options: vueLoaderConfig,
      },
    ],
    threadPool: HappyPackThreadPool,
  }),
]

Note that when the project is small, multi-threaded packaging will slow down the packaging speed.

copy-webpack-plugin

We public/index.html , but webpack will not help us copy to the dist directory when packaging, so copy-webpack-plugin can help me do the copying work well.

const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public/js/*.js',
          to: path.resolve(__dirname, 'dist', 'js'),
          flatten: true,
        },
      ],
    }),
  ],
}

IgnorePlugin

This is a built-in webpack plug-in. Its function is to ignore the specified directories of third-party packages and prevent these specified directories from being packaged.

For example, we want to use moment , which mainly formats the time and supports multiple national languages. Although I set the language to Chinese, when packaging, all languages will be packaged. This results in a large package and slow packaging speed. In this regard, we can use IgnorePlugin make the specified directory ignored, which makes the packaging faster and the files smaller.

const Webpack = require('webpack')
plugins: [
  //moment这个库中,如果引用了./locale/目录的内容,就忽略掉,不会打包进去
  new Webpack.IgnorePlugin(/\.\/locale/, /moment/),
]

’./locale/' according to the above method, it also makes it impossible to display the Chinese language when we use it, so at this time, we can manually import the Chinese language directory.

import moment from 'moment'

//手动引入所需要的语言包
import 'moment/locale/zh-cn'

moment.locale('zh-cn')

let r = moment().endOf('day').fromNow()
console.log(r)

original address


兰俊秋雨
5.1k 声望3.5k 粉丝

基于大前端端技术的一些探索反思总结及讨论