Optimizing Loader Configuration

Loader configuration :(1) optimize regular matching; (2) enable caching with cacheDirectory option; (3) reduce the number of files processed by include and exclude.

{// 1, if the project source only js file, do not write /\.jsx? Test: /\.js$/, // Babel-loader include: [resolve(' SRC ')]}Copy the code

Optimize the resolve.modules configuration

Resolve. modules is used to configure which directories Webpack goes to find third-party modules. Resolve. Modules defaults to [node modules], which means to find the module in the /node modules directory of the current directory. If not, go to the upper directory.. /node modules, if there is no more, go to.. /.. /node modules, and so on. This is similar to node.js’s module finding mechanism. When installed third-party modules are placed in the./node modules directory at the root of the project, there is no need to follow the default path of layer by layer search. You can specify the absolute path to store third-party modules to reduce the search.

Resolve: {// use an absolute path to specify the location of third-party modules to reduce the search step modules: [path.resolve(__dirname,'node_modules')]}Copy the code

Optimize the resolve.alias configuration

Import common from '@/common.js' alias: {'@': resolve(' SRC '),}, // import common from '@/common.js';Copy the code

Optimize the resolve.extensions configuration

  • The list of postfix attempts should be as small as possible. Do not include impossible situations in the project.
  • File suffixes with the highest frequency should be placed first in order to exit the search process as quickly as possible.
  • When writing import statements in source code, use suffixes whenever possible to avoid the search process. For example, when working with certainty, write require(‘. /data ‘) as require(‘. /data.json ‘), when enforceExtension and enforceModuleExtension are enabled, the developer can enforce compliance with this optimization
/ / the expansion of the automatic resolution determine config. Resolve the extensions. The values ([' js', 'vue', 'json', 'less']),Copy the code

Optimize the resolve.noparse configuration

Some libraries, such as jQuery and ChartJS, are so large and do not adopt modular standards that it is time-consuming and pointless for Webpack to parse these files, so you can ignore them.

// Use the regular expression noParse: / jquerylChartjs // use the function, starting with Webpack3.0.0 support noParse: (content) = > {/ / return true or false return/jquery | chartjs /. The test (content); }Copy the code

Exclude externals

  • Exclude packaging dependencies to prevent packaging of a dependency
  • In general, some mature third-party libraries, such as jquery, do not need to be packaged and can be directly imported into the CDN

Image loading and optimization

Image urls are imported into sASS, and file-loader is required to import files

Image-webpack-loader can help us compress and optimize images. When running Webpack, we find that the size of the generated images will be greatly compressed (I would like to know the principle and what kind of images to compress).

vue.config.js

chainWebpack: config => {
    config.plugins.delete('prefetch')
    config.plugin('provide').use(webpack.ProvidePlugin, [{
      $: 'jquery',
      jquery: 'jquery',
      jQuery: 'jquery',
      'window.jQuery': 'jquery'
    }])
    config.module.rule('images')
      .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
      .use('image-webpack-loader')
      .loader('image-webpack-loader')
      .options({ bypassOnDebug: true })
  }

Copy the code

webpack.config.js

const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(png|svg|jpg|gif|jpeg|ico)$/, use: [ 'file-loader', + { + loader: 'image-webpack-loader', + options: { mozjpeg: { progressive: true, quality: 65 }, optipng: { enabled: false, }, pngquant: { quality: '65-90', speed: 4 }, gifsicle: { interlaced: false, }, webp: { quality: 75} +} +},]}]}};Copy the code
config.module.rule('images') .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/) // .use('file-loader') .use('image-webpack-loader') .loader('image-webpack-loader') .options({ bypassOnDebug: true, mozjpeg: { progressive: true, quality: 65 }, optipng: {enabled: false,}, // pngQuant: {// quality: '65-90', // speed: 4 //}, pngQuant: {quality: [0.65, 0.90], speed: 4}, gifsicle: { interlaced: false, }, webp: { quality: 75 } });Copy the code
  • Mozjpeg – Compress JPEG images
  • Optipng – Compress PNG images
  • Pngquant — Compress PNG images
  • Svgo – Compress SVG images
  • Gifsicle — Compress GIF images

And optional optimizers:

  • Webp – Compress JPG & PNG images into webp

Extended Learning: The differences between several image formats

The plugin is chosen

  • File – loader and url – loader

Url-loader relative to file-loader: If the image size is smaller than the configured size, the image is converted to base64 to reduce the number of image requests

  • Compression -webpack-plugin: Compression files, production environment can use Gzip compression JS and CSS

Gzip on: Generate gzip files at package time and have Nginx read gzip files directly at deployment time

new CompressionPlugin({    // Pack the file in GIZ format
    filename: '[path].gz[query]'.// Target resource name. [file] will be replaced with the original resource. [path] is replaced with the original resource path, and [query] is replaced with the original query string
    algorithm: 'gzip'./ / algorithm
    test: new RegExp('\\.(js|css)$'),
    threshold: 10240.// Only resources larger than this value are processed. In bytes
    minRatio: 0.8// Only resources with compression rates lower than this value will be processed
})
Copy the code
  • Configuring global SASS does not need to be imported into the component
Module. exports = {CSS: {extract: true, sourceMap: false, loaderOptions: {// define global SCSS without importing sass: {prependData: ` @import "@/assets/css/variable.scss"; @import "@/assets/css/common.scss"; @import "@/assets/css/mixin.scss"; '}}},}Copy the code
  • SplitChunks: Common code is removed
module.exports = { configureWebpack: config => { config.optimization = { splitChunks: { cacheGroups: { vendor: { chunks: 'all', test: /node_modules/, name: 'vendor', minChunks: 1, maxInitialRequests: 5, minSize: 0, priority: 100}}}}}}Copy the code
  • TerserPlugin: Code compression removes console.log
module.exports = { configureWebpack: config => { if (process.env.NODE_ENV === 'production') { config.plugins.push( new TerserPlugin({ terserOptions: { ecma: undefined, warnings: false, parse: {}, compress: { drop_console: true, drop_debugger: false, pure_funcs: ['console.log'] // Remove console}}}))}}}Copy the code

See the Loader and Plugin topics

Import CDN static files

Const CDN = {// Ignore the bundled third-party library externals: {vue: 'vue ', vuex: 'vuex ', 'vue-router': 'VueRouter', axios: 'axios'}, // use js via CDN: [' https://cdn.bootcss.com/vue/2.6.11/vue.runtime.min.js', 'https://cdn.bootcss.com/vue-router/3.1.2/vue-router.min.js',' https://cdn.bootcss.com/vuex/3.1.2/vuex.min.js', 'https://cdn.bootcss.com/axios/0.19.2/axios.min.js',' https://cdn.bootcss.com/moment.js/2.24.0/moment.min.js'], CSS: []} chainWebpack: config => {config. Plugin (' HTML ').tap(args => {args[0].cdn = CDN return args})}; Externals = cdn.externals} <body> <div id="app"></div> <! - loop introduced - > < % for (I in htmlWebpackPlugin var. The options. The CDN && htmlWebpackPlugin. Options. The CDN. Js) {% > < script SRC = "< % = htmlWebpackPlugin.options.cdn.js[i] %>" crossorigin="anonymous"></script> <% } %> </body>Copy the code

Note: chainWebpack: (config) => {} must end with a semicolon, otherwise an error will be reported.

Choose the appropriate Source Map mode (this is a personal recommendation, but not always)

  • Development environment: eval-cheap-module-source-map
  • Production: none | nosources – source – the map

If you want to see error location in the build environment, you can also use cheap-module-source-map in the build environment

Reasons for this choice:

  • Eval is quickly rebuilt, so you can add eval properties to the local environment.
  • Using eval-source-map makes packaged files too large to be used in production environments

A proper Source map can speed up compilation

Enabling caching

  1. Babel cache

CacheDirectory :true On a second build, the previous cache is read

  1. File resource cache

Solution: Set the name of the code file to a hash name, and load the latest content when the name changes

Output file fingerprints after packaging, including hash, chunkhash, and Contenthash

  • Hash: Related to the construction of the entire project,As long as the project file is modified, the hash value for the entire project builds changes, and all files share the same hash value

The hash value of the files generated by the build is the same, so the hash calculation is related to the build of the entire project, and the hash generated during the same build is the same.

Disadvantages: will not change the file, hash value will change, no way to achieve cache

  • Chunkhash: packaged with WebpackThe chunk on, different entries will produce different chunkhash

You can package the public file and the program entry file separately, so as long as the public file doesn’t change, the hash value won’t be affected.

If chunkhash is used, the main entry file index.js and its corresponding dependent file index. CSS share the same chunkhash because they are packaged in the same module, but the common library has a separate chunkhash because it is a different module. This ensures that online builds will not repeat as long as the contents of the file have not changed

Disadvantages: index. CSS is referenced by index.js. If index.js changes the code, the CSS file will be built repeatedly, even if the contents of the CSS file are not changed.

Use contenthash alone for CSS files. As long as the CSS file contents remain the same, there will be no repeat builds.

  • Contenthash: according to theThe file contentTo define hash, contenthash does not change if the contents of the file do not change
var extractTextPlugin = require('extract-text-webpack-plugin'), path = require('path') module.exports = { ... . output:{ path:path.join(__dirname, '/dist/js'), filename: 'bundle.[name].[chunkhash].js', }, plugins:[ new extractTextPlugin('../css/bundle.[name].[contenthash].css') ] }Copy the code

Such as:

Js output file with chunkhash

output: {
        filename: '[name][chunkhash:8].js',
        path:__dirname + '/dist'
    }
Copy the code

CSS MiniCssExtractPlugin handles Contenthash

plugins:[
        new MiniCssExtractPlugin({
            filename: `[name][contenthash:8].css`
        })
    ]
Copy the code

Putting this together, I think we can consider using contenthash for CSS dependencies, chunkhash for public import files, and hash as little as possible.

Extension: File fingerprint is generally used in combination with CDN cache. After webpack construction, the corresponding file name is generated and the corresponding MD5 value is automatically added. If the file content changes, the corresponding file hash value will also change, and the URL address referenced by the corresponding HTML will also change, triggering the CDN server to pull the corresponding data from the source server, and then update the local cache. But in actual use, we use our own server

Dynamic import (lazy loading and preloading)

Lazy loading: This mode is not loaded by default and is loaded only after an event is triggered.

WebpackChunkName: ‘Load name’

  1. Preloading: Wait for other resources to load and load again when the browser is idle

webpackPrefetch: true

Cons: Compatibility issues on mobile

document.getElementId('btn').onclick = function(){
    //import starts lazy loading
    //webpackChunkName: 'desc' specifies the lazy file name
    //webpackPrefetch: true starts preloading
    import(/*webpackChunkName: 'desc', webpackPrefetch: true */'test').then(() = >{
        console.lo('I'm only loading the test file here so I can call something in that file.')})}Copy the code

The Treeshaking configuration is enabled

  • Production mode: tree-shaking is enabled automatically
  • Development mode:
  1. usedExports
  2. sideEffects
optimization: {
    /*unused harmony export XXXX */
    usedExports:true.// Delete the unused Harmony export XXXX flag
    minimize:true.Terser-webpack-plugin: WebPack4 needs to be installed separately, while WebPack5 needs to be imported
    minimizer: [new TerserPlugin()]
}
Copy the code

Turn on side effects:

optimization: {
    sideEffects:true
}
Copy the code

The above knowledge includes webpack4 and Webpack5 configurations. The author provides the solution. For details, please refer to the official website