Vue.js 设计与实现 知识点 Vol. 3 | 青训营笔记

115 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的的第22天

我将创作一些 Vue.js 学习相关的笔记。

《Vue.js设计与实现》笔记 Vol. 3

框架设计的核心要素

框架要做到良好的 Tree-Shaking

Tree-Shaking 指的就是消除那些永远不会被执行的代码,也就是排除 dead code。

rollup.js 和 webpack 都支持 Tree-Shaking。

想要实现 Tree-Shaking,必须满足模块是 ES Module,因为 Tree-Shaking 依赖 ESM 的静态结构。

对于副作用:如果一个函数调用会产生副作用,即当调用函数的时候会对外部产生影响,例如修改了全局变量,那么 Tree-Shaking 就不能将其移除。

到底会不会产生副作用,只有代码真正运行的时候才能知道,JavaScript 本身是动态语言,想要静态地分析哪些代码是 dead code 很困难,所以 rollup.js 提供了一个机制,可以声明某段但代码不会有副作用:

/**
 * Make a map and return a function for checking if a key
 * is in that map.
 * IMPORTANT: all calls of this function must be prefixed with
 * \/\*#\_\_PURE\_\_\*\/
 * So that rollup can tree-shake them if necessary.
 */
export function makeMap(
  str: string,
  expectsLowerCase?: boolean
): (key: string) => boolean {
  const map: Record<string, boolean> = Object.create(null)
  const list: Array<string> = str.split(',')
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true
  }
  return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]
}

使用 makeMap 函数必须在前面加上 \/\*#\_\_PURE\_\_\*\/,其作用就是告诉 rollup.js,对于 makeMap 函数的调用不会产生副作用,可以放心对其进行 Tree-Shaking。

框架应该输出怎样的构建产物

不同类型的产物是为了满足不同的需求。

为了让用户能够通过 <script> 标签直接引用框架并使用,我们需要输出 IIFE 格式的资源,,即立即调用的函数表达式。

为了让用户能够通过 <script type = 'module'> 标签直接引用框架并使用,我们需要输出 ESM 格式的资源。

ESM 格式的资源有两种:用于浏览器的 esm-browser.js 和用于打包工具的 esm-bundler.js。前者直接将 DEV 常量替换为字面量 true 或 false,后者则将 DEV 常量替换为 process.env.NODE_ENV !== 'production' 语句。

对于选项式 API 和 组合式 API,如果用户明知道只会使用其中一种,可以通过特性开关关闭对应的特性,这样打包时实现关闭功能的代码会被 Tree-Shaking 机制排除。

框架需要为用户提供统一的错误处理接口,这样用户可以通过注册自定义的错误处理函数来处理全部的框架异常。

为了让框架提供更加友好的 TS 类型支持,甚至要花费比视线框架功能更多的时间和精力。

感想

Tree-Shaking 不仅仅是删除不会被运行的代码,其背后还有海量的细节,令人叹为观止。

引用参考

霍春阳. Vue.js设计与实现[M]. 1. 北京:人民邮电出版社, 2022.