Webpack - 知识点补充

7/20/2022

# webpack打包流程

# 基本概念

  1. compiler:webpack的运行入口,实例化时定义webpack构建主要流程,同时创建时使用的核心对象compilation;
  2. compilation:由compiler实例化,存储构建过程中使用的数据,用户监控这些数据的变化,每次构建创建一个compilation实例;
  3. chunk:一般一个入口对应一个chunk;
  4. Module:用于标示代码模块的类型,有很多子类用于处理不同情况的模块,模块相关信息都可以从Module实例中获取,例如dependiencies记录模块的依赖信息
  5. Parser:基于acorn来分析AST语法树,解析出代码模块的依赖
  6. Dependency:解析用于保存代码块对应的依赖使用对象
  7. template:生成最终代码要用到的代码模块

# 打包流程

  • 初始化参数: 从shell参数和配置文件合并参数,得出最终的参数
  • 开始编译:从上一步获得的参数初始化compiler对象,加载所有的插件,通过run方法执行编译。
  • 确定入口:根据配置文件的entry找出所有入口文件。
  • 编译模块:从入口文件开始,调用所有配置的loader对模块进行翻译成compliation,然后递归所有依赖的模块,然后重复编译。得到每个模块翻译后的最终内容以及它们之间的依赖关系。
  • 输出资源:根据入口和模块的依赖关系,组装成一个个包含多个模块的chunk,然后将chunk转换成一个单独的文件加入输出列表,这是可以修改输出内容的最后机会
  • 输出完成: 在确定好输出内容后,根据配置确定输出的路径和文件名,将文件的内容写入文件系统上。

# HMR热更新

  • 参考 (opens new window)
  • 总结就是,webpack和浏览器之间维护了一个websocket,当webpack的watch监听到文件变化,根据配置对模块重新编译打包, 然后通过websocket把打包各阶段的状态信息告知浏览器,浏览器根据这些socket信息进行不同的操作。(而webpack怎么监听和识别还有命名 文件呢,其实就是一串哈希值,每个文件都有一串独有的哈希值,如果变化了这个哈希值就会随之改变,是chunk那边的东西)。

# Loader 和 Plugin 的区别

  • 不同的作用
    1. Loader是加载器, 原生webpack只能解析js文件,如果想将其它文件也打包就要用loader,所以loader的作用是让webpack拥有了加载和解析js以外文件的能力。
    2. plugin是插件,也就是扩展webpack的功能,在webpack运行的生命周期中会广播出很多事件,plugin可以监听这些事件,并在合适的时机通过webpack的api改变输出结果。
  • 不同的用法
    1. Loader 在 module.rules 中配置,也就是说他作为模块的解析规则而存在。 类型 为数组,每一项都是一个 Object,里面描述了对于什么类型的文件(test),使用什么加载(loader) 和使用的参数(options)
    2. Plugin 在 plugins 中单独配置。 类型为数组,每一项是一个 plugin 的实例,参 数都通过构造函数传入。

# 长缓存优化?

  • 在webpack中,在output给输出的文件制定chunkhash,并分离经常更新的代码和框架 代码,通过NameModulesPlugin或者HashedmodulesPlugin使再次打包名不变。

# treeShaking

  • 摇树优化,通过移除多余代码优化打包体积。默认情况下生产环境是开启treeShaking的。

# babel 转译

  • 转译流程 分成三步:parse, transform, generate。
  • 简单来讲就是在parse阶段,把源码转成AST,在transform阶段,遍历和修改AST,最后generate阶段把AST打印为目标代码字符串,生成个sourcemap。
  • babel 工作原理
    • 参考 (opens new window)
    • ES6代码输入 => babylon进行解析 > 得到AST> plugin用babel-traverse对AST树进行遍历转译 => 得到新的AST树 => 用babel-generator通过AST树生成ES5代码
  • Plolyfill 垫片
    • babel默认只转换新的 JavaScript 语法,比如箭头函数、扩展运算(spread)。 不转换新的 API,例如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转译。如果想使用这些新的对象和方法,则需要为当前环境提供一个垫片(polyfill)。
    • Polyfill主要有三种@babel/polyfill
      • Babel 包含一个polyfill 库即@babel/polyfill。这个库里包含 regenerator 和 core-js。