• Webpack


    1. 对webpack的理解

    1.1 模块化

    模块化就是根据文件划分的形式,将每个功能及其相关的数据放在一个JS中,每个JS文件就是一个单独的模块,在需要时再去引入。

    这样的模块化有一个缺点就是:模块都是在全局中,容易造成全局变量污染,命名冲突;而且模块与模块之间并没有依赖关系,维护困难。

    1.2 webpack

    webpack是一个前端应用程序静态打包工具,它的目标是实现前端项目的模块化,皆在更高效地管理和维护项目中的每一个资源

    1.2.1 静态模块

    静态模块是指开发阶段可以被webpack直接引用的资源(可以直接被获取打包进bundle.js的资源)。当webpack处理项目时,它会在内部构建一个依赖图,此依赖图对应项目所需的每个模块,并生成一个或多个bundle
    请添加图片描述

    2. webpack的构建流程

    请添加图片描述
    webpack的构建流程是一个串行的过程,它的工作流程就是将各个插件串联起来。

    webpack的构建流程分为以下三步:

    • 初始化流程:从配置文件和Shell语句中读取参数、合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数。
    • 编译构建流程:从Entry触发,针对每个Module串行调用对应的Loader编译文件内容,再找到该Module依赖的Module,递归地进行编译处理。
    • 输出流程:对编译后的Module组合成Chunk,把Chunk转换成文件,输出到文件系统
    var path = require('path');
    var node_modules = path.resolve(__dirname, 'node_modules');
    var pathToReact = path.resolve(node_modules, 'react/dist/react.min.js');
    
    module.exports = {
      // 入口文件,是模块构建的起点,同时每一个入口文件对应最后生成的一个 chunk。
      entry: './path/to/my/entry/file.js',
      // 文件路径指向(可加快打包过程)。
      resolve: {
        alias: {
          'react': pathToReact
        }
      },
      // 生成文件,是模块构建的终点,包括输出文件与输出路径。
      output: {
        path: path.resolve(__dirname, 'build'),
        filename: '[name].js'
      },
      // 这里配置了处理各模块的 loader ,包括 css 预处理 loader ,es6 编译 loader,图片处理 loader。
      module: {
        loaders: [
          {
            test: /\.js$/,
            loader: 'babel',
            query: {
              presets: ['es2015', 'react']
            }
          }
        ],
        noParse: [pathToReact]
      },
      // webpack 各插件对象,在 webpack 的事件流中执行对应的方法。
      plugins: [
        new webpack.HotModuleReplacementPlugin()
      ]
    };
    
    • 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

    2.1 编译阶段构建流程

    1. 初始化参数:从配置文件和Shell命令中读取、合并参数,写到Options对象中
    2. 开始编译:初始化Compiler对象,加载所有配置的插件,调用Compilerrun方法来启动webpack的构建流程
    3. 确定入口:找到entry,确定入口文件
    4. 编译模块:从入口文件出发,根据每个Module调用对应的Loader编译文件内容,再找到该Module依赖的Module,递归进行编译,得到每个Module之间的依赖关系
    5. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk,再把每个Chunk转换成一个单独的文件加入到输出列表
    6. 输出完成:根据配置好的文件输出路径将文件内容写到文件系统中

    在上述过程中,webpack会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用webpack提供的API改变webpack的运行结果。

    3. 常见的Loader

    对于不同类型的资源,webpack有对应模块加载器loader

    3.1 css相关loader

    • css-loader:加载CSS。只负责加载CSS文件,如果样式生效,还需要style-loader配合
    • style-loader:将css-loader生成的内容用style标签注入到页面的head
    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/,
            use: [
              { loader: 'style-loader' },
              {
                loader: 'css-loader',
                options: {
                  modules: true
                }
              },
              { loader: 'sass-loader' }
            ]
          }
        ]
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    多个`loader`的加载方式是从右到左,从下到上
    
    • 1
    • less-loader/sass-loader:解析lesssasscss

    3.2 JS相关loader

    • ts-loader:将TS转换为JS
    • babel-laoder:将ES6解析为ES5
    • eslint-loader:检查JS代码规范

    3.3 静态资源的loader

    • file-loader:将文件输出到指定目录,并将该资源的地址返回
    • url-loader:与file-loader类似,但遇到图片格式的文件可以选择性的把图片转成base64格式的字符串,并打包到js中。对小体积的图片合适,对大图片不合适。

    4. 常见的Plugin

    • provider-plugin:将指定的模块暴露到全局,使用时就不需要再import或者require
    • html-webpack-plugin:在打包结束后,自动生成一个html文件,将打包生成的js模块引入到该html
    • hot-module-replacement-plugin:热更新。通过监听本地代码的变化,自动构建,自动刷新页面
    • uglifyjs-webpack-plugin:压缩JS代码,去掉console.log()、注释等代码,减少文件的字节数,提升构建效率
    • mini-css-extract-plugin:提取CSS,实现按需加载
    • webpack-parallel-uglify-plugin:多核压缩,提升压缩速度

    5. loader和plugin的区别

    5.1 运行时机不同

    • loader运行在打包文件之前。
    • plugin在整个编译周期内都起作用。webpack会在特定的时间点广播特定的事件,plugin会监听这些事件,对感兴趣的事件进行执行。plugin还可以调用wepack提供的API来改变webpack的执行结果。

    5.2 功能不同

    • loader是文件加载器,能够加载资源文件,并对这些文件进行处理
    • plugin扩展了webpack的功能,例如打包优化、压缩代码等

    6. webpack常见的功能

    • 代码转换:TS编译成JS;ES6转换为ES5;less、sass编译成CSS等
    • 代码语法检测:检查代码是否符合语法
    • 代码分割:打包代码时,可以将代码分割成不同的chunk(块),实现按需加载,降低了项目初始化时间,提升受屏渲染效率
    • 热更新:监听本地源代码的变化,自动构建,刷新页面
    • 文件压缩:压缩JS、HTML、CSS文件体积
    • 模块合并:由于模块化开发,一个页面可能会需要加载多个模块,所以编译时需要将多个模块进行合并

    7. bundlechunkmodule的区别

    • module:webpack可以解析的模块,多个module之间存在依赖关系
    • chunk:包含一个或多个module,代码分割加载的就是chunk
    • bundle:包含一个或多个chunk,是webpack最终打包出来的代码文件

    我们写的源文件module传送到webpack进行打包时,webpack会根据module之间的依赖关系生成chunk文件,webpack会对这些chunk文件进行操作,比如实现按需加载。webpack处理好chunk后最终输出bundle文件,bundle由一个或多个chunk文件构成,bundle包含了经过加载和编译最终生成的源文件,可以直接在浏览器中运行。

    8. Babel的原理

    1. 将代码转换为AST,分为两个阶段,词法分析和语法分析
      • 词法分析阶段把字符串形式的代码转换为tokens流
      • 语法分析就是根据tokens流转换成AST
    2. 使用@babel/traverse方法对AST进行遍历,完成对AST节点的替换、删除或增加操作,返回转换后的AST
    3. 使用@babel/generator将AST转换成字符串形式的代码

    9. Tree Shaking的原理

    Tree-Shaking主要从以下三个方面进行优化:

    • 代码不会被执行到的
    • 代码执行的结果不会被用到的
    • 变量或函数定义了但没有被使用到的

    首先,Tree-Shaking分为以下两步:

    1. 标记出模块导出值哪些没有被用过
      • Make阶段:收集导出的变量并记录到模块依赖图**ModuleGraph**中
      • Seal阶段:遍历**ModuleGraph**标记模块导出有没有被使用
      • 若没有使用则删除对应的导出语句
    2. 使用Terser删除掉没有被用到的导出语句

    10. 热更新的原理

    1. webpack Complier对象将源代码与HMR Runtime一起编译成bundle文件,HMR Runtime是一个socket服务器,会被注入到浏览器,更新文件的变化
    2. 客户端与服务器建立websocket连接,客户端运行的HRM Runtime,服务器端运行的是HRM Server
    3. webpack监听文件的变化,如果发生变化,重新编译打包后再推送给客户端,编译生成唯一的hash值,这个hash值用来作为下一次热更新的标识
    4. 根据变化的内容生成两个补丁文件:manifest(包含了hashchunkId,用来说明变化的内容)和chunk.js
    5. 服务器向客户端推送一条消息,包含文件改动后生成的hash
    6. 客户端发送ajax请求,根据hash获取包含变化内容的manifest文件
    7. 客户端根据manifest替换掉旧的内容实现局部更新

    11. 如何用webpack优化前端性能

    • 压缩代码
      • 对于JS:利用UglifyJsPlugin ParallelUglifyPlugin 来压缩JS⽂件
      • 对于CSS:利用css-minimizer-webpack-plugin压缩css
    • 利用CDN加速:将静态资源文件修改为CDN上对应的路径,提高对静态资源的访问速度
    • chunk分为更小的chunk,对css提取到单独的文件中,控制资源加载的优先级,实现按需加载,提高首屏渲染速度
    • Tree Shaking:将代码永远走不到的片段删除
    • 提取公共模块,利用浏览器缓存对这些长期不变动的模块进行缓存
    • 延迟加载(懒加载):使用import加载,将import放到异步回调函数中,异步函数执行后再去加载
    • 预加载:等浏览器空闲,让出主线程后再去加载

    12. 如何提高webpack的打包速度

    • 将不怎么更新的第三方库脱离webpack的打包
    • 将一些不会改动的代码先打包成静态资源,避免反复编译浪费时间

    13. 如何提高webpack的构建速度

    • 使⽤ webpack-uglify-parallel 来提升 uglifyPlugin 的压缩速度。 原理上 webpack-uglify-parallel采⽤了多核并⾏压缩来提升压缩速度
    • 使⽤ Tree-shaking来剔除多余代码
    • 对代码、图片进行压缩
    • 提取公共资源
    • 使用缓存:webpack.cachehappypack.cachebabel-loader.cacheDirctory都可以提高二次构建的速度

    14. 为什么webpack的文件名要加hash值

    hash一般结合CDN缓存来使用,通过webpack构建之后,生成对应文件名自动带上对应的MD5值,如果文件内容改变的话,那么对应文件哈希值也会改变,对应的HTML引用的URL地址也会发生改变,触发CDN回源,进行更新CDN节点缓存。

    14.1 chunkhash

    chunkhash是根据chunk来生成hash值的,chunkhash实现了模块的异步加载。

    14.2 contenthash

    chunkhash存在一个问题,就是当在一个JS中引入CSS,编译后它们的hash是相同的,而且只要js发生改变 ,关联csshash也会改变。

    这个时候可以使用mini-css-extract-plugin里的contenthash值,保证css所处的模块里就算其他文件内容改变,只要css内容不变,那么不会重复构建。

    15. CSS Modules

    CSS Modules是以模块化的形式引入CSS,使用CSS Modules可以防止样式覆盖,防止CSS命名冲突,做到样式隔离。

    15.1 基本使用

    1. 首先在webpack上进行配置并启用CSS Modules:
    {
       test: /\.css$/,
       loaders: [
          'style-loader',
          'css-loader?modules'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 创建一个modules.css文件,内容为:
    .color {
        color: red;
    }
    
    • 1
    • 2
    • 3
    1. 引入modules,可以直接引入整个modules,也可以按需引入
    // 整体引入
    import modules from './modules.css'
    // 按需引入
    import { color } from './modules.css'
    
    • 1
    • 2
    • 3
    • 4
    1. 使用modules
    class Cssmodules extends React.Component {
      render() {
        return (
          

    基本用法

    这是整体引入的红色文字

    这是通过按需引入红色文字

    ) } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    15.2 CSS Modules的作用域

    作用域分为局部作用域和全局作用域。像上面那样不管是modules.color还是color都属于局部作用。在DOM中,对应的类名会变成一个唯一的hash字符串,只有在当前作用域才有效,这也是一个模块化的体现。

    如果想要申明全局作用域,需要在前面加上:global关键字

  • 相关阅读:
    React18入门(第五篇)——React Router详细使用教程
    8款提高小团队协作效率的app软件,你用过几款?
    【MySQL基础 安装】CentOS 7 Yum网络部署 最新官方MySQL5 2020_2_1
    QDockWidget DEMO 动态添加QDockWidget ,无主窗口,禁止tab重叠
    山西电力市场日前价格预测【2023-09-30】
    开源模型应用落地-业务优化篇(八)
    第十四届蓝桥杯(第二期)模拟赛试题与题解 C++
    提出问题,解答问题!这才是理解代码设计的正确方法
    湖南成考学位英语考试有模拟测试吗
    LeetCode-复原 IP 地址(C++)
  • 原文地址:https://blog.csdn.net/qq_43539854/article/details/125998918