• 尚硅谷wepack课程学习笔记


    为什么需要使用打包工具?

    开发时使用的框架、es6 语法 、less 等浏览器无法识别。
    需要经过编译成浏览器能识别的css、js才可以运行。
    打包工具可以帮我们编译,还可以做代码压缩、兼容处理、性能优化

    常见的打包工具有什么?
    vite、webpack、glup、grunt

    webapck最基本的使用?
    是一个静态资源打包工具,以一个或多个文件为打包入口,将项目中所有文件编译组合成输入一个或多个文件。这个输出的文件我们叫budle,他就是经过编译可以在浏览器运行的文件。

    webpack本身的功能是有限的?
    开发模式:仅仅编译js modle语法
    生产模式:编译js modle语法、压缩js代码

    package.json 是什么文件?
    通常我们需要安装一些依赖包,而在下载这个包之前,我们需要包描述文件。通常描述这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证、如何启动项目、运行脚本等元数据。
    package.json 一般在项目创建之初创建。创建方式可以手动(直接在项目根目录新建一个 package.json 文件)、也可以npm init -y 初始化一个,y 就是要使用配置的默认值
    package.json文件就是一个JSON对象,该对象的每一个成员就是当前项目的一项设置

    webpack 安装文档,不建议全局安装
    练习步骤:
    1、新建一个包,名称不能和webpack重复
    2、创建基本的mani.js 文件、src、public文件、写入es6 模块化语法,报错,浏览器无法识别。
    3、试试使用webpack 后能否识别呢?无法解析modle语法
    4、引入之前需要初始化一个包描述文件 npm init -y
    5、npm install webpack webpack-cli --save-dev
    6、安装成功后执行npx webpack ./src/main.js --mode=development ,npx 会将node—module 的bin 下面的内容临时添加到环境变量。
    7、执行上面即可打包了。默认输出到dist,可以观察输出文件,是编译后的文件。
    8、npx webpack ./src/main.js --mode=production 生产模式,会压缩代码

    webapck的五大核心概念
    入口entry
    输入output
    loader webpack本身只能处理js、json等资源,其他资源需要借助loader
    plugin 拓展功能
    mode 模式:生产、开发

    练习步骤:
    1、安装好之后建一个webpack的配置文件,在根路径下,并且文件名必须是webpack.config.js
    2、添加基本配置
    3、我们之前打包执行的是npx webpack ./src/main.js --mode=development 这个命令,写了webpack的配置文件中设置了入口后,可以直接使用npx webpack 执行了。上面是使用cli的方式运行本地的webpack,但这样还是有些麻烦。
    4、在 package.json 文件中添加一个 npm script: “build”: “webpack”
    现在,可以使用 npm run build 命令替代之前使用的 npx 命令。注意,使用 npm scripts 便可以像使用 npx 那样通过模块名引用本地安装的 npm packages。
    拓展,可以学习下npm中文文档

    资源管理
    1、使用style样式,需要借助loader
    2、npm install --save-dev style-loader css-loader
    3、添加配置,参考官网

    1、使用less资源
    2、npm install less less-loader --save-dev
    3、添加配置,参考官网

    1、图片资源的使用
    2、不需要要下载,使用内置的asset即可。资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。``关于这块配置webpack官网介绍
    3、添加配置,

    {
            test: /\.(png|svg|jpg|jpeg|gif)$/i,
            type: 'asset/resource',
    },
    
    • 1
    • 2
    • 3
    • 4

    1、对文件的加载,如 JSON 文件、CSV、TSV 和 XML。
    2、npm install --save-dev csv-loader xml-loader
    3、添加配置,参考官网

    调整文件打包输出目录
    每一次打包都会在dist下多一些文件,而且很混乱。我们在下一次打包之前手动删除dist,再重新打包。
    并设置输出路径,文件资源可设置输出路径。
    为特定资源指定输出路径

       generator: {
              filename: 'asset/[hash:10][ext][query]'
       }
    
    • 1
    • 2
    • 3

    可不可以不每次都需要手动删除呢?
    能不能自动清除dist文件上次内容?可以,在output 对象中配置clean:true 即可。

    处理js资源
    webpack对于js资源的处理是有限的,只能处理model语法,对于es6新语法不兼容,我们需要使用babel
    在转换之前先介绍一下eslint ,用于检查js和jsx语法的工具。更多介绍eslint官网

    在webpack中使用eslint
    1、npm install eslint-webpack-plugin --save-dev
    2、npm install eslint --save-dev
    3、添加配置,参考官网

    const ESLintPlugin = require('eslint-webpack-plugin');
    
    module.exports = {
      // ...
      plugins: [new ESLintPlugin({
          context:path.resolve(__dirname,'src'),
        })]
      // ...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4、运行起来报错,缺少eslint的配置文件。我们在根目录下新建 .eslintrc.js 文件名不能改。
    然后具体的配置可以参考官网,可以继承推荐的默认配置。

    5、发现dist下定义的文件也被eslint 检查了,但我们并不需要检查这些文件。在根目录下创建一个 .eslintignore 文件,写上需要忽略的文件路径即可。

    在webpack中使用babel

    关于bable的介绍可以看bable官网
    1、npm install -D babel-loader @babel/core @babel/preset-env webpack
    2、配置,参考官网 bable配置
    3、配置可以直接写在webpack的配置文件中,也可以在根目录创建 babel.config.js 配置。

    处理html资源
    1、原本html中引入的js资源是这么写的

     
    
    • 1

    引入的是打包编译后的文件,如果更改入口起点的名称,或者添加一个新的入口,那么会在构建时重新命名生成的 bundle,但是 index.html 仍然在引用旧的名称!而且如果需要引入很多资源,手动维护非常困难。
    我们可以使用 HtmlWebpackPlugin (为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中)来解决这个问题。
    安装:

    npm install --save-dev html-webpack-plugin
    
    • 1

    配置:

      new HtmlWebpackPlugin({
          title: '管理输出',
          // 模板:以public/index.html 文件创建新的html 这样打包之后的html不会把之前的东西丢掉
          template:path.resolve(__dirname,'public/index.html')
        }),
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用了这个插件,我们无需在html中手动引入,他会自动帮我们引入并且在输出文件中新增一个html文件。

    搭建开发服务器
    我们之前每次改动了src的内容,都需要编译之后才能看到效果,需要手动执行npx webapck ,我们希望webpack能自动化,可以使用
    webpack-dev-server,他相当于webpack 启动了一个服务器,他会帮我们监听src下所有的改动,只有有改动会帮我们自动打包编译。
    安装

    npm install --save-dev webpack-dev-server
    
    
    • 1
    • 2

    配置

    devServer:{
        host:'localhost',// 启动服务器的域名
        port:'8080',// 启动服务器端口号,
        open:true,// 是否自动打开浏览器
        static: './dist', // 将 dist 目录下的文件 serve 哒服务器
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行命令

    npx webpack serve 
    
    • 1

    添加一个可以直接运行 dev server 的 script:

     "scripts": {
         "test": "echo \"Error: no test specified\" && exit 1",
         "watch": "webpack --watch",
         "start": "webpack serve --open",
         "build": "webpack"
       },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在命令行中运行 npm start,会看到浏览器自动加载页面。

    eee,报错了!

    报错内容:

    Error: Cannot find module ‘ajv/dist/compile/codegen’
    
    • 1

    解决办法:

    npm i ajv
    npm install ajv-errors@1.0.1
    
    • 1
    • 2

    再次启动
    eee,又报错了!

    报错内容:

    Error: Conflict: Multiple chunks emit assets to the same filename static/js/bundle.js (chunks main and vendors-node_modules_react-hot-loader_patch_js-node_modules_react_jsx-dev-runtime_js-node_mod-4610d2)
    
    • 1

    解决办法:

    让它工作不得不改变filename: "static/js/bundle.js"至filename: "static/js/[name].js"
    
    output: {
        path: undefined,
        publicPath: "/",
        filename: "static/js/[name].js",
        chunkFilename: "static/js/[name].chunk.js",
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    再次启动可以了

    在这里插入图片描述

    webpack-dev-server 在编译之后不会写入到任何输出文件,而是将 bundle 文件保留在内存中,然后将它们 serve 到 server 中,就好像它们是挂载在 server 根路径上的真实文件一样。如果你的页面希望在其他不同路径中找到 bundle 文件,可以通过 dev server 配置中的 devMiddleware.publicPath 选项进行修改。

    意思就是开发模式下不会生成打包后的文件,尝试把dist删除,保存后自动打包确实没有生成dist文件了
    修改js文件内容页面自动更新了。

    生产和开发环境两套配置
    development(开发环境) 和 production(生产环境) 这两个环境下的构建目标存在着巨大差异。在开发环境中,我们需要:强大的 source map 和一个有着 live reloading(实时重新加载) 或 hot module replacement(热模块替换) 能力的 localhost server。而生产环境目标则转移至其他方面,关注点在于压缩 bundle、更轻量的 source map、资源优化等,通过这些优化方式改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。

    首先我们新建一个config文件夹,分别新建webpack.dev.js 和 webpack.prod.js 两个文件
    将文件中使用相对路径的地方加个…/

     template:path.resolve(__dirname,'../public/index.html')
    
    • 1

    但是入口文件路径不改变,因为配置文件运行时在根目录

      entry:'./src/main.js',
    
    • 1

    生产环境不需要dev-server

    分别添加两个命令

      "build": "webpack --config ./config/webpack.prod.js",
      "start": "webpack serve --config ./config/webpack.dev.js"
    
    • 1
    • 2

    执行对应的命令,生产环境下的budle 有压缩。

    虽然,以上我们将 生产环境 和 开发环境 做了细微区分,但是,请注意,我们还是会遵循不重复原则(Don’t repeat yourself - DRY),保留一个 “common(通用)” 配置。为了将这些配置合并在一起,我们将使用一个名为 webpack-merge 的工具。此工具会引用 “common” 配置,因此我们不必再在环境特定(environment-specific)的配置中编写重复代码。

    我们先从安装 webpack-merge 开始,并将之前指南中已经成型的那些代码进行分离:

    npm install --save-dev webpack-merge
    
    • 1

    新建一个webpack.common.js文件,写入公共配置
    在生产和开发文件中分别引入即可。

     const { merge } = require('webpack-merge');
     const common = require('./webpack.common.js');
    
     module.exports = merge(common, {
       mode: 'production',
     });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    提取css成单独文件
    我们可以看到,现在我们的css文件,是被打包到了js中,当js文件加载时,会创建一个style 标签来生成样式。
    只有js加载完了,页面才会出现样式,给用户闪屏的感觉,体验不好。
    应该是将样式抽离到单独的css文件中,通过link标签引入,加载的性能才好
    借助插件MiniCssExtractPlugin来实现,官网介绍
    在这里插入图片描述
    1、安装:

    npm install --save-dev mini-css-extract-plugin
    
    • 1

    2、配置

    官方建议 mini-css-extract-plugin 与 css-loader 一起使用。
    将styel-loader 替换为MiniCssExtractPlugin.loader,因为插件会将 CSS 提取到单独的文件中,
    为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
    不再需要创建style 标签了

    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    use: [MiniCssExtractPlugin.loader, 'css-loader'],
    
    
    
    • 1
    • 2
    • 3
    • 4

    现在已经被打包到main.css 中了
    在这里插入图片描述

    css 兼容性处理
    postcss-loader 官网介绍
    可以帮我们处理一些样式兼容性问题
    1、安装

    npm install --save-dev postcss-loader postcss postcss-preset-env 
    
    • 1

    2、配置,必须写在css-loder 后面

    {
                loader: 'postcss-loader',
                options: {
                  postcssOptions: {
                    plugins: [
                      [
                        'postcss-preset-env',
                        {
                          // 其他选项
                        },
                      ],
                    ],
                  },
                },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、在package.json 中添加配置
    设置浏览器兼容需要做到什么程度。
    最近一个版本,99%任然再使用的浏览器

      "browserslist" :[
        "last 2 version",
        "< 1%",
        "not dead"
      ]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    css压缩处理
    通过观察可以发现,我们dist目录下的资源,js和html都压缩了。但css文件没有压缩处理。
    我们可以借助CssMinimizerWebpackPlugin 插件,官网介绍
    在这里插入图片描述

    1、安装

    npm install css-minimizer-webpack-plugin --save-dev
    
    • 1

    2、配置

    const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
      optimization: {
        minimizer: [
          // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
          // `...`,
          new CssMinimizerPlugin(),
        ],
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    再次打包已经被压缩了
    在这里插入图片描述

    打包优化
    1、提升开发体验
    2、提升打包构建速度
    3、减少代码体积
    4、优化代码性能

    sourceMap
    开发时我们运行的代码是编译之后的,如果有报错,只能定位到编译后的位置,不便于我们排查问题。
    sourceMap(源代码映射) 是一个用来生成源代码和映射代码构建的方案

    他会生成xx.map 文件,里面包含源代码码和构建好的代码每一行,每一列的关系。从而让浏览器提示源文件的出错位置,从而帮我们快速定位错误。
    如何使用devtool?官网介绍
    具体配置:

    开发模式:
      mode:'development',
      devtool:'cheap-module-source-map',
    
    生成模式:
      mode:'production',
      devtool:'source-map',
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    经过测试,已经定位到具体一行了

    HotModlueReplcaement
    当我们在开发时只修改了某一个模块的代码,webpack在打包时会重新打包,速度很慢,页面整体重新刷新了。我们希望它只编译需要打包的模块,其他模块不变。

    HotModlueReplcaement(热模块替换)在程序运行中,替换、添加、删除模块,而无需加载整页面,
    如何使用?
    从 webpack-dev-server v4.0.0 开始,热模块替换是默认开启的。

      devServer:{
        host:'localhost',// 启动服务器的域名
        port:'8080',// 启动服务器端口号,
        open:true,// 是否自动打开浏览器
        static: './dist',
        hot:true // 只应用与开发环境,生产环境不需要,默认开启
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    但是只有css/html 可以做到,对于js 需要在入口文件manjs中

    if(module.hot) {
      // 判断是否支持热模块替换功能,有的话需要一个个js文件添加
       module.hot.accept('./js/sum.js')
    }
    
    • 1
    • 2
    • 3
    • 4

    每个js文件都需要手动引入,太麻烦?
    当然了,vue-loader,react-hot-loder 已经帮我们做了这些事情。

    oneOf
    打包时每个文件都会经过所有 loader 处理,例如一个css文件也会进过js文件的判断,虽然因为 test 正则原因实际没有处理上,但是都要过一遍比较慢。所以使用OneOf,匹配上一个 loader, 剩下的就不匹配了,开发模式和生产模式都可以用

     module: {//loader规则
        rules: [
         // 比如是css文件,匹配到之后处理use对应的一组loader,后续不再匹配
          {
            //每个文件只能被其中一个loader配置处理
            oneOf: [
              {
                test: /\.css$/i, // 用来匹配 .css 结尾的文件
                use: [
                  "style-loader", //将js中css通过创建style标签添加到html中
                  "css-loader" //该模块将css资源编译成commonjs的模块到js中
                ],//use 数组里面 Loader 执行顺序是从右到左(从下到上)
              },
              {
                test: /\.less$/i, // 用来匹配 .less 结尾的文件
                //loader:"xxx"只能使用1个loader
                use: [//use可以使用多个loader
                  // compiles Less to CSS
                  '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

    eslint 和babel 缓存
    每次打包的时候js文件都需要经过eslint检查和babel编译,速度很慢。
    我们如果能缓存之前的结果,第二次打包的速度就会快很多
    对babel的配置

    {
            test:/\.js$/,
            include:path.resolve(__dirname,'../src'),
            loader:'babel-loader',
            options:{
              cacheDirectory:true, // 开启babel缓存
              cacheCompression:false // 关闭缓存文件压缩
            }
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    对eslin的配置

        new ESLintPlugin({
          context:path.resolve(__dirname,'../src'),
          exclude:"node_modules",
          // cache:true,// 开启缓存
          // cacheLocation:path.resolve(__dirname,'../node_modules/.cache/eslintcache')
        }),
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    多进程打包
    我们打包的速度大部分时候是处理js文件的速度,而处理js文件主要就是eslint、bable、terser这三个工具,我们要提升他们的运行速度,可以开启多线程同时处理。
    但是需要注意的是,仅在特别耗时的项目中使用,因为每个进程启动大约有600ms的开销
    我们启动进程的数量就是cpu的核数。
    如何获取自己电脑cpu的核数?

    const os = require('os');
    const threads = os.cpus().length;
    
    • 1
    • 2

    还需要借助

    npm i thread-loader -D
    
    • 1

    配置

     {
            test:/\.js$/,
            include:path.resolve(__dirname,'../src'),
            use:[
              {
               loader:'thread-loader',// 开启多进程
               options :{
                works:threads // 进程数量
               }
    
              },
              {
                loader:'babel-loader',
                options:{
                  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

    还需要引入一个插件

     optimization: {
        minimizer: [
          // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
          // `...`,
          new CssMinimizerPlugin(),
          new TerserWebpackPlugin({
            parallel:threads
          })
        ],
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    什么是tree-shaking

    我们定义或引入了一些第三方工具函数或组件库,如果没做特殊处理的话,打包的时候会引入整个库,即使我们使用的是很小一部分功能。
    依赖es model ,移除没有被引用的代码
    webpack 默认开启了这个功能,无需配置

    减少babel的体积
    babel 会为每个编译后的文件添加辅助代码
    Babel 对一些公共方法使用了非常小的辅助代码,比如 extend 。默认情况下会被添加到每一个需要它的文件中。
    你可以将这些辅助代码作为一个独立模块,来避免重复引入。

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

    1、安装

    npm i @babel/plugin-transform-runtime -D
    
    • 1

    2、配置

    {
                loader:'babel-loader',
                options:{
                  cacheDirectory:true, // 开启babel缓存
                  cacheCompression:false, // 关闭缓存文件压缩
                  plugins:["@babel/plugin-transform-runtime"],// 减少代码体积
                }
              }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    图片压缩
    插件官网介绍,使用方式直接参考官网,这里不记录了

    代码分割,优化代码运行性能
    我们打包时会将所有的js文件都打包到一个文件中,体积太大。如果我们只渲染首页,那么应该只加载首页的js文件,其他文件不需要加载。

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

    代码分割主要做了两件事情:
    1、将打包生成的文件分为多个js文件
    2、按需加载,需要哪个文件就加载哪个文件。

    多入口文件

    entry:{
        main:'./src/main.js',
        app:'./src/app.js'
      },
       output:{
        // path 是所有文件输出的路径
        path:path.resolve(__dirname,'../dist'),// 当前文件的文件夹目录的dist下面
        filename:'static/js/[name].js',
        clean:true
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    设置了多个入口文件,就会有多个输出文件。
    但是如果多个文件中引入了公共的函数,我们可以发现打包后的两个js文件中都引入了一边。
    我们希望,将公共的代码抽离出来,只需要写一次。

    可以在webpack的配置文件中添加配置,官网介绍

    optimization: {
        splitChunks:{
          chunks:'all',// 对所有模块都进行分割
          //修改配置
         cacheGroups: {// 组,哪些模块要打包到一个组
            default:{
              // 没有写的都是使用默认配置,单独写的会覆盖默认配置
              minSize:0 
            }
         }
         },
          /* 
          以下都是默认配置
          minSize:20000 分割代码最小的大小
          minRemainingSize: 0,// 类似于minsize,最后确保提取的文件大小不能为0,
          minChunks: 1,// 至少被引用的次数,满足条件才会代码分割
          maxAsyncRequests: 30,// 按需加较时并行加战的文件的最大数量
          maxInitialRequests: 30,// 入口js文件最大并行请求数量
          enforceSizeThreshold: 50000,// 超过5kb一定会单独打包(此时会忽略minRemainingSize
          cacheGroups: {// 组,哪些模块要打包到一个组
            defaultVendors:{ // 组名
              test: /[\V]node_modules[\V]/,// 需要打包到一起的模块 
              priority: -10,// 权重《越大越高》
              reuseExistingChunk: true,// 如果当前 chunk 包含已从主 bundle 中拆分出的模块
            },
            default:{// 其他没有写的配置会使用上面的默认值
              minChunks:2,// 这里的minChunks权重更大
              priority: -20,
              reuseExistingChunk: true.
            }
          }
    
    
         */
        minimizer: [
          // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
          // `...`,
          new CssMinimizerPlugin(),
          new TerserWebpackPlugin({
            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
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    添加完配置之后再次打包,多了一些文件
    在这里插入图片描述
    按需加载
    尽管我们实现了多模块输出,但是对于初始化时不需要加载的js文件,还是一次性加载了
    例如countjs文件中的方法,仅仅在按钮点击时才会触发,我们希望能异步加载整个文件。

    在这里插入图片描述
    动态引入,将文件代码分割,拆分成单独的模块,在需要使用的时候自动加载
    注意当调用 ES6 模块的 import() 方法(引入模块)时,必须指向模块的 .default 值,因为它才是 promise 被处理后返回的实际的 module 对象

    document.getElementById("btn").onclick = function () {
      import('./js/count').then((res)=>{
        console.log(res.default(9,1),'res');
      })
      .catch((err)=>{
        console.log('模块引入失败',err);
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这样我们可以看到只有点了按钮后才会加载count文件,manjs中没有引入

    在这里插入图片描述

    管理打包输出的文件名
    对于动态加载的文件
    在这里插入图片描述
    添加配置
    少了个]
    在这里插入图片描述
    查看效果
    在这里插入图片描述
    所有type为asset 的资源都可以在 output中统一设置输出

     assetModuleFilename:'static/css/[hash:10][ext][query]',
    
    • 1

    preload、prefetch
    前面已经做了代码分割,同时会使用import 动态导入语法来进行代码按需加载(路由懒加载就是这样实现的)
    但是如果动态加载的资源比较大,用户会感觉到明显的卡顿。
    所以我们希望浏览器在空闲的时候,能加载后续需要的资源、
    preload: 告诉浏览器立即加载资源,但是并不执行。优先级更高。只能加载当前页面资源。兼容性大约92%
    prefetch:告诉浏览器在空闲时间才开始加载资源。优先级低,可以加载当页面的也可以加载下一个页面的。兼容性大约72%

    缓存
    官网缓存介绍
    我们将dist文件部署到服务器后,客户端就可以通过访问站点来获取资源,浏览器都使用了一种缓存技术。
    然而,如果在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。由于缓存的存在,当你需要获取新的代码时,就会显得很棘手。
    我们可以给输出文件添加hash值,当内容变化再次构建时,hash会发生变化

     output: {
         filename: '[name].[contenthash].js',
          path: path.resolve(__dirname, 'dist'),
          clean: true,
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5

    那如果什么也不改,hash应该不变吧?
    还是变了!
    为什么呢?

    首页写我们先看下,在打包的时候想要把公共的模块提取出来,只加载一次。
    将 optimization.runtimeChunk 设置为 true 或 ‘multiple’,会为每个入口添加一个只含有 runtime 的额外 chunk。
    值 “single” 会创建一个在所有生成 chunk 之间共享的运行时文件。此设置是如下设置的别名:
    在这里插入图片描述

    由于像 lodash 或 react 这样的第三方库很少像本地源代码一样频繁修改,因此通常推荐将第三方库提取到单独的 vendor chunk 中。这一步将减少客户端对服务器的请求,同时保证自身代码与服务器一致。

       optimization: {
          runtimeChunk: 'single',
         splitChunks: {
           cacheGroups: {
             vendor: {
               test: /[\\/]node_modules[\\/]/,
               name: 'vendors',
               chunks: 'all',
             },
           },
         },
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这样可以大大减少mainjs 打包后的体积。

    回到上面的问题,为什么没有什么改动hash也变化 了?
    这是因为每个 module.id 会默认基于解析顺序(resolve order)增量。换言之,当解析顺序发生变化,ID 也会随之改变。简要概括便是:

    main bundle 会随着自身的新增内容的修改,而发生变化。
    vendor bundle 会随着自身的 module.id 的变化,而发生变化。
    manifest runtime 会因为现在包含一个新模块的引用,而发生变化。

    上面的第一点与最后一点都是符合预期的行为,而 vendor 的哈希值发生变化是我们要修复的。试试将 optimization.moduleIds 设置为 ‘deterministic’:

     optimization: {
         moduleIds: 'deterministic',
    
    • 1
    • 2

    现在,不论是否添加任何新的本地依赖,对于前后两次构建,vendor 的哈希值都应保持一致

    core-js
    过去我们引用了babel对js代码进行兼容性处理,其中使用@babel/preset-env 智能预设来处理兼容性问题。
    它能将es6的语法进行编译转换,但如果是async,promse等es6+的语法。它没办法处理。
    此时我们的js代码依然存在兼容性问题。
    core-js 是专门用老做es6 及以上api 的 polyfill(垫片)
    就是用社区上提供的一段代码。让我们在不兼容某些特性的浏览器上能够兼容。
    1、安装

    npm i core-js
    
    • 1

    2、引入

    import ‘core-js’
    
    • 1

    3、上面全部引入,体积太大,我们只想引入某一个

    import “core-js/es/promise”
    
    • 1

    4、每次使用一个都需要手动引入吗,太麻烦了。我们希望它能够实现自动引入,使用了那个就自动引入那个
    我们只需要在babel的配置文件中添加配置即可。

    module.export = {
     presets: [['@babel/preset-env',{
      useBuiltIns:'usage',// 按需自动引入
      corejs:3 // corejs的版本
     }]]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    PWA
    什么是pwa ? 渐进式网络应用程序
    一种可以提供类似于navtie app 体验的技术。
    在离线状态下应用程序依然能够继续运行。
    内部通过ServiceWorks 技术实现。
    webapck 应该帮我们封装好了,我们只需要使用即可。
    pwa的使用

    使用过程中报错了
    在这里插入图片描述
    因为我们注册的文件在dist下面
    我们可以下载一个专门用来部署静态资源服务器的库

    npm i serve -g
    
    • 1

    安装好后,通过

    serve dist
    
    • 1

    在这里插入图片描述
    然后我们就可以看到效果了,设置为离线状态再加载页面,页面缓存了刚才的内容。

    但是这个技术,目前兼容性并不好

    webpack 优化总结
    官网给的优化建议
    总结
    我们从 4 个角度对 webpack 和代码进行了优化:
    一、提升开发体验
    1、使用 source Map 让开发或上线时代码报错能有更加准确的错误提示。

    二、提升 webpack 提升打包构建速度
    1、使用HotModuleReplacement 让开发时只重新编译打包更新变化了的代码,不变的代码使用须存,从而使更新速度更快。
    2、使用 oneof 让资源文件一旦被某个loader 处理了,就不会继续遍历了,打包速度更快。
    3、使用 Include/Exclude 排除或只检测某些文件,处理的文件更少,速度更快。
    4、使用 Cache 对 eslint 和 babel 处理的结果进行缓存,让第二次打包速度更快。
    5、便用 Thead 多进程处理 eslint 和 babel 任务,速度更快(需要注意的是,进程启动通信都有开销的,要在比较多代码处理时使用才有效果)

    三、减少代码体积
    1、使用 Tree shaking 剔除了没有使用的多余代码,让代码体积更小。
    2、使用 @babel/plugin-transfor-runtime 插件对 babel 进行处理,让辅助代码从中入,而不是每个文件都生成辅助代码,从而体积更小
    3、使用 Image Minimizer 对项目中图片进行压缩,体积更小,请求速度更快。(需要注意的是,如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。)

    四、优化代码运行性能
    1、便用 code Split 对代码进行分割成多个js 文件,从而使单个文件体积更小,并行加载 js 速度更快。并通过 import 动态导入语法进行按需加载,从而达到需要使用时才加载该资源,不用时不加载资源。
    2、使用 Preload / Prefetch 对代码进行提前加载,等未来需要使用时就能直接使用,从而用户体验更好。
    3、便用 Network Cache 能对输出资源文件进行更好的命名,将来好做缓存,使用optimization.splitChunks 的cacheGroups 缓存第三方库,从而用户体验更好。
    4、使用 core-js对js 进行兼容性处理,让我们es6+代码能运行在低版本浏览器。
    5、使用 PWA 能让代码离线也能访问,从而提升用户体验。

    在react-cli 中配置webpack
    待学习

    在vue-cli 中配置webpack
    待学习

    下面部分是原理,了解即可

    loader 介绍
    我们前面用到了各种各样的loader,他可以帮助webpack将不同类型的文件转换成webpack可以识别的模块。
    loader的分类
    1、pre 前置
    2、normal 普通,默认
    3、inline 内联
    4、post 后置

    执行顺序:pre > normal > inline > post

    相同优先级的loader执行顺序为:从右到左,从下到上

    使用loader的两种方式
    1、配置方法

    在这里插入图片描述

    2、内联方式,在import 语法中显示指定loader
    不想写了,放个截图吧,不推荐使用这种方式引入
    在这里插入图片描述
    定义一个简单的loader
    定义
    在这里插入图片描述
    使用,相当于是一个函数
    在这里插入图片描述
    同步和异步loader

    /* 
    err d代表是否有错误
    content 处理后的内容
    source-map 继续传递给下一个loader
    meta 参数传递给下一个loader
    同步loader中不能进行异步处理
    */
    module.exports = function (content,map,meta) {
      this.callback(null,content,map,meta)
      
    };
    
    // 异步loader
    module.exports = function (content,map,meta) {
      const callback = this.async();
      setTimeout(()=>{
         callback(null,content,map,meta)
      },1000)
    
    }
    
    // raw loader 用于处理如本、字体等,接受的content 是buffer数据,二进制
    function rawLoader (content,map,meta) {
       return content;
    }
    rawLoader.raw = true;
    module.exports = rawLoader;
    
    //pitch loader 优先于normal 执行,并且是从左到右执行
    module.exports.pitch = function (content,map,meta) {
      return content;
    }
    
    
    • 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

    loader API
    更多关于api的介绍

    我们需要了解的几个
    在这里插入图片描述
    自定义loader

    // 自定义loader1
    module.exports = function (content) {
      // 清楚文件内容中所有的console
      return  content.replace(/console\.log\(.*\);?/g,'');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    还有一些pulgin的原理,不想看了,就学到这吧

  • 相关阅读:
    DataFrame的操作-使用SQL
    读取s3图片并保存至excel
    Java 实例:删除字符串中的一个字符和字符串替换
    博弈论——动态博弈
    Mysql应用日志时间与系统时间相差八小时
    PCL点云处理之利用颜色RGB的SHOT特征描述方法 (二百一十七)
    基于inotify实现落盘文件的跨进程实时读写交互
    【vue3|第20期】vue3中Vue Router路由器工作模式
    使用Jupyter Notebook调试PySpark程序错误总结
    CSS进阶篇——布局 (Layout)
  • 原文地址:https://blog.csdn.net/MissXu666/article/details/132999408