• webpack 高级


    高级配置就是要进行 webpack 优化,让代码在编译、运行时性能更好
    主要从以下角度去优化:
    1、提升开发体验
    2、提升打包构建速度
    3、减少代码体积
    4、优化代码运行性能

    一、提升体验

    1、SourceMap

    为什么

    打包出来的所有css和js合并成了一个文件,将代码进行了编译、压缩,多了其他代码。这种情况下,进行 debug 是比较困难的,因为看到的代码不仅是一坨,有的较原代码,还做了编译(如剪头函数转换为了普通函数)。

    是什么

    SourceMap(源代码映射)是一个用来生成源代码和构建代码一一映射的文件的方案。

    SourceMap 会在dist目录生成一个 XX.map 文件,里面包含源代码和构建后的代码没一行、每一列的映射关系。当代码报错时,会通过 XXX.map 文件,从构建后代码出错的位置,找到映射后源代码的出错位置,从而让浏览器提示源代码文件出错的位置,帮助我们更快的找到错误根源。

    怎么用

    //webpack.dev.js 开发模式下
    //优点:打包编译速度快,只包含行映射
    //缺点:没有列映射
    // 其他省略
    module.exports = {
    	mode: "development",
    	devtool: "cheap-module-source-map",
    };
    
    //webpack.prod.js 生产模式下
    //优点:包含行/列映射
    //缺点:打包编译速度更慢
    module.exports = {
      // 其他省略
      mode: "production",
      devtool: "source-map",
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    说明

    1、使用SourceMap会在打包输出目录的对应位置,生产 XX.map 文件
    2、css、js 都会生产 .map 文件
    3、使用 SourceMap 后,在浏览器控制台的 Sources 功能区,可以通过 Command+p 搜索对应的文件 (如main.js、main.css)
    在这里插入图片描述

    二、提升打包构建速度

    1、HotModuleReplacement(HMR/热模块替换)

    是什么

    HotModuleReplacement(HMR/热模块替换):在程序运行中,替换、添加或删除模块,无需重新加载整个页面(刷新页面)。

    只需要在开发环境上配置,生产环境不需要。

    怎么用

    css

    devServer.hot 在webpack5时时默认开启的,

    module.exports = {
      //开发服务器:不会输出资源,在内存中编译打包
      devServer: {
        host: "127.0.0.1",//启动服务器域名
        open: true, //启动服务器端口号
        port: 8000,  //是否自动打开浏览器
        hot: true, // 开启HMR功能(只能用于开发环境,生产环境不需要了)
      },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    js

    HotModuleReplacement 只适用与css,js修改还是会重新加载整个页面。要使js实现该功能,需要在 main.js 增加:

    // main.js
    // 判断是否支持HMR功能
    if (module.hot) {
      module.hot.accept("./js/count.js", function (count) {
      	//js更新后的回调
        const result1 = count(2, 1);
        console.log(result1);
      });
    
      module.hot.accept("./js/sum.js", function (sum) {
      	//js更新后的回调
        const result2 = sum(1, 2, 3, 4);
        console.log(result2);
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    以上修改比较麻烦,实际开发中,也可以使用其他 loader 来解决(如:vue-loader,react-hot-loader)。

    2、OneOf

    为什么

    打包时,每个文件都会经过所有的loader处理,虽然因为test正在原因实际上没有处理,但是都要比对一遍,比较慢。

    是什么

    只要匹配上一个 loader,剩下的就不进行匹配。

    怎么用

    module.exports = {
      module: {
        rules: [
          {
            oneOf: [
            	 {
    		        test: /\.css$/i,  //使用正则匹配.css后缀的文件
    		        //执行顺序:从右到左(从上到下)
    		        use:[
    		          "style-loader", //将js中的css通过创建style标签的方式,添加到html中
    		          "css-loader"  //将css资源编译成commonjs的模块到js中
    		        ]
    		      },
    		      {
    		        test: /\.less$/,
    		        use: [
    		          "style-loader",
    		          "css-loader",
    		          "less-loader" //将less编译成css文件
    		        ]
    		    },
            ]
          }
        ]
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    3、Include/Exclude

    为什么

    开发时的第三方库或插件,不需要再进行编译,可以直接使用,所以在对js文件处理时,要做排除。

    是什么

    • include
      包含,只处理XXX文件
    • exclude
      排除,除了XX文件外,其他文件都处理

    怎么用

    可以使用在loader里面,也可使用在 plugin 中,使用方法是一样的

    //webpack.X.js
    //loader修改
    {
       test: /\.js$/,
       // exclude: /node_modules/, // 排除node_modules代码不编译
       include: path.resolve(__dirname, "../src"), // 也可以用包含
       loader: 'babel-loader',
       // options: {
       //   presets: ['@babel/preset-env']
       // }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4、cache

    为什么

    每次打包时,js文件都要经过Eslint检查和Babel编译,速度比较慢。
    可以缓存之前的Eslint检查和Babel编译结果,这样第二次打包的速度就是更快了。

    是什么

    对Eslint检查和Babel编译结果进行缓存,缓存目录在 node_modules/.cache 下

    怎么用

    //webpack.XXX.js,开发环境、生产环境都可以使用
    //module.rules 下的loader
    {
       test: /\.js$/,
        // exclude: /node_modules/, // 排除node_modules代码不编译
        include: path.resolve(__dirname, "../src"), // 也可以用包含
        loader: 'babel-loader',
        options: {
          // presets: ['@babel/preset-env'],
          cacheDirectory: true,//开启Babel编译缓存
          cacheCompression: false,//缓存文件不要压缩(这里缓存是缓存在本地的)
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    plugins: [
      new ESLintWebpackPlugin({
        // 指定检查文件的根目录
        context: path.resolve(__dirname, "../src"),
        exclude: "node_modules", // 默认值
        cache: true, // 开启缓存
        // 缓存目录
        cacheLocation: path.resolve(
          __dirname,
          "../node_modules/.cache/.eslintcache"
        ),
      })
    ],
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5、Thead 多进程

    为什么

    当项目越来约庞大,打包速度会越来越慢。想要提升打包速度,其实就是提升js的打包速度,因为其他文件比较少。
    对js文件处理主要是 eslint、babel、Terser 三个工具,所以要提升他们的运行速度。
    可以开启多个进程同事处理js文件。

    是什么

    多进程打包:开启电脑的多个进程同事干一件事,速度较快。
    注意:请仅在特别耗时的操作中使用,因为每个进程启动就有大概600ms左右的开销。

    怎么用

    启动经常的数据就是cup的核数
    1、下载包

    $ npm i thread-loader -D
    
    • 1

    2、获取cpu的核数(每个电脑都不一样)

    // nodejs核心模块,直接使用
    const os = require("os")
    //cpu核数
    const threads = os.cpus().length
    
    • 1
    • 2
    • 3
    • 4

    3、js 使用

    //webpack.xxx.js 中,js-loader修改如下:
    {
       test: /\.js$/,
        // exclude: /node_modules/, // 排除node_modules代码不编译
        include: path.resolve(__dirname, "../src"), // 也可以用包含
        use: [
          {
            loader: "thread-loader",
            options: {
              workers: threads,
            }
          },
          {
            loader: 'babel-loader',
            options: {
              // presets: ['@babel/preset-env'],
              cacheDirectory: true,//开启Babel编译缓存
              cacheCompression: false,//缓存文件不要压缩(这里缓存是缓存在本地的)
            }
          }
        ]
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    4、css 使用

    //webpack.xxx.js 中,js-loader修改如下:
    
    const TerserPlugin = require("terser-webpack-plugin")
    
    //css增加进程可以写到 plugin 下面,也可以写到 optimization 下面,效果一样,webpack5推荐写到 optimization 中
    plugins: [
      //plugin的配置
      //将css输出到指定目录
      // new CssMinimizerPlugin(), //压缩css文件
      // new TerserPlugin({
      //   parallel: threads
      // })
    ],
    optimization: {
        minimize: true,
        minimizer: [
          //css压缩不仅可以写到plugin中,也可写到optimization。minimizer中,官方推荐就是这里,效果一样
          new CssMinimizerPlugin(), //压缩css文件
          //生产模式会默认开启TerserPlugin,这里需要进行其他配置,就需要重新写
          new TerserPlugin({
            parallel: threads, //开启多进程
          })
        ]
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    三、减少代码体积

    1、Tree Shaking

    为什么

    开发时定义的一些工具函数,或者饮用的第三方工具函数或组件库,如果没有特殊处理,打包时会引入整个库,但是实际上我们可能只用了极小部分的功能,这样整个库都打包进来,体积会很大。

    是什么

    Tree Shaking是一个属术语,通常用与描述一处 Javascript 中没有使用上的代码。
    注:它依赖 ES Module

    怎么用

    Webpack 已经默认开启了这个功能,无需其他配置。

    2、Babel

    为什么

    Babel 为编译的每个文件都插入了辅助的代码,是代码体积过大。
    Babel 对一些公共方法使用了非常小的辅助代码,比如_extend。默认情况下,会被添加到每一个需要它的文件中。

    是什么

    @babel/plugin-transform-runtime:禁用了 Babel 自动对每个文件的 runtime 注入,而是饮用@babel/plugin-transform-runtime并且使所有辅助代码从这里引用。

    怎么用

    js loader中,增加 plugins: ["@babel/plugin-transform-runtime"]

    //webpack.prod.js
    {
      test: /\.js$/,
      // exclude: /node_modules/, // 排除node_modules代码不编译
      include: path.resolve(__dirname, "../src"), // 也可以用包含
      use: [
        {
          loader: "thread-loader",
          options: {
            workers: threads,
          }
        },
        {
          loader: 'babel-loader',
          options: {
            // presets: ['@babel/preset-env'],
            cacheDirectory: true,//开启Babel编译缓存
            cacheCompression: false,//缓存文件不要压缩(这里缓存是缓存在本地的)
            plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
          }
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3、Image Minimizer

    为什么

    如果项目中引用了较多图片,那么图片体积会比较大,将来请求速度比较慢。
    开发可以对图片进行压缩,减少图片体积。
    注意:如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。

    是什么

    image-minimizer-webpack-plugin:用来压缩图片的插件

    怎么用

    1、下载包

    $ npm i image-minimizer-webpack-plugin imagemin -D
    
    • 1

    还有剩下的包需要下载,分两种模式

    • 无损压缩
    $ npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D
    
    • 1
    • 有损压缩
    $ npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo -D
    
    • 1

    2、配置

    //引入
    const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
    //------------------------
    
    optimization: {
      minimizer: [
        // 压缩图片
        new ImageMinimizerPlugin({
          minimizer: {
            implementation: ImageMinimizerPlugin.imageminGenerate,
            options: {
              plugins: [
                ["gifsicle", { interlaced: true }],
                ["jpegtran", { progressive: true }],
                ["optipng", { optimizationLevel: 5 }],
                [
                  "svgo",
                  {
                    plugins: [
                      "preset-default",
                      "prefixIds",
                      {
                        name: "sortAttrs",
                        params: {
                          xmlnsOrder: "alphabetical",
                        },
                      },
                    ],
                  },
                ],
              ],
            },
          },
        }),
      ],
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    四、优化代码运行性能

    1、Code Split

    为什么

    打包代码时,会将所有的 js 文件打包到一个文件中,体积太大了。如果只要渲染首页,就应该只加载首页的 js 文件,其他文件不应该加载。

    所以需要将打包生产的文件进行代码分割,生成多个 js 文件,渲染哪个页面就只加载某个 js 文件,这样加载的资源少了,速度就更快。

    是什么

    代码分割(Code Split)主要做了两件事:
    1、分割文件:将打包生产的文件进行分割,生产多个 js 文件
    2、按需加载:需要哪个文件就加载哪个文件

    怎么用

    1、创建一个新的目录,目录结构如下(其中 src 是多入口文件):
    在这里插入图片描述

    2、初始化webpack项目,下载包

    $ npm init -y   
    $ npm i webpack webpack-cli html-webpack-plugin -D
    
    • 1
    • 2

    3、安装目录结构新建文件,src中的随便写点东西,主要是 webpack.cofig.js 的配置

    //webpack.config.js
    const path = require("path")
    const HtmlWebpackPlugin = require("html-webpack-plugin")
    
    module.exports = {
      // enrty: "./src/main.js",  //只有一个入口文件,单入口时使用这种方式
      entry: {
        //有多个入口文件,多入口时, entry 要使用对象,
        //对象包含:输出的文件名:入口文件路径
        app: "./src/app.js",
        main: "./src/main.js",
      },
      output: {
        path: path.resolve(__dirname, "dist"),
        filename: "js/[name].js" //webpack命名方式,【name】是enrty中的键名
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, "public/index.html")
        })
      ],
      mode: "production"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4、运行

    $ npx webpack
    
    • 1

    2、Code Split 提取重复代码

    如果多入口文件都引用了同一份代码,我们不希望这份代码被打包到两个文件中,导致代码重复,体积更大。
    我们需要提取多入口文件的重复代码,只打包生产一个 js 文件,其他文件引用它就好。

    //webpack.config.js
    optimization: {
        // 代码分割配置
        splitChunks: {
          chunks: "all", // 对所有模块都进行分割
          // 以下是默认值
          // minSize: 20000, // 分割代码最小的大小
          // minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
          // minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
          // maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
          // maxInitialRequests: 30, // 入口js文件最大并行请求数量
          // enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
          // cacheGroups: { // 组,哪些模块要打包到一个组
          //   defaultVendors: { // 组名
          //     test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
          //     priority: -10, // 权重(越大越高)
          //     reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
          //   },
          //   default: { // 其他没有写的配置会使用上面的默认值
          //     minChunks: 2, // 这里的minChunks权重更大
          //     priority: -20,
          //     reuseExistingChunk: true,
          //   },
          // },
          // 修改配置
          cacheGroups: {
            // 组,哪些模块要打包到一个组
            // defaultVendors: { // 组名
            //   test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
            //   priority: -10, // 权重(越大越高)
            //   reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
            // },
            default: {
              // 其他没有写的配置会使用上面的默认值
              minSize: 0, // 我们定义的文件体积太小了,所以要改打包的最小文件体积
              minChunks: 2,
              priority: -20,
              reuseExistingChunk: true,
            },
          },
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    3、Code Split 按需加载,动态倒入

    场景:页面上有一个按钮,点击按钮的时候加载执行的方法。
    1、修改文件

    • main.js
    import {sum} from "./math"
    // import count from "./count" //普通方式引入方法
    console.log('main');
    console.log(sum(5,6));
    
    document.getElementById("btn").onclick = function() {
      // console.log(count(2,3));
      import('./count.js').then(({count}) => {
        console.log("按需加载了" + count(1,2,3,4,5));
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • public/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>webpack-more-entry</title>
    </head>
    <body>
      哈哈哈哈
      <button id="btn">点击按钮</button>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    第 四 部分功能代码见:链接: https://pan.baidu.com/s/15yzdHnrWIKdo5ixeRdnJcw?pwd=hqtf 提取码: hqtf

    4、Code Split 单入口

    开发时我们可能是单页面应用(SPA),只有一个入口(单入口)。那么我们需要这样配置(主要是optimization.splitChunks.chunks 配置项):

    //webpack.config.js
    const path = require("path")
    const HtmlWebpackPlugin = require("html-webpack-plugin")
    
    module.exports = {
      entry: "./src/main.js",  //只有一个入口文件,单入口时使用这种方式
      // entry: {
      //   //有多个入口文件,多入口时, entry 要使用对象,
      //   //对象包含:输出的文件名:入口文件路径
      //   app: "./src/app.js",
      //   main: "./src/main.js",
      // },
      output: {
        path: path.resolve(__dirname, "dist"),
        filename: "js/[name].js", //webpack命名方式,【name】是enrty中的键名
        clean: true
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, "./public/index.html")
        })
      ],
      mode: "production",
      optimization: {
        // 代码分割配置
        splitChunks: {
         // 对所有模块都进行分割
         //(把 node-modules 相关代码打包成一个文件;
         //把动态倒入配置打包成一个文件)
          chunks: "all", 
        },
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    5、给模块命名

    之前打包出来的文件名都是webpack自动生成的字符串,读起来不太友好。

    • 动态引入时,使用注释语句/* webpackChunkName: "count" */'把名字写进去
      方法:
    // main.js
    import {sum} from "./math"
    // import count from "./count" //普通方式引入方法
    console.log('main');
    console.log(sum(5,6));
    
    document.getElementById("btn").onclick = function() {
      // console.log(count(2,3));
      // /* webpackChunkName: "count" */' webpack魔法命名,以注释的方式写入
      import(/* webpackChunkName: "count" */'./count.js').then(({count}) => {
        console.log("按需加载了" + count(1,2,3,4,5));
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 修改webpack的输出配置(chunkFilename)
    {
      path: path.resolve(__dirname, "dist"),
      filename: "js/[name].js", //webpack命名方式,【name】是enrty中的键名
      chunkFilename: "js/[name].js",  //打包输出的其他文件名
      clean: true
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    6、统一命名配置

    • 文件输出配置项,配置chunk名字以及图片字体等文件资源的名字,统一格式的名字
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "js/[name].js", //webpack命名方式,【name】是enrty中的键名
        chunkFilename: "js/[name].chunk.js",  //动态输出资源命名方式
        assetModuleFilename: "media/[name].[hash][ext]",//图片、字体等资源命名方式
        clean: true
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • css、图片等相关资源的loader中,文件名配置项 generator 去掉
      打包出来的文件如下
      在这里插入图片描述

    2、Preload/Prefetch

    为什么

    前面已经做了代码分割,同时会使用 import 动态倒入语法来进行代码按需加载(也叫懒加载,比如路由懒加载就是这样实现的)。
    但是加载速度还不够好,如:是用户点击按钮才加载这个资源的,如果资源体积很大,那么用户会感到明显的卡顿效果。
    PreloadPrefetch技术,是在浏览器空闲的时间,加载后续需要使用的资源。

    是什么

    • Preload是告诉浏览器立即加载资源
    • Prefetch是告诉浏览器在空闲时,才开始加载资源

    共同点:

    • 都只会加载资源,并不执行
    • 都有缓存

    区别:

    • Preload加载优先级高,Prefetch加载优先级低
    • Preload只能加载当前页面需要使用的资源,Prefetch可以加载当前页面资源,也可以加载下一个页面需要使用的资源

    总结:

    • 当前页面优先级高的资源用Preload加载
    • 下一个页面页面需要使用的资源用Prefetch加载

    问题:兼容性较差,Preload相对于Prefetch兼容性好一点

    怎么用

    • 下载包
    $ npm i @vue/preload-webpack-plugin -D
    
    • 1
    • webpack.config.js 中配置
    plugins: [
      new PreloadWebpackPlugin({
        // rel: "preload",
        // as: "script"
        rel: "prefetch"
      })
    ],
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3、Core-js

    为什么

    在这之前使用的 babel 对 js 代码进行了兼容性处理,其中,使用 @babel/preset-env 智能预设来处理兼容性问题,它能将 ES5 的一些语法进行编译转换,比如剪头函数、三点运算符等。但是如果是 async 函数,promise 对象,数组的一些方法(includes)等,它无法处理。
    所以,此时 js 代码仍然存在兼容性问题,一旦遇到低版本浏览器会直接报错。所以需要将 js 兼容性问题彻底解决。

    是什么

    core-js是专门用来做 ES6 以及以上 API 的polyfill
    polyfill翻译过来叫垫片、补丁。就是用社区上提供的一段代码,让我们在不兼容某些新特性等浏览器上,使用该新特性

    怎么用

    • main.js
    //1、引入core-js下的所以资源,缺点:打出的包会比较大
    // import "core-js"
    //2、按需引入,缺点:手动引入,容易遗漏
    // import "core-js/es/promise"
    //3、自动按需引入,方法:仅需配置 babel.config.js
    
    new Promise(resolve => {
      setTimeout(() => {
        resolve(2)
        console.log("promise");
      }, 1000);
    })
    const arr = [1,2,3,4,5]
    console.log(arr.includes(1));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • babel.config.js
    module.exports = {
      // 智能预设:能够编译ES6语法
      presets: [
        [
          "@babel/preset-env",
          // 按需加载core-js的polyfill
          { 
            useBuiltIns: "usage", 
            corejs: { version: "3.32.2", proposals: true } },
        ],
      ],
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4、PWA

    为什么

    开发 Web App 项目,项目一旦处理网络离线情况,就没发访问了。我们希望给项目提供离线体验。

    是什么

    渐进式网络应用程序(progressive web application - PWA):是一种可以提供类似于 native app(原生应用程序)体验的 Web App 的技术。
    其中最重要的是,在离现象(offline)时,应用程序能够继续运行功能。
    内部是通过 Service Woekers 技术实现的。

    怎么用

    • 下载包
    $ npm i workbox-webpack-plugin -D
    
    • 1
    • webpack.config.js 中增加:
    //引入workbox-webpack-plugin
    const WorkboxPlugin = require("workbox-webpack-plugin");
    //plugin中使用WorkboxPlugin
    plugins: [
      new HtmlWebpackPlugin({
        template: path.resolve(__dirname, "./public/index.html")
      }),
      new PreloadWebpackPlugin({
        // rel: "preload",
        // as: "script"
        rel: "prefetch"
      }),
      new WorkboxPlugin.GenerateSW({
        // 这些选项帮助快速启用 ServiceWorkers
        // 不允许遗留任何“旧的” ServiceWorkers
        clientsClaim: true,
        skipWaiting: true,
      }),
    ],
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • main.js 增加判断
      因为 serviceWorker 具有兼容性问题,这里要加一下判断
    if ("serviceWorker" in navigator) {
      window.addEventListener("load", () => {
        navigator.serviceWorker
          .register("/service-worker.js")
          .then((registration) => {
            console.log("SW registered: ", registration);
          })
          .catch((registrationError) => {
            console.log("SW registration failed: ", registrationError);
          });
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 重新打包,打包出来的目录下多了service-worker.js和workbox-XXX.js
      在这里插入图片描述
      此时如果直接在浏览器中打开 dist/index.html,将浏览器置为 offline,控制台是会报错的(找不到相关服务),这时需要下载 serve
    $ npm i serve -g
    
    • 1

    之后执行启动命令 serve dist,根据输出ip打开即可,此时设置 offline 时,刷新页面,页面内容还是存在的。

    总结

    在这里插入图片描述

    以上代码参考:链接: https://pan.baidu.com/s/1Y9fcso1l-Cyt-eIGKSfqow?pwd=9jh0 提取码: 9jh0

  • 相关阅读:
    linux安装aerospike免安装版
    基础医学概论试题
    [Java Framework] [Spring] Spring Event / 事件的使用 一: ApplicationEvent
    【ElementUI】ElementUI Tooltip 根据内容判断是否显示、文字提示自定义样式
    Unity基于EventSystem让SpriteRenderer支持点击事件
    Nacos配置中心交互模型
    matlab 矩阵逆运算的条件数
    Linux收集内存快照来使用crash分析的方法
    Redis专题-秒杀
    四数之和(LeetCode)
  • 原文地址:https://blog.csdn.net/qq_41604686/article/details/134134126