本章首先讲解了框架设计中关于开发体验的内容,开发体验是衡量一个框架的重要指标之一。 提供友好的警告信息至关重要,这有助于开发者快速定位问题,因为大多数情况下“框架”要比开发者更清楚问题出在哪里,因此在框架层面抛出有意义的警告信息是非常必要的。
但提供的警告信息越详细,就意味着框架体积越大。因此,为了框架体积不受警告信息的影响,我们需要利用 Tree-Shaking 机制,配合构建工具预定义常量的能力, 例如预定义 __DEV__
常量,从而实现仅在开发环境中打印警告信息,而生产环境中则不包含这些用于提升开发体验的代码,从而实现线上代码体积的可控性。
Tree-Shaking 是一种排除 dead code 的机制,框架中会内建多种能力,例如 Vue.js 内建的组件等。 对于用户可能用不到的能力,我们可以利用 Tree-Shaking 机制使最终打包的代码体积最小化。 另外,Tree-Shaking 本身基于 ESM,并且 JavaScript 是一门动态语言,通过纯静态分析的手段进行 Tree-Shaking 难度较大, 因此大部分工具能够识别 /*#__PURE__*/
注释,在编写框架代码时,我们可以利用 /*#__PURE__*/
注释来辅助构建工具进行 Tree-Shaking。
接着我们讨论了框架的输出产物,不同类型的产物是为了满足不同的需求。为了让用户能够通过 <script>
标签直接引用并使用, 我们需要输出 IIFE 格式的资源,即立即调用函数表达式。为了让用户能够通过 <script type="module">
引用并使用,我们需要输出 ESM 格式的资源。 这里需要注意的是,ESM 格式的资源有两种:用于浏览器的 esm-browser.js 和用于打包工具的 esm-bundler.js。它们的区别在于对预定义常量 DEV 的处理, 前者直接将 __DEV__
常量替换为字面量 true 或 false,后者则将 __DEV__
常量替换为process.env.NODE_ENV !== 'production' 语句。
框架会提供多种能力或功能。有时出于灵活性和兼容性的考虑,对于同样的任务,框架提供了两种解决方案, 例如 Vue.js 中的选项式 API 和组合式 API 都能用来完成页面的开发,两者虽然不互斥,但从框架设计的角度看,这完全是基于兼容性考虑的。 有时用户明确知道自己仅会使用组合式 API,而不会使用选项对象式 API,这时用户可以通过特性开关关闭对应的特性, 这样在打包的时候,用于实现对应特性功能的代码在对应特性被关闭时,就会被 Tree-Shaking 机制排除。
框架的错误处理做得好坏直接决定了用户应用程序的健壮性,同时还决定了用户开发应用时处理错误的心智负担。 框架需要为用户提供统一的错误处理接口,这样用户可以通过注册自定义的错误处理函数来处理全部的框架异常。
最后,我们点出了一个常见的认知误区,即“使用 TS 编写框架和框架对 TS 类型支持友好是两件完全不同的事”。有时候为了让框架提供更加友好的类型支持,甚至要花费比实现框架功能本身更多的时间和精力。