webpack基础学习,各个loader和plugin的具体配置

news2024/11/29 6:34:17

一、邂逅Webpack

Webpack是什么

webpack是一个静态的模块化打包工具,为现代的JavaScript应用程序;

  • 打包bundler:webpack可以将帮助我们进行打包,所以它是一个打包工具

  • 静态的static:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器);

  • 模块化module:webpack默认支持各种模块化开发,ES Module、CommonJS、AMD等;

  • 现代的modern:我们前端说过,正是因为现代前端开发面临各种各样的问题,才催生了webpack的出现和发展;

二、webpack配置和css处理

webpack配置文件

1、出口、入口的配置

我们可以在根目录下创建一个webpack.config.js文件,来作为webpack的配置文件:

module.exports = {
    entry: " 指定入口路径",
    output: {
        filename:"bundle.js", // 出口名字
        path: '出口路径'
    }
}

2、css-loader的使用

loader是什么

  • loader 可以用于对模块的源代码进行转换;

  • 我们可以将css文件也看成是一个模块,我们是通过import来加载这个模块的;

  • 在加载这个模块时,webpack其实并不知道如何对其进行加载,我们必须制定对应的loader来完成这个功能;

module.rules的配置如下:

  • test属性:用于对resource(资源)进行匹配的,通常会设置成正则表达式;

  • use属性:对应的值时一个数组:[UseEntry]

    • UseEntry是一个对象,可以通过对象的属性来设置一些其他属性

      • loader:必须有一个loader属性,对应的值是一个字符串;

      • options:可选的属性,值是一个字符串或者对象,值会被传入到loader中;

      • query:目前已经使用options来替代;

    • 传递字符串(如:use: [ 'style-loader' ])是loader 属性的简写方式(如:use: [ { loader: 'style-loader'} ])

  • loader属性:Rule.use: [ { loader } ] 的简写。

module.exports = {
    entry: " 指定入口路径",
    output: {
        filename:"bundle.js", // 出口名字
        path: '出口路径'
    },
    module: {
        rules: [
            {
                test:/\.css$/,
                // loader:"css-loader" // 写法一
                // use:["css-loader"]   //写法二
                // 写法三
                use:[
                    {loader:"css-loader"}
                ]
            }
        ]
    }
}

3、style-loader

当我们通过css-loader来加载css文件时,代码没有生效。这是因为css-loader只是将.css文件进行解析,并不会将解析之后的css插入到页面中,而style-loader将完成插入style的操作

注意:因为loader的执行顺序是从右向左(或者说从下到上,或者说从后到前的),所以我们需要将styleloader写到css-loader的前面

        use:[
                    {loader:"style-loader"},
                    {loader:"css-loader"}
                ]

4、less-loader

        use:[
                    {loader:"style-loader"},
                    {loader:"css-loader"}
                    {loader:"less-loader"}
            ]

5、浏览器的兼容性

认识browserslist工具

  • Browserslist编写规则一:

    • defaults:Browserslist的默认浏览器(> 0.5%, last 2 versions, Firefox ESR, not dead)。

    • 5%:通过全局使用情况统计信息选择的浏览器版本。>=,<和<=工作过。

    • dead:24个月内没有官方支持或更新的浏览器。现在是IE 10,IE_Mob11,BlackBerry 10,BlackBerry 7,Samsung 4和OperaMobile12.1。

    • last 2 versions:每个浏览器的最后2个版本。

配置browserslist

  • 方案一:在package.json中配置;

    "browserslist": [
         "last 2 version",
         "not dead",
         "> 0.2%"
    ]

  • 方案二:单独的一个配置文件.browserslistrc文件;

     last 2 version
     not dead
     > 0.2%

6、认识postCss工具

PostCSS是一个通过JavaScript来转换样式的工具,这个工具可以帮助我们进行一些CSS的转换和适配,比如自动添加浏览器前缀、css样式的重置;

如何使用

安装工具:postcss、postcss-cli

npm install postcss postcss-cli -D

插件autoprefixer

添加浏览器前缀需要安装autoprefixer

npm install autoprefixer -D

直接使用使用postcss工具,并且制定使用autoprefixer

npx postcss --use autoprefixer -o end.css ./src/css/style.css

postcss-loader

  • 借助构建工具进行css处理

npm install postcss-loader -D
 {
  loader:"postcss-loader",
  options: {
   postcssOptions: {
    plugins: [
     require('autoprefixer')
    ]
   }
  }
 },
  • 单独的postcss配置

在跟目录下创建postcss.config.js

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}
  • postcss-preset-env

在项目中配置postcss-loader时,我们一般不使用autoprefixer。而是使用另一插件postcss-preset-env

  • postcss-preset-env也是一个postcss的插件;

  • 它可以帮助我们将一些现代的CSS特性,转成大多数浏览器认识的CSS,并且会根据目标浏览器或者运行时环境添加所需的polyfill;

  • 也包括会自动帮助我们添加autoprefixer(所以相当于已经内置了autoprefixer);

安装

npm install postcss-preset-env -D

使用

module.exports = {
    plugins: [
        require('postcss-preset-env')
    ]
}

三、加载和处理其他资源

1、file-loader

用来处理jpg、png等格式的图片

  • file-loader的作用就是帮助我们处理import/require()方式引入的一个文件资源,并且会将它放到我们输出的文件夹中;

安装

npm install file-loader -D

配置:

        {
              test:/\.(png|jpe?g|svg|gif)$/i,
              use: {
                  loader: "file-loader"
              }  
            }

1、文件名称规则

对处理后的文件名称按照一定的规则进行显示,一般使用PlaceHolders来完成,webpack给我们提供了大量的PlaceHolders来显示不同的内容:

介绍几个最常用的placeholder:

  • [ext]:处理文件的扩展名;

  • [name]:处理文件的名称;

  • [hash]:文件的内容,使用MD4的散列函数处理,生成的一个128位的hash值(32个十六进制);

  • [contentHash]:在file-loader中和[hash]结果是一致的(在webpack的一些其他地方不一样,后面会讲到);

  • [hash:<length>]:截图hash的长度,默认32个字符太长了;

  • [path]:文件相对于webpack配置文件的路径;

2、设置文件名称和存放路径

        {
              test:/\.(png|jpe?g|svg|gif)$/i,
              use: {
                  loader: "file-loader"
                  options: {
                    name: "img/[name].[hash:8].[ext]",
                    outputPath: "img"
                  }
              }  
            }

2、url-loader

将较小的文件转换为base64的URI

安装:

npm install url-loader -D

配置:

    {
          test:/\.(png|jpe?g|svg|gif)$/i,
          use: {
              loader: "url-loader"
              options: {
                name: "img/[name].[hash:8].[ext]",
                outputPath: "img"
              }
          }  
        }

打包之后的显示结果跟file-loader一样,但是在打包好的dist文件夹中,看不到图片文件,而是转换为base64格式存储。

limit属性

限制转换base64格式的图片大小(比如小于100kb)

    {
          test:/\.(png|jpe?g|svg|gif)$/i,
          use: {
              loader: "url-loader"
              options: {
                limit:100 * 1024,
                name: "img/[name].[hash:8].[ext]",
                outputPath: "img"
              }
          }  
        }

3、asset module type

1、介绍

  • webpack5之前,加载这些资源我们需要使用一些loader,比如raw-loader 、url-loader、file-loader

  • webpack5之后,我们可以直接使用资源模块类型(asset module type),来替代上面的这些loader;

资源模块类型(asset module type),通过添加4 种新的模块类型,来替换所有这些loader

  • asset/resource发送一个单独的文件并导出URL。之前通过使用file-loader 实现

  • asset/inline导出一个资源的data URI。之前通过使用url-loader 实现;

  • asset/source导出资源的源代码。之前通过使用raw-loader 实现;

  • asset在导出一个data URI 和发送一个单独的文件之间自动选择。之前通过使用url-loader,并且配置资源体积限制实现;

2、使用

      {
        test: /\.(png|jpe?g|svg|gif)$/i,
        type: "asset/resource",
      },
  • 如何自定义文件的输出路径和文件名

方式一:修改output,添加assetModuleFilename属性;

  output: {
    filename: "bundle.js", // 出口名字
    path: "出口路径",
    assetModuleFilename:"img/[name].[hash:6][ext]"
  },
方式二:在Rule中,添加一个generator属性,并且设置filename;    
            {
        test: /\.(png|jpe?g|svg|gif)$/i,
        type: "asset/resource",
        generator: {
          filename: "img/[name].[hash:6][ext]",
        },
      },
  • url-loader中的limit限制图片大小效果

           {
        test: /\.(png|jpe?g|svg|gif)$/i,
        type: "asset",   // 注意
        generator: {
          filename: "img/[name].[hash:6][ext]",
        },
        parser: {
            dataUrlCondition: {
                maxSize: 100 *1024
            }
        }
      },

4、加载字体文件

处理特殊字体或者字体图标的使用

我们可以选择使用file-loader来处理,也可以选择直接使用webpack5的资源模块类型来处理;

           {
        test: /\.(woff2?|eot|ttf)$/,
        type: "asset/resource",
        generator: {
          filename: "img/[name].[hash:6][ext]",
        },
      },

四、认识plugin

  • Loader是用于特定的模块类型进行转换;

  • Plugin可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等;

1、CleanWebpackPlugin

每次修改了一些配置,重新打包时,都需要手动删除dist文件夹,CleanWebpackPlugin可以帮助我们完成这个功能。

安装:

npm install clean-webpack-plugin -D

配置:

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

module.exports = {
    plugins : [
        new CleanWebpackPlugin()
    ]
  };

2、HtmlWebpackPlugin

HtmlWebpackPlugin用来对HTML进行打包处理

安装:

npm install html-webpack-plugin -D

配置:

const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      titile: "webpack案例",
    }),
  ],
};

3、自定义HTML模板

如果我们想在自己的模块中加入一些比较特别的内容:

  • 添加一个noscript标签,在用户的JavaScript被关闭时,给予响应的提示;

  • 比如在开发vue或者react项目时,我们需要一个可以挂载后续组件的根标签<div id="app"></div>;

自定义模板数据填充

上面的代码中,会有一些类似这样的语法<%变量%>,这个是EJS模块填充数据的方式。

在配置HtmlWebpackPlugin时,我们可以添加如下配置:

  • template:指定我们要使用的模块所在的路径;

  • title:在进行htmlWebpackPlugin.options.title读取时,就会读到该信息;

const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      titile: "webpack案例",
      template: "./public/index.html"
    }),
  ],
};

4、DefinePlugin的介绍

当在我们的模块中还使用到一个BASE_URL的常量,我们需要设置这个常量,这个时候我们可以使用DefinePlugin插件;

使用:

DefinePlugin允许在编译时创建配置的全局常量,是一个webpack内置的插件(不需要单独安装):

const { DefinePlugin } = require("webpack");
module.exports = {
  plugins: [
    new DefinePlugin({
        BASE_URL:'"./"'  // 注意需要多一层包裹
    })
  ],
};

5、CopyWebpackPlugin

vue的打包过程中,如果我们将一些文件放到public的目录下,那么这个目录会被复制到dist文件夹中。这个复制的功能,我们可以使用CopyWebpackPlugin来完成;

安装:

npm install copy-webpack-plugin -D

配置:

  • from:设置从哪一个源中开始复制;

  • to:复制到的位置,可以省略,会默认复制到打包的目录下;

  • globOptions:设置一些额外的选项,其中可以编写需要忽略的文件:

    • .DS_Store:mac目录下回自动生成的一个文件;

    • index.html:也不需要复制,因为我们已经通过HtmlWebpackPlugin完成了index.html的生成;

    new CopyWebpackPlugin({
        patterns: [
            {
                from:"public",
                globOptions: {
                    ignore: [
                        '**/.DS_Store',
                        '**/index.html'
                    ]
                }
            }
        ]
    })

五、source-map

source-map是从已转换的代码,映射到原始的源文件。使浏览器可以重构原始源并在调试器中显示重建的原始源

使用:

第一步:根据源文件,生成source-map文件,webpack在打包时,可以通过配置生成source-map;

第二步:在转换后的代码,最后添加一个注释,它指向sourcemap;

//# sourceMappingURL=common.bundle.js.map

浏览器会根据我们的注释,查找响应的source-map,并且根据source-map还原我们的代码,方便进行调试。

分析source-map

  • version:当前使用的版本,也就是最新的第三版;

  • sources:从哪些文件转换过来的source-map和打包的代码(最初始的文件);

  • names:转换前的变量和属性名称(因为我目前使用的是development模式,所以不需要保留转换前的名称);

  • mappings:source-map用来和源文件映射的信息(比如位置信息等),一串base64VLQ(veriablelengthquantity可变长度值)编码;

  • file:打包后的文件(浏览器加载的文件);

  • sourceContent:转换前的具体代码信息(和sources是对应的关系);

  • sourceRoot:所有的sources相对的根目录;

生成source-map

webpack为我们提供了非常多的选项,目前为止是26个,来处理source-map,选择不同的值,打包形成的代码会有性能的差异,可以根据不同情况进行选择

  • 不会生成source-map的配置项

    • false:不使用source-map,也就是没有任何和source-map相关的内容。

    • nnone:production模式下的默认值,不生成source-map。

    • eval:development模式下的默认值,不生成source-map

      • 但是它会在eval执行的代码中,添加//#sourceURL=;

      • 它会被浏览器在执行时解析,并且在调试面板中生成对应的一些文件目录,方便我们调试代码;

source-map值

生成一个独立的source-map文件,并且在bundle文件中有一个注释,指向source-map文件;

bundle文件中有如下的注释:

//# sourceMappingURL=bundle.js.map

eval-source-map值

eval-source-map:会生成sourcemap,但是source-map是以DataUrl添加到eval函数的后面

inline-source-map值

inline-source-map:会生成sourcemap,但是source-map是以DataUrl添加到bundle文件的后面

cheap-source-map

cheap-source-map:

  • 会生成sourcemap,但是会更加高效一些(cheap低开销),因为它没有生成列映射(Column Mapping)

cheap-module-source-map值

会生成sourcemap,类似于cheap-source-map,但是对源自loader的sourcemap处理会更好。

hidden-source-map值

  • 会生成sourcemap,但是不会对source-map文件进行引用;

  • 相当于删除了打包文件中对sourcemap的引用注释;

//  被删除掉的
//# sourceMappingURL=bundle.js.map

nosources-source-map值

会生成sourcemap,但是生成的sourcemap只有错误信息的提示,不会生成源代码文件;

多个值的组合(重要)

事实上,webpack提供给我们的26个值,是可以进行多组合的。

组合的规则如下:

  • inline-|hidden-|eval:三个值时三选一;

  • nosources:可选值;

  • cheap可选值,并且可以跟随module的值;

    [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

在开发中,最佳的实践是什么呢?

  • 开发阶段:推荐使用source-map或者cheap-module-source-map

  • 测试阶段:推荐使用source-map或者cheap-module-source-map

  • 发布阶段:false、缺省值(不写)

六、Babel深入理解

1、babel是什么东西,用来做什么的

  • Babel是一个工具链,主要用于旧浏览器或者缓解中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript;

  • 语法转换、源代码转换、Polyfill实现目标缓解缺少的功能等;

Babel命令行使用

  • @babel/core:babel的核心代码,必须安装;

  • @babel/cli:可以让我们在命令行使用babel;

npm install @babel/cli @babel/core

使用babel来处理我们的源代码:

  • src:是源文件的目录;

  • --out-dir:指定要输出的文件夹dist;

npx babel src--out-dirdist

插件的使用

比如我们需要转换箭头函数,那么我们就可以使用箭头函数转换相关的插件:

npm install @babel/plugin-transform-arrow-functions -D
npx babel src--out-dirdist--plugins=@babel/plugin-transform-arrow-functions

查看转换后的结果,我们会发现const 并没有转成var,这是因为plugin-transform-arrow-functions,并没有提供这样的功能,我们需要使用plugin-transform-block-scoping 来完成这样的功能。

npm install @babel/plugin-transform-block-scoping -D
npx babel src--out-dirdist--plugins=@babel/plugin-transform-block-scoping @babel/plugin-transform-arrow-functions

Babel的预设preset

如果要转换的内容过多,一个个设置是比较麻烦的,我们可以使用预设(preset)

安装 :

npm install @babel/preset-env -D

执行:

npx babel src--out-dirdist--presets=@babel/preset-env

2、Babel的底层原理

工作流程:

  • 解析阶段(Parsing)

  • 转换阶段(Transformation)

  • 生成阶段(CodeGeneration)

流程图:

3、babel-loader

安装:

npm install babel-loader @babel/core      

使用:

module.exports = {
    module: {
        rules: [
            {
                test:/\.js$/,
                use: {
                    loader: "babel-loader"
                }
            }
        ]
    }
}

指定使用的插件

我们必须指定使用的插件才会生效

module: {
        rules: [
            {
                test:/\.js$/,
                use: {
                    loader: "babel-loader",
                    options: {
                        plugins: [
                            "@babel/plugin-transform-block-scoping",
                            "@babel/plugin-transform-arrow-functions"
                        ]
                    }
                }
            }
        ]
    }

babel-preset

如果我们一个个去安装使用插件,那么需要手动来管理大量的babel插件,我们可以直接给webpack提供一个preset,webpack会根据我们的预设来加载对应的插件列表,并且将其传递给babel。

常见的预设:

  • env

  • react

  • TypeScript

安装preset-env:

npm install @babel/preset-env
  {
  test:/\.js$/,
      use: {
        loader: "babel-loader",
         options: {
            plugins: [
              "@babel/plugin-transform-block-scoping",
                "@babel/plugin-transform-arrow-functions"
           ]
         }
     }
  
}

Babel的Stage-X设置

在babel7之前(比如babel6中),我们会经常看到这种设置方式:

  • 它表达的含义是使用对应的babel-preset-stage-x预设;

  • 从babel7开始,已经不建议使用了,建议使用preset-env来设置;

4、Babel的配置文件

我们可以将babel的配置信息放到一个独立的文件中,babel给我们提供了两种配置文件的编写:

  • babel.config.json(或者.js,.cjs,.mjs)文件;

  • .babelrc.json(或者.babelrc,.js,.cjs,.mjs)文件;

区别:

  • .babelrc.json:早期使用较多的配置方式,但是对于配置Monorepos项目是比较麻烦的;

  • babel.config.json(babel7):可以直接作用于Monorepos项目的子包,更加推荐;

5、认识polyfill

更像是应该填充物(垫片),一个补丁,可以帮助我们更好的使用JavaScript;

使用场景:

比如我们使用了一些语法特性(例如:Promise,Generator,Symbol等以及实例方法例如Array.prototype.includes等),但是某些浏览器压根不认识这些特性,必然会报错,我们可以使用polyfill来填充或者说打一个补丁,那么就会包含该特性了;

可以通过单独引入core-js和regenerator-runtime来完成polyfill的使用:

npm install core-js regenerator-runtime --save
{
	test:/\.m?js$/,
	exclude:/node_modules/,
	use:"babel-loader"
}

配置babel.config.js

我们需要在babel.config.js文件中进行配置,给preset-env配置一些属性:

  • useBuiltIns:设置以什么样的方式来使用polyfill;

  • corejs:设置corejs的版本

    • 另外corejs可以设置是否对提议阶段的特性进行支持;

    • 设置proposals属性为true即可;

useBuiltIns属性设置

  • useBuiltIns属性有三个常见的值

    第一个值:false

    • 打包后的文件不使用polyfill来进行适配;

    • 并且这个时候是不需要设置corejs属性的;

    第二个值:usage

    • 会根据源代码中出现的语言特性,自动检测所需要的polyfill;

    • 这样可以确保最终包里的polyfill数量的最小化,打包的包相对会小一些;

    • 可以设置corejs属性来确定使用的corejs的版本;

    第三个值:entry

    • 如果我们依赖的某一个库本身使用了某些polyfill的特性,但是因为我们使用的是usage,所以之后用户浏览器可能会报错,果你担心出现这种情况,可以使用entry;

    • 需要在入口文件中添加`import 'core-js/stable'; import 'regenerator-runtime/runtime';

    • 这样做会根据browserslist目标导入所有的polyfill,但是对应的包也会变大;

6、认识Plugin-transform-runtime(了解)

在前面我们使用的polyfill,默认情况是添加的所有特性都是全局的,如果我们正在编写一个工具库,这个工具库需要使用polyfill,别人在使用我们工具时,工具库通过polyfill添加的特性,可能会污染它们的代码,所以,当编写工具时,babel更推荐我们使用一个插件:@babel/plugin-transform-runtime来完成polyfill的功能;

7、React的jsx支持

安装:

npm install @babel/preset-react -D

使用:

presets: [
	["@babel/preset-env", {
		useBuiltIns:"usage",
		corejs: 3.8
	}],
	["@babel/preset-react"]
]

8、TypeScript的编译

TypeScript通过compiler来转换成JavaScript

安装:

npm install typescript -D

TypeScript的编译配置信息我们通常会编写一个tsconfig.json文件:

tsc --init

之后我们可以运行npxtsc来编译自己的ts代码:

npx tsc

1、使用ts-loader编译TS

安装:

npm install ts-loader -D

配置:

{
	test:'/\.ts$/',
	exclude: /node_modules/,
	use: [
		"ts-loader"
	]
}

2、使用babel-loader编译TS

Babel是有对TypeScript进行支持

  • 我们可以使用插件:@babel/tranform-typescript;

  • 但是更推荐直接使用preset:@babel/preset-typescript;

安装:

npm install @babel/preset-typescript -D

配置:

{
    test:'/\.ts$/',
    exclude: /node_modules/,
    use: [
        "babel-loader"
    ]
}

七、大数据中关于代码格式校验(Eslint和prettierrc )

大数据中关于eslint的配置

/*
 * @Description: eslint 配置
 * @ 规则依赖于 @umijs/fabric,在此基础上,可自行添加自己的规则进行配置
 * @Author: 贾永昌
 * @Date: 2022-05-01 13:55:14
 * @LastEditTime: 2022-05-02 17:35:45
 */
module.exports = {
  extends: [require.resolve('@umijs/fabric/dist/eslint')],
​
  // in antd-design-pro
  globals: {
    ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
    page: true,
  },
​
  rules: {
    // 强制语句有分号结尾
    semi: [2, 'always'],
    // ? 操作符前后必须有空格 bad: 1||2  good: 1 || 2
    'space-infix-ops': 2,
    // ? 对象字面量中冒号前面禁止有空格,后面必须有空格 bad: {a :'a'} good:{a: 'a'}
    'key-spacing': 2,
    // ? 花括号首尾必须有空格
    'object-curly-spacing': [2, 'always'],
    // ? 语句块(if、function、class、try...catch等的大括号) 的前面必须要有空格
    'space-before-blocks': 2,
    // ? 箭头函数的箭头与后面的{}之间需要空格
    'arrow-spacing': 2,
    // ? 禁止多余的空格
    'no-multi-spaces': 2,
    // ? 禁止代码行结束后面有多余空格
    'no-trailing-spaces': 2,
    // ? 禁止多余空行
    'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 1, maxEOF: 1 }],
    // ? 允许标识符中使用悬空下划线(标识符的开头或末尾的下划线)
    'no-underscore-dangle': 0,
    // ? 允许逻辑短路、三元运算符等表达式求值
    'no-unused-expressions': 0,
    // ? 禁止使用嵌套的三元表达式
    'no-nested-ternary': 2,
    // ? 禁止对函数参数再赋值(保证react函数式编程纯函数的概念)
    'no-param-reassign': 2,
    // ? 禁止使用 var 定义变量
    'no-var': 2,
    // ? 禁止修改const声明的变量
    'no-const-assign': 2,
    // ? 函数调用时 函数名与()之间不能有空格
    'no-spaced-func': 2,
​
    // ? jsx 属性中强制使用双引号
    'jsx-quotes': [2, 'prefer-double'],
    // ? 禁止 jsx 属性对象的引用括号里 两边加空格
    'react/jsx-curly-spacing': [2, 'never'],
    // ? JSX 中前标签传有属性换行展示的话,其后面的 > 也需换行对齐展示
    'react/jsx-closing-bracket-location': 2,
    // ? 校验 jsx 中所有换行属性值缩进
    'react/jsx-indent-props': [2, 2],
    // ? jsx 中传入属性值是Boolean值且为true时,省略传入
    'react/jsx-boolean-value': 2,
    // ? 在 JSX 属性中禁止等号前后存在空格
    'react/jsx-equals-spacing': 2,
​
    // ? 关闭此规则,允许 useEffect 的依赖为空数组
    'react-hooks/exhaustive-deps': 0,
​
    // ? 未使用的变量警告提醒
    '@typescript-eslint/no-unused-vars': ['warn'],
    // ? 禁用使用在前,保证 useEffct 使用在最前面,这时候里面如果使用了外部的函数就会报这错
    '@typescript-eslint/no-use-before-define': 0,
    // ? 允许空的 ts 接口定义  eg: interface IProps {}
    '@typescript-eslint/no-empty-interface': 0,
  },
};
大数据中 .prettierrc 配置
{
  "printWidth": 80,
  "tabWidth": 2,
  "singleQuote": true,
  "useTabs": false,
  "semi": true,
  "jsxSingleQuote": false,
  "trailingComma": "all",
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "arrowParens": "always",
  "requirePragma": false,
  "insertPragma": false,
  "proseWrap": "preserve", 
  "htmlWhitespaceSensitivity": "css",
  "overrides": [
    {
      "files": ".prettierrc",
      "options": { "parser": "json" }
    }
  ]
}

八、DevServer

为什么需要搭建本地服务器?

我们希望可以做到,当文件发生变化时,可以自动完成编译和展示

  • webpack watch mode

  • webpack-dev-server

  • webpack-dev-middleware

1、Webpack watch(基本不用)

webpack给我们提供了watch模式:

  • 在该模式下,webpack依赖图中的所有文件,只要有一个发生了更新,那么代码将被重新编译(损耗性能)

开启watch的两种方式

  • 方式一:在导出的配置中,添加watch: true;

  • 方式二:在启动webpack的命令中,添加--watch的标识;

"scripts" : {
	"watch":"webpack --watch"
}

2、webpack-dev-server(必会,常用)

除了可以监听到文件的变化,还可以具备实时重新加载的功能

安装:

npm install --save-dev webpack-dev-server

配置:

"scripts" : {
	"watch":"webpack --watch"
	"serve":"webpack serve --config wk.config.js"
}

webpack-dev-server 在编译之后不会写入到任何输出文件。而是将bundle 文件保留在内存中:

  • 事实上webpack-dev-server使用了一个库叫memfs(memory-fswebpack自己写的)

3、webpack-dev-middleware(基本不用)

如果我们想要有更好的自由度,可以使用webpack-dev-middleware;

定义:

webpack-dev-middleware 是一个封装器(wrapper),它可以把webpack处理过的文件发送到一个server,webpack-dev-server 在内部使用了它,然而它也可以作为一个单独的package 来使用,以便根据需求进行更多自定义设置;

4、output的publicPath(outPut中的配置)

output中还有一个publicPath属性,该属性是指定index.html文件打包引用的一个基本路径

  • 它的默认值是一个空字符串,所以我们打包后引入js文件时,路径是bundle.js;

  • 在开发中,我们也将其设置为/,路径是/bundle.js,那么浏览器会根据所在的域名+路径去请求对应的资源;

  • 如果我们希望在本地直接打开html文件来运行,会将其设置为./,路径时./bundle.js,可以根据相对路径去查找资源;

    module.exports = {
        entry: " 指定入口路径",
        output: {
            filename:"bundle.js", // 出口名字
            path: '出口路径'
            publicPath:'./'
        }
    }

5、devServer的publicPath

devServer中也有一个publicPath的属性,该属性是指定本地服务所在的文件夹

  • 它的默认值是/,也就是我们直接访问端口即可访问其中的资源http://localhost:8080

  • 如果我们将其设置为了/abc,那么我们需要通过http://localhost:8080/abc才能访问到对应的打包后的资源

  • 并且这个时候,我们其中的bundle.js通过http://localhost:8080/bundle.js也是无法访问的:

    • 所以必须将output.publicPath也设置为/abc;

    • 官方其实有提到,建议devServer.publicPath与output.publicPath相同

6、devServer的contentBase(不常用)

主要作用是如果我们打包后的资源,又依赖于其他的一些资源,那么就需要指定从哪里来查找这个内容

  • 比如在index.html中,我们需要依赖一个abc.js文件,这个文件我们存放在public文件中

  • 在index.html中,我们应该如何去引入这个文件

    • 比如代码是这样的:<script src="./public/abc.js"></script>

    • 但是这样打包后浏览器是无法通过相对路径去找到这个文件夹的;

    • 所以代码是这样的:<script src="/abc.js"></script>;

    • 但是我们如何让它去查找到这个文件的存在呢?设置contentBase即可

devserver: {
 contentBase: path.resolve(__dirname,"why"),
 watchContentBase:true   //监听contentBase发生变化后重新编译
}

7、hotOnly、hos、port、open、compress配置

  • hotOnly是当代码编译失败时,是否刷新整个页面

  • port设置监听的端口,默认情况下是8080

  • host设置主机地址

  • open是否打开浏览器

  • compress是否为静态文件开启gzip compression

devserver: {
 	contentBase: path.resolve(__dirname,"why"),
	watchContentBase:true,   //监听contentBase发生变化后重新编译
 	hotOnly:true,
 	host: 0.0.0.0,
 	port: 3000,
 	open: true,
 	compress:true
}

8、Proxy代理(解决跨域问题)注意:在开发环境中使用

我们可以将请求先发送到一个代理服务器,代理服务器和API服务器没有跨域的问题,就可以解决我们的跨域问题了

配置:

  • target:表示的是代理到的目标地址,比如/api-hy/moment会被代理到http://localhost:8888/api-hy/moment;

  • pathRewrite:默认情况下,我们的/api-hy也会被写入到URL中,如果希望删除,可以使用pathRewrite;

  • secure:默认情况下不接收转发到https的服务器上,如果希望支持,可以设置为false;

  • changeOrigin:它表示是否更新代理后请求的headers中host地址;

  devserver: {
    '/api': {
      // 标识需要进行转换的请求的url
      target: 'http://172.16.188.188:8000', // 服务端域名
      changeOrigin: true, // 允许域名进行转换
      pathRewrite: {
        // 将请求url里的ci去掉
        '^/api': '',
      },
      logLevel: 'debug',
      secure: false, // 将该属性设置为false,将允许在https上运行或者运行在证书无效的后端服务器
    },
  },

9、historyApiFallback

  • historyApiFallback是开发中一个非常常见的属性,它主要的作用是解决SPA页面在路由跳转之后,进行页面刷新时,返回404的错误。

  • boolean值:默认是false

    • 如果设置为true,那么在刷新时,返回404错误时,会自动返回index.html的内容;

  • object类型的值,可以配置rewrites属性:

    • 可以配置from来匹配路径,决定要跳转到哪一个页面;

  devserver: {
    '/api': {
      // 标识需要进行转换的请求的url
      target: 'http://172.16.188.188:8000', // 服务端域名
      changeOrigin: true, // 允许域名进行转换
      pathRewrite: {
        // 将请求url里的ci去掉
        '^/api': '',
      },
      logLevel: 'debug',
      secure: false, // 将该属性设置为false,将允许在https上运行或者运行在证书无效的后端服务器
    },
    historyApiFallback: {
        rewrites:[
            {from: /abc/, to:"/index.html"}
        ]
    }
  },

九、模块热替换(HMR)

什么是HMR

  • HMR的全称是Hot Module Replacement,翻译为模块热替换;

  • 模块热替换是指在应用程序运行过程中,替换、添加、删除模块,而无需重新刷新整个页面;

如何使用HMR

  • 默认情况下,webpack-dev-server已经支持HMR,我们只需要开启即可;

  • 在不开启HMR的情况下,当我们修改了源代码之后,整个页面会自动刷新,使用的是live reloading;

1、开启HMR

// 在webpack.config.js 中添加以下配置
devserver: {
    hot:true
}

同时还需要指定发生更新的模块

if(module.hot) {
    module.hot.accept("./*文件路径",() => {
        console.log()
    })
}

2、框架中的HMR

项目中已经有非常成熟的方案,别操心了

  • vue开发中,我们使用vue-loader,此loader支持vue组件的HMR,提供开箱即用的体验

  • react开发中,有React HotLoader,实时调整react组件(目前React官方已经弃用了,改成使用reactrefresh);

3、HMR的原理

HMR的原理是什么

  • webpack-dev-server会创建两个服务:提供静态资源的服务(express)和Socket服务(net.Socket)

  • express server负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析);

HMR Socket Server,是一个socket的长连接:(想想webSocket,需要及时通信)

  • 长连接有一个最好的好处是建立连接后双方可以通信(服务器可以直接发送文件到客户端)

  • 当服务器监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js文件(update chunk);

  • 通过长连接,可以直接将这两个文件主动发送给客户端(浏览器)

  • 浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新;

十、resolve模块解析

resolve用于设置模块如何被解析:

  • resolve可以帮助webpack从每个require/import 语句中,找到需要引入到合适的模块代码;

  • webpack 使用enhanced-resolve来解析文件路径;

webpack能解析三种文件路径:

  • 绝对路径

  • 相对路径

  • 模块路径:在resolve.modules中指定的所有目录检索模块,默认值是['node_modules'],所以默认会从node_modules中查找文件;

1、extensions和alias配置

extensions是解析到文件时自动添加扩展名:

  • 默认值是['.wasm','.mjs','.js','.json'];

    配置:

    module.exports = {
        entry: " 指定入口路径",
        output: {
            filename:"bundle.js", // 出口名字
            path: '出口路径'
        },
        resolve:{
        	extensions:['.wasm','.mjs','.js','.json','.jsx','.ts'],
        }
    }

我们可以使用alias给某些常见的路径起一个别名;

    resolve:{
    	extensions:['.wasm','.mjs','.js','.json','.jsx','.ts'],
    	alias: {
    		"@":resolveApp('./src'),
    		pages:resolveApp('./src/pages')
    	}
    }

十一、环境分离和代码分离

1、入口文件解析

context的作用是用于解析入口(entry point)和加载器(loader)

默认是webpack的启动目录

module.exports = {
	context:path.resolve(__dirname,'./')
	entry:"../src/index.js"
}

2、配置文件的分离

  • 将原来的webpack.config.js划分为webpack.comm.conf.js(通用配置)、webpack.dev.conf.js(开发环境)、webpack.prod.conf.js(生产环境)三部分

  • 利用mode配置项,区分开发环境和生产环境。用利用merge将用到的环境配置和通用配置合并

3、认识代码分离

代码分离(CodeSplitting)主要的目的是将代码分离到不同的bundle中,之后我们可以按需加载,或者并行加载这些文件;

Webpack中常用的代码分离有三种

  • 入口起点:使用entry配置手动分离代码;

  • 防止重复:使用EntryDependencies或者SplitChunksPlugin去重和分离代码;

  • 动态导入:通过模块的内联函数调用来分离代码;

1、多入口起点

entry: {
	index:"./src/index.js",
	main:"./src/main.js"
}
output: {
	filename:"[name].bundle.js",
	path:resolveApp("./build")
}	

2、EntryDependencies(入口依赖)

假如我们的index.js和main.js都依赖两个库:lodash、dayjs

  • 如果我们单纯的进行入口分离,那么打包后的两个bunlde都有会有一份lodash和dayjs;

    entry: {
    	index: {import:"./src/index.js",dependOn:"shared"},
    	main:{import:"./src/main.js",dependOn:"shared"},
    	shared:['lodash','axios']
    }
    output: {
    	filename:"[name].bundle.js",
    	path:resolveApp("./build"),
    	publicPath: ""
    }

3、SplitChunks

另外一种分包的模式是splitChunk,它是使用SplitChunksPlugin来实现的:

Webpack提供了SplitChunksPlugin默认的配置,我们也可以手动来修改它的配置:

  • 比如默认配置中,chunks仅仅针对于异步(async)请求,我们可以设置为initial或者all;

optimization: {
	splitChunks: {
		chunks:'all'
	}
}

4、SplitChunks自定义配置

SplitChunks: {
	chunks:'all',
	// 拆分包的大小,至少为minsize
	// 如果一个包拆分出来不到minsize,那么将不会被拆分
	minsize:100,
	// 将大于maxMize的包,拆分成不小于minSize 的包
	maxsize:1000,
	// 至少包被引入的次数
	minChunks:2,
	// 最大异步请求数量
	maxAsyncRequests:30,
	// 最大的初始化请求数量
	cacheGroups: {
		venders: {
			test:/[\\/]node_modules[\\/]/,
			priority: -10,
			filename: "[id]_[hash:6]_vendor.js"
		},
		foo: {
			test:/foo/,
			priority: -20,
			filename: "foo_[id]_[name]_.js"
		}
	}
}

配置解析:

  • Chunks

    • 默认值是async

    • 另一个值是initial,表示对通过的代码进行处理

    • all表示对同步和异步代码都进行处理

  • minSize

    • 拆分包的大小, 至少为minSize;

    • 如果一个包拆分出来达不到minSize,那么这个包就不会拆分;

  • maxSize

    • 将大于maxSize的包,拆分为不小于minSize的包;

  • minChunks

    • 至少被引入的次数,默认是1;

    • 如果我们写一个2,但是引入了一次,那么不会被单独拆分;

  • name:设置拆包的名称

    • 可以设置一个名称,也可以设置为false;

    • 设置为false后,需要在cacheGroups中设置名称;

  • cacheGroups

    • 用于对拆分的包就行分组,比如一个lodash在拆分之后,并不会立即打包,而是会等到有没有其他符合规则的包一起来打包;

    • test属性:匹配符合规则的包;

    • name属性:拆分包的name属性;

    • filename属性:拆分包的名称,可以自己使用placeholder属性;

5、动态导入(dynamic import)

使用ECMAScript中的import()语法来完成,也是目前推荐的方式;

注意:

  • 在webpack中,通过动态导入获取到一个对象;

  • 真正导出的内容,在改对象的default属性中,所以我们需要做一个简单的解构;

动态导入的文件命名

它的命名我们通常会在output中,通过chunkFilename属性来命名

output: {
    filename: "[name].bundle.js",
    path:resolveApp("./build"),
    chunkFilename: "chunk_[id]_[name].js"
}

默认情况下我们获取到的[name]是和id的名称保持一致的

  • 我们希望修改name的值,可以通过magic comments(魔法注释)的方式

import(/* webpackChunkName:"bar"*/ "./bar").then(({default:bar}) => {
    bar()
})

6、optimization.chunkIds配置

optimization.chunkIds配置用于告知webpack模块的id采用什么算法生成。

  • natural:按照数字的顺序使用id;

  • named:development下的默认值,一个可读的名称的id;

  • deterministic:确定性的,在不同的编译中不变的短数字id

最佳实践:

  • 开发过程中,我们推荐使用named;

  • 打包过程中,我们推荐使用deterministic;

7、optimization. runtimeChunk配置

配置runtime相关的代码是否抽取到一个单独的chunk中:

  • 抽离出来后,有利于浏览器缓存的策略:

  • 设置的值

    • true/multiple:针对每个入口打包一个runtime文件;

    • single:打包一个runtime文件;

    • 对象:name属性决定runtimeChunk的名称;

    optimization:{
        chunkIds:"deterministic",
        runtimeChunk: {
            name:"runtime"
        }
    }

8、Prefetch和Preload

  • webpack v4.6.0+增加了对预获取和预加载的支持。

    • prefetch(预获取):将来某些导航下可能需要的资源

    • preload(预加载):当前导航下可能需要资源

    import(/* webpackChunkName:"bar"*/ 
    	/* webpackpeload:true */
    	"./bar").then(({default:bar}) => {
    	bar()
    })
  • 区别

    • preload chunk 会在父chunk 加载时,以并行方式开始加载。prefetch chunk 会在父chunk 加载结束后开始加载。

    • preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。

    • preload chunk 会在父chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。

9、CDN

CDN称之为内容分发网络(ContentDeliveryNetwork或ContentDistributionNetwork,缩写:CDN)

开发中的应用方式:

  • 方式一:打包的所有静态资源,放到CDN服务器,用户所有资源都是通过CDN服务器加载的;

  • 方式二:一些第三方资源放到CDN服务器上;

方式一花钱,直接说方式二

一些比较出名的开源框架都会将打包后的源码放到一些比较出名的、免费的CDN服务器上

使用方法:

  • 第一步,我们可以通过webpack配置,来排除一些库的打包:

    externals: {
    	lodash: "_",
    	dayjs: "dayjs"
    }
  • 第二步,在html模块中,加入CDN服务器地址:

    <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.core.js"></script>

10、认识shimming

  • shimming是一个概念,是某一类功能的统称:

    • 比如我们现在依赖一个第三方的库,这个第三方的库本身依赖lodash,但是默认没有对lodash进行导入(认为全局存在lodash),那么我们就可以通过ProvidePlugin来实现shimming的效果;

  • 注意:webpack并不推荐随意的使用shimming

    • Webpack背后的整个理念是使前端开发更加模块化;

    • 也就是说,需要编写具有封闭性的、不存在隐含依赖(比如全局变量)的彼此隔离的模块;

11、MiniCssExtractPlugin

MiniCssExtractPlugin可以帮助我们将css提取到一个独立的css文件中,该插件需要在webpack4+才可以使用。

安装:

npm install mini-css-extract-plugin -D

配置:

plugins: [
	new MiniCssExtractPlugin({
		filename:"css/[name].[contenthash:8].css",
		chunkfilename: "css/[name].[contenthash:8].css"
	})
],
module:{
	rules: [
		{
			test:/\.css$/i,
			use:[MiniCssExtractPlugin.loader,'css-loader']
		}
	]
}

12、Hash、ContentHash、ChunkHash

  • hash值的生成和整个项目有关系:

    • 比如我们现在有两个入口index.js和main.js;

    • 它们分别会输出到不同的bundle文件中,并且在文件名称中我们有使用hash;

    • 这个时候,如果修改了index.js文件中的内容,那么hash会发生变化;

    • 那就意味着两个文件的名称都会发生变化;

  • chunkhash可以有效的解决上面的问题,它会根据不同的入口进行借来解析来生成hash值:

比如我们修改了index.js,那么main.js的chunkhash是不会发生改变的;

  • contenthash表示生成的文件hash名称,只和内容有关系:

    • 比如我们的index.js,引入了一个style.css,style.css有被抽取到一个独立的css文件中;

    • 这个css文件在命名时,如果我们使用的是chunkhash;

    • 那么当index.js文件的内容发生变化时,css文件的命名也会发生变化;

    • 这个时候我们可以使用contenthash;

十二、DLL_Tree Shaking

认识DLL库(了解一下)

  • DLL全程是动态链接库(Dynamic Link Library),是为软件在Windows中实现共享函数库的一种实现方式;

  • webpack中也有内置DLL的功能,它指的是我们可以将可以共享,并且不经常改变的代码,抽取成一个共享的库;

Terser介绍和安装(一般使用默认配置)

  • Terser是一个JavaScript的解释(Parser)、Mangler(绞肉机)/Compressor(压缩机)的工具集;

    • 早期我们会使用uglify-js来压缩、丑化我们的JavaScript代码,但是目前已经不再维护,并且不支持ES6+的语法;

  • Terser可以帮助我们压缩、丑化我们的代码,让我们的bundle变得更小。

安装:

npm install terser -g // 可以进行局部安装,也可以全局安装

命令行使用

terser [input files] [options]

常见的配置项:

Compress option

  • arrows:class或者object中的函数,转换成箭头函数;

  • arguments:将函数中使用arguments[index]转成对应的形参名称;

  • dead_code:移除不可达的代码(tree shaking);

  • 等等其他属性,详情看官方文档

Mangle option

  • toplevel:默认值是false,顶层作用域中的变量名称,进行丑化(转换)

  • keep_classnames:默认值是false,是否保持依赖的类名称;

  • keep_fnames:默认值是false,是否保持原来的函数名称;

Terser在webpack中配置使用

  • (注意)真实开发中,我们不需要手动的通过terser来处理我们的代码,我们可以直接通过webpack来处理:

    • 在webpack中有一个minimizer属性,在production模式下,默认就是使用TerserPlugin来处理我们的代码的;

    • 如果我们对默认的配置不满意,也可以自己来创建TerserPlugin的实例,并且覆盖相关的配置;(基本不会手动配置)

module.exports = {
    optimization: {
        minimize:true,
        minimizer: [
            new TerserPlugin({
                parallel:true, // 使用多进程并发运行提高构建的速度,默认值是true,
                extractComments:false, // 默认值为true,表示会将注释抽取到一个单独的文件中
                terserOptions: { // 设置我们的terser相关的配置
                    compress: { // 设置压缩相关的选项;
                        arguments:true,
                        dead_code:true
                    },
                    mangle:true, // 设置丑化相关的选项,可以直接设置为true;
                    toplevel:true, // 底层变量是否进行转换
                    keep_classnames:false,// 保留类的名称
                    keep_fnames:false// 保留函数的名称;
                }
            })
        ]
    }
}

CSS的压缩

安装:

npm install css-minimizer-webpack-plugin -D

在optimization.minimizer中配置:

minimizer: [
    new CssMinimizerplugin({
        parallel: true
    })
]

提升作用域 Scope Hoisting

  • Scope Hoisting从webpack3开始增加的一个新功能,功能是对作用域进行提升,并且让webpack打包后的代码更小、运行更快;

  • 默认情况下webpack打包会有很多的函数作用域,Scope Hoisting可以将函数合并到一个模块中来运行

  • 使用:

    • 在production模式下,默认这个模块就会启用;

    • 在development模式下,我们需要自己来打开该模块;

    new webpack.optimize.ModuleConcatenationPlugin()

Tree Shaking

定义:最早的想法起源于LISP,用于消除未调用的代码(纯函数无副作用,可以放心的消除,这也是为什么要求我们在进行函数式编程时,尽量使用纯函数的原因之一)

webpack实现TreeShaking

两种方法:

  • 在optimization中配置usedExports为true,来帮助Terser进行优化;

  • 在package.json中配置sideEffects,直接对模块进行优化;

usedExports

在usedExports设置为true时,会有一段注释:unused harmony export mul,这段注释告知Terser在优化时,可以删除掉这段代码

注意:

  • 配置该属性时,需要将mode设置为development模式

  • usedExports实现tree Shaking是结合terse来完成的

sideEffects

sideEffects用于告知webpack compiler哪些模块时有副作用的(副作用的意思是这里面的代码有执行一些特殊的任务,不能仅仅通过export来判断这段代码的意义;)

  • 在package.json中设置sideEffects的值:

    • false:告知webpack可以安全的删除未用到的exports;

    • 如果有一些希望保留,可以设置数组

"sideEffects": [
    "./src/util/format.js",
    "*.css"
]

CSS实现TreeShaking

我们可以使用一个库来完成CSS的Tree Shaking:PurgeCSS,帮助我们删除未使用的CSS的工具

安装:

npm install purgecss-webpack-plugin -D

配置:

  • paths:表示要检测哪些目录下的内容需要被分析,这里我们可以使用glob;

  • 默认情况下,Purgecss会将我们的html标签的样式移除掉,如果我们希望保留,可以添加一个safelist的属性;

  • purgecss也可以对less文件进行处理(所以它是对打包后的css进行tree shaking操作)

new  PurgecssPlugin({
    paths:glob.sync(`${resolveApp(./src)}/**/*`,{nodir:true}),
    safelist: function() {
        return {
            standard:['html']
        }
    }
})

HTTP压缩

定义:HTTP压缩是一种内置在服务器和客户端之间的,以改进传输速度和带宽利用率的方式

流程:

第一步:HTTP数据在服务器发送前就已经被压缩了

第二步:兼容的浏览器在向服务器发送请求时,会告知服务器自己支持哪些压缩格式

第三步:服务器在浏览器支持的压缩格式下,直接返回对应的压缩后的文件,并且在响应头中告知浏览器;

目前的压缩格式

  • compress–UNIX的“compress”程序的方法(历史性原因,不推荐大多数应用使用,应该使用gzip或deflate);

  • deflate–基于deflate算法(定义于RFC1951)的压缩,使用zlib数据格式封装;

  • gzip–GNUzip格式(定义于RFC1952),是目前使用比较广泛的压缩算法;

  • br–一种新的开源压缩算法,专为HTTP内容的编码而设计;

Webpack对文件压缩

webpack中相当于是实现了HTTP压缩的第一步操作,我们可以使用CompressionPlugin。

安装:

npm install compression-webpack-plugin -D

配置:

new CompressionPlugin({
    test:/\.(css|js)$/,  // 匹配哪些文件需要压缩
    threshold:500, // 设置文件多大开始压缩
    minRatio: 0.7, // 至少采用的压缩比例
    algorithm: "gzip" // 采用的压缩算法
})

HTML文件中代码的压缩

我们之前使用了HtmlWebpackPlugin插件来生成HTML的模板,事实上它还有一些其他的配置:

  • inject:设置打包的资源插入的位置

    • true、false、body、head

  • cache:设置为true,只有当文件改变时,才会生成新的文件(默认值也是true)

  • minify:默认会使用一个插件html-minifier-terser

InlineChunkHtmlPlugin

可以辅助将一些chunk出来的模块,内联到html中

安装

npm install react-dev-utils -D

在production的plugins中进行配置:

module.exports = {
    plugin:[
        new InlineChunkHtmlPlugin(HtmlWebpackPlugin,[/runtime.+\.js/])
    ]
}

十三、webpack打包分析

分析一:打包的时间分析

speed-measure-webpack-plugin 可以帮助我们看到每一个loader、每一个plugin的打包时间

安装:

npm install speed-measure-webpack-plugin -D

配置:

const smp = new SpeedMeasurePlugin();
cpnst webpackConfig = smp.wrap({
    plugins: [new MyPlugin(),new MyOtherPlugin()]
})

分析二:打包后文件分析

使用webpack-bundle-analyzer工具

安装:

npm install webpack-bundle-analyzer -D

配置

module.exports = {
    plugins: [
        new BundleAnalyzerPlugin()
    ]
}

Compiler和Compilation的区别(面试题)

  • Compiler中webpack构建的之初就会创建的一个对象, 并且在webpack的整个生命周期都会存在(before -run -beforeCompiler-compile -make -finishMake-afterCompiler-done)

    • 只要是做webpack的编译, 都会先创建一个Compiler

  • Compilation是到准备编译模块(比如main.js), 才会创建Compilation对象

    • watch -> 源代码发生改变就需要重新编译模块

    • 主要是存在于compile -make 阶段主要使用的对象

  • Compiler可以继续使用(如果我修改webpack的配置, 那么需要重新执行run run build)

  • Compilation需要创建一个新的Compilation对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/367477.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(三十)大白话MySQL的redo log buffer中的缓冲日志,到底什么时候可以写入磁盘?

之前我们给大家讲解了一下redo log buffer的缓冲机制&#xff0c;大家现在应该都知道了&#xff0c;redo log在写的时候&#xff0c;都是一个事务里的一组redo log&#xff0c;先暂存在一个地方&#xff0c;完事儿了以后把一组redo log写入redo log buffer。 写入redo log buf…

C++ 动态内存管理

目录 1. C/C内存分布 练习 2. C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free 3. C内存管理方式 3.1 new/delete操作内置类型 3.2 new和delete操作自定义类型 4. operator new与operator delete函数 4.1 operator new与operator delete函数&#xff08…

跨境多账号管理教程分享:解决多账号管理混乱问题

如今&#xff0c;跨境电商卖家拥有多平台多账号已经成为常态&#xff0c;但很多人找东哥咨询的担忧都是要如何有效地管理这么多账号&#xff0c;因为如果账号过多&#xff0c;容易被关联&#xff0c;进而影响账号安全。如果你也刚好有这个烦恼&#xff0c;那找东哥真的就是找对…

HEVC 编码速率控制

视频传输带宽通常都会受到一定的限制&#xff0c;为了在满足通信带宽和传输时延限制的情况下有效传输视频数据&#xff0c;保证视频业务的播放质量&#xff0c;需要对视频编码过程进行速率控制&#xff0c;所谓速率控制&#xff0c;就是通过选择一系列编码失真尽量小&#xff0…

「TCG 规范解读」初识 TPM 2.0 库续三

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Alli…

导航定位状态评估专题:“特征”离群点判断与剔除 | 定位状态完整性监控

1、前言&#xff1a;经典状态估计中协方差的计算能准确反映机器人状态的完整性吗&#xff1f;在每一次机器人执行各种目的的自动导航任务时&#xff0c;拥有高精度且可靠状态估计的能力可以说是机器人顺利、安全完成任务的必要条件之一。简而言之&#xff0c;机器人状态估计算法…

Docker Compose

为什么需要使用Docker ComposeDocker Compose 容器编排技术1、现在我们有一个springboot项目&#xff0c;需要依赖Redis、mysql、nginx。如果使用docker原生部署的话&#xff0c;则需要安装Redis、mysql、nginx容器&#xff0c;才可以启动我们springboot项目&#xff0c;这样的…

Flink-CEP理论与实践

一.什么是Flink cepCEP 是复杂事件处理&#xff08;Complex Event Processing&#xff09;的缩写&#xff0c;是一种处理实时数据流的技术。它可以在大规模数据流中实时识别出与预定义的模式匹配的事件&#xff0c;并在匹配到事件时采取相应的措施。CEP 技术的应用范围非常广泛…

Web前端:为什么要雇佣全栈开发人员

全栈开发人员是任何软件开发项目的宝贵专家。但是&#xff0c;在某些情况下&#xff0c;它们是企业最需要的。雇佣一名全栈开发人员来监督你的项目&#xff0c;从构思到启动&#xff0c;再到以后&#xff0c;有无数的好处。1.出色的web/应用程序开发人员全栈web开发人员有经验&…

CSS3实现文字循环滚动播放

CSS3实现文字循环滚动播放 效果图&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name&q…

【微信小程序】-- 常用视图容器类组件介绍 -- view、scroll-view和swiper(六)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#…

分布式爬虫的介绍和搭建

分布式爬虫 Scrapy单机模式 Scrapy引擎通过一调度器&#xff0c;将request队列中的 request请求发给下载器进行页面的爬取 Scrapy单机框架的优缺点 优点&#xff1a; 部署容易&#xff0c;架构简单快速&#xff0c;快速部署 缺点&#xff1a; 单点执行&#xff0c;抓取…

假脱机技术Spooling和守护进程

文章目录假脱机系统Spooling和守护进程1.假脱机技术的引入2.SPOOling系统的组成3.SPOOling系统的工作过程守护进程假脱机系统Spooling和守护进程 1.假脱机技术的引入 脱机技术&#xff1a; 为了缓和CPU的高速性与IO设备的低速性间的矛盾&#xff0c;而引入了脱机输入&#xf…

Objective-C 中类和对象的基本使用 方法的调用(消息传递)

总目录 iOS开发笔记目录 从一无所知到入门 文章目录Intro截图自定义类型的interface部分和implementation部分main方法中的类型调用部分Demo测试代码输出Intro Objective-C&#xff0c;具有面向对象特性的C。 但其实&#xff0c;它的面向对象和其他高级语言相比&#xff0c;还…

【C++】C++的内存模型之四大分区

程序的内存模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域 代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理的全局区&#xff1a;存放全局变量和静态变量以及常量栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数值&…

CIMCAI intelligent tally shore AI auto container damage detect

全球港航人工智能/集装箱人工智能领军者CIMCAI&#xff0c;世界首创港口岸边超级智能理货产品自动化AI验箱&#xff0c;AI自动化码头港口数字化港口。中集飞瞳CIMCAI领跑全球港口码头人工智能科技&#xff0c;领先集装箱箱况残损识别科技全方位提升港口码头效能。集装箱残损可能…

剑指 Offer 68 - I. 二叉树的最近公共祖先

摘要 剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 剑指 Offer 68 - II. 二叉树的最近公共祖先 一、二叉搜索树的最近公共祖先 注意到题目中给出的是一棵二叉搜索树&#xff0c;因此我们可以快速地找出树中的某个节点以及从根节点到该节点的路径&#xff0c;例如我们需要找…

2023年金三银四必备软件测试常见面试题1500问!!!

十九、持续集成19.1 jenkins ant jmeter svn接口自动化测试?jenkins ant jmeter svn环境搭建原来这个环境是我这边搭建的&#xff0c;主要是几个步骤&#xff0c;第一Jenkins安装、第二&#xff0c;ant安装、第三&#xff0c;jmeter安装、第四&#xff0c;jmeter与ant连…

HTML基础(1)

HTML基础HTML基本介绍编辑工具HTML概述多如牛毛的标签头部标签&#xff1a;标题与段落标签&#xff1a;br换行符&#xff1a;a href超链接标签&#xff1a;< meta > 元素标签&#xff1a;主体标签HTML注释&#xff1a;水平线标签hr&#xff1a;段落标签p&#xff1a;文本…

[ 常用工具篇 ] 多媒体视频处理工具 ffmpeg 安装使用详解

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…