Optimizing environment Configuration

1- Webpack performance optimization

  • Development environment performance optimization
  • Production environment performance optimization

Development environment performance optimization

  • Optimize packaging build speed
    • HMR
  • Optimized code debugging
    • source-map

Production environment performance optimization

  • Optimize packaging build speed
    • oneOf
    • Babel cache
    • Multi-process packaging
    • externals
    • dll
  • Optimize the performance of code execution
    • Cache (hash – chunkhash – contenthash)
    • tree shaking
    • code split
    • Lazy loading/preloading
    • pwa

01-HMR Hot module replacement

Devserver based on development environment (development environment does not have HMR functionality)

HMR: Hot Module replacement or hot module replacement

What it does: When a module changes, it repackages only that module (not all modules), greatly increasing build speed

  • Style files: you can use the HMR function: because style-loader implements ~ internally

  • Js file: HMR function cannot be used by default –> Need to modify js code, add code supporting HMR function.

    Note: the HMR function can only handle other files that are not entry JS files.

  • HTML files: the HMR function is disabled by default. It also causes problems: HTML files cannot be hot updated.

    • Solution: Modify the entry entry to import the HTML file
  entry: ['./src/js/index.js'.'./src/index.html'],...devServer: {
    static: resolve(__dirname, 'build'),
    compress: true.port: 3000.open: true.// Enable HMR
    // When the WebPack configuration is changed, the webpack service must be restarted for the new configuration to take effect
    hot: true} The method's hot module replacement can be achieved by negotiating the following code in a non-entry JS file that requires hot module replacementif (module.hot) {
  // Once module.hot is true, HMR is enabled. --> Make the HMR function code work
  module.hot.accept('./print.js'.function() {
    // The print.js method listens for changes in the print.js file, and when changes occur, other modules are not repackaged and built.
    // The following callback functions are executed
    print();
  });
}

Copy the code

02-source-map

(Development environment) source-map: a technique that provides source code to post-build code mapping (if post-build code fails, source code errors can be traced through the mapping)

// Add it to webpack.config.js
devtool: '... '<! --[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map--> <! --source-map: external --> <! Error code exact information and source code error location --> <! -- Inline-source-map: inline --> <! -- Generate only an inline source-map--> <! Error code exact information and source code error location --> <! --hidden-source-map: external --> <! -- Error code error cause, but no error location --> <! -- Can't trace source code errors, can only prompt the error location of the built code --> <! --eval-source-map: inline --> <! -- Each file generates a corresponding source-map, all ineval-- > <! Error code exact information and source code error location --> <! --nosources-source-map: external --> <! -- Error code exact information, but no source code information --> <! --cheap source-map: external --> <! Error code exact information and source code error location --> <! -- can only be exact line --> <! --cheap-module-source-map: external --> <! Error code exact information and source code error location --> <! --moduleAdd loader source map --> <! -- The difference between inline and external:1.External generated file, inline not2.Inline builds are faster --> <! -- Development environment: faster, more debug friendly --> <! -- Fast (eval>inline>cheap>...) -- > <! --eval-cheap-souce-map--> <! --eval-source-map--> <! -- Debug friendlier --> <! -- souce-map--> <! -- cheap-module-souce-map--> <! -- cheap-souce-map--> <! -- -->eval-source-map  / eval-cheap-module-souce-map--> <! Production environment: Should source code be hidden? Debug more friendly --> <! Inlining makes code bigger, so don't use it in production --> <! -- Nosource-source-map all hidden --> <! -- hidden-source-map only hides the source code, and will prompt you with a post-build code error message --> <! -- --> source-map / cheap-module-souce-map-->
Copy the code

03-oneof

Optimize the packaging construction speed of production environment

Only one of the following loaders will match

Note: You cannot have two configurations that handle the same type of file

Oneof causes a file to match only one loader, otherwise multiple matches will be made. You cannot have two configurations that handle the same type of file. Because both eslint-loader and babel-loader match JS files, a loader is placed outside oneof.

 module: {
    rules: [{// In package.json eslintConfig --> Airbnb
        test: /\.js$/,
        exclude: /node_modules/.// Priority execution
        enforce: 'pre'.loader: 'eslint-loader'.options: {
          fix: true}}, {// The following loader will only match one
        // Note: No two configurations can handle the same type of file
        oneOf: [{test: /\.css$/,
            use: [...commonCssLoader]
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader']},/* Normally, only one loader can process a file. When a file is to be processed by multiple Loaders, it is important to specify the order in which loader executes: esLint before Babel */
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader'.options: {
              presets: [['@babel/preset-env',
                  {
                    useBuiltIns: 'usage'.corejs: {version: 3},
                    targets: {
                      chrome: '60'.firefox: '50'}}]]}}, {exclude: /\.(js|css|less|html|jpg|png|gif)/,
            loader: 'file-loader'.options: {
              outputPath: 'media'}}]}]},Copy the code

04 – cache

HMR cache similar to development environment:

  • Babel cache cacheDirectory: true–> makes the second packaged build faster
  • File resource cache
    • Hash: A unique hash value is generated for each Wepack build.
      • Problem: Because JS and CSS use the same hash value. If repackaged, all caches will be invalidated. (Maybe I only changed one file)
    • Chunkhash: Hash value generated by chunk. If the package comes from the same chunk, the hash value is the same
      • Problem: JS and CSS have the same hash value because CSS is introduced in JS, so it belongs to the same chunk
    • Contenthash: Generates hash values based on file contents. Different files must have different hash values -> It is better to put code online and run cache.

// Enable the Babel cache
{
    test: /\.js$/,
    exclude: /node_modules/,
    loader: 'babel-loader'.options: {
      presets: [['@babel/preset-env',
          {
            useBuiltIns: 'usage'.corejs: { version: 3 },
            targets: {
              chrome: '60'.firefox: '50'}}]],// Enable the Babel cache
      // On the second build, the previous cache is read
      cacheDirectory: true}},// File resource cache
  output: {
    filename: 'js/built.[contenthash:10].js'.path: resolve(__dirname, 'build')},Copy the code

05-tree-shaking

Tree shaking: Remove useless code

  • Prerequisites: 1. ES6 modularization must be used. 2
  • Effect: Reduces code size
Configure in package.json"sideEffects": falseProblem: CSS / @babel/polyfill files might get wiped out"sideEffects": ["*.css"."*.less"]
Copy the code

06- Code segmentation

As many files go in as many files go out

 entry: {
    // Multiple entries: There is one entry, and the final output has a bundle
    index: './src/js/index.js'.test: './src/js/test.js'
  },
 output: {
    // [name] : Indicates the name of the file
    filename: 'js/[name].[contenthash:10].js'.path: resolve(__dirname, 'build')},Copy the code

Node_modules can be packaged as a separate chunk of final output

  /* 1. The node_modules code can be packaged separately as a chunk of the final output */
  optimization: {
    splitChunks: {
      chunks: 'all'}},Copy the code

Single entry

// Write the following configuration in a js file to output multiple files
/* Dynamic import syntax: it is possible to package a file separately */
import(/* webpackChunkName: 'test' */'./test')
  .then(({ mul, count }) = > {
    // The file is successfully loaded ~
    // eslint-disable-next-line
    console.log(mul(2.5));
  })
  .catch(() = > {
    // eslint-disable-next-line
    console.log('File load failed ~');
  });
    
Copy the code

07 – lazy loading

Lazy loading ~ : files are loaded only when they are needed ~ Preloading prefetch: js files are loaded in advance before they are used. Normal loading can be considered parallel loading (loading multiple files at the same time) preloading prefetch: Wait for other resources to load, the browser is free, then secretly load resources (preloading compatibility problems are serious)

console.log('index.js file loaded ~');

// import { mul } from './test';

document.getElementById('btn').onclick = function() {
  // Lazy loading ~ : files are loaded only when they are needed
  // Prefetch: preloads the JS file before it is used
  // Normal loading can be considered parallel loading (multiple files are loaded at the same time)
  // Prefetch: Wait until other resources are loaded and the browser is free, then secretly load the resources
  import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) = > {
    console.log(mul(4.5));
  });
};

Copy the code

08-PWA Progressive Web Development Application (offline accessible)

workbox —->workbox-wepack-plugin

webpack.config.js

plugins: [
    new WorkboxWebpackPlugin.GenerateSW({
      2. Delete the old ServiceWorker and generate a Serviceworker profile ~ */
      clientsClaim: true.skipWaiting: true})].Copy the code

Entry JS file configuration


{"env": {"browser": {"env": {"env": Sw code must run on the server --> nodejs --> NPM I serve-g serve-s build start the server, expose all resources in the build directory as static resources */
/ / register serviceWorker
// Handle compatibility issues
if ('serviceWorker' in navigator) {
  window.addEventListener('load'.() = > {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then(() = > {
        console.log('Sw registered successfully ~');
      })
      .catch(() = > {
        console.log('SW registration failed ~');
      });
  });
}
Copy the code

09- Multi-process packaging

Download thread-loader and configure the thread-loader after it for the multiprocess packaging

Enable multi-process packaging. (Pros and cons) Process startup is about 600ms, and process communication has overhead. Multi-process packaging is required only if the work takes a long time

  {
    test: /\.js$/,
    exclude: /node_modules/,   
    use: [
      /* Enable multi-process packaging. Process startup takes about 600ms and process communication is also overhead. Multi-process packaging is required only if the work takes a long time
      {
        loader: 'thread-loader'.options: {
          workers: 2 // Process 2}}, {loader: 'babel-loader'.options: {
          presets: [['@babel/preset-env',
              {
                useBuiltIns: 'usage'.corejs: { version: 3 },
                targets: {
                  chrome: '60'.firefox: '50'}}]],// Enable the Babel cache
          // On the second build, the previous cache is read
          cacheDirectory: true}}},Copy the code

10-externals

Some packages need to be imported using the CDN to prevent packages from being packaged in. Use externals to ignore the package name.

  mode: 'production'.externals: {
    // Refuse to package jQuery
    jquery: 'jQuery'
  }
Copy the code
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
Copy the code

11-dll

Package the code separately

New webpack. DLL. Js

/* Use DLL technology for some libraries (third-party libraries: jquery, React, vue...) When you run webpack, the default is to look for the webpack.config.js configuration file. Requirements: need to run webpack.dll

const { resolve } = require('path');
const webpack = require('webpack');

module.exports = {
  entry: {
    [name] --> jquery
    // ['jquery'] --> The library is jquery
    jquery: ['jquery'],},output: {
    filename: '[name].js'.path: resolve(__dirname, 'dll'),
    library: '[name]_[hash]' // What is the name of the contents exposed in the packaged library
  },
  plugins: [
    // Package to generate a manifest.json --> provide and jquery mapping
    new webpack.DllPlugin({
      name: '[name]_[hash]'.// The exposed content name of the mapping library
      path: resolve(__dirname, 'dll/manifest.json') // Output file path})].mode: 'production'
};

Copy the code

webpack.config.js

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

module.exports = {
  entry: './src/index.js'.output: {
    filename: 'built.js'.path: resolve(__dirname, 'build')},plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    // Tell Webpack which libraries are not included in the package, and change their names when used
    new webpack.DllReferencePlugin({
      manifest: resolve(__dirname, 'dll/manifest.json')}),// Package a file and import the resource automatically in HTML
    new AddAssetHtmlWebpackPlugin({
      filepath: resolve(__dirname, 'dll/jquery.js')})],mode: 'production'
};

Copy the code

Please leave a message if you have any questions!!