2. 框架设计的核心要素
2.1 提升用户的开发体验
- 提供友好的警告信息
- 打印的时候让输出的信息更友好
js
const count = ref(0);
console.log(count); // Ref<0>
2.2 控制框架代码的体积
在开发环境中为用户提供友好的警告信息的同时,不会增加生产环境代码的体积
js
// 通过 rollup.js 预定义 __DEV__ 常量,当 Vue 构建开发资源时,会把 __DEV__ 常量设置为 true
if (__DEV__ && !res) {
warn(
`Failed to mount app: mount target selector "${container}" returned null.`
);
}
2.3 框架要做到良好的 Tree-Shaking
概念:消除那些永远不会被执行的代码,也就是排除 dead code
- 想要实现 Tree-Shaking,模块必须是 ES Module ,因为 Tree-Shaking 依赖 ESM 的静态结构。
- 如果一个函数调用会产生副作用,那么打包工具就不会将其移除。但框架可以使用
/*#__PURE__*/
注释明确告诉打包工具移除该函数, - 该注释不仅仅作用于函数,也可以应用于任何语句上。该注释也不是只有 rollup.js 才能识别,webpack 以及压缩工具(如 terser)都能识别它
2.4 框架应该输出怎样的构建产物
vue.global.js 用于开发环境,它包含必要的警告信息,而 vue.global.prod.js 用于生产环境,不包含警告信息
不同类型的产物一定有对应的需求背景,因此需要从需求出发
js
// rollup.config.js
const config = {
input: "input.js",
output: {
file: "output.js",
format: "iife", // 指定模块形式 // es cjs umd
},
};
export default config;
无论是 rollup.js 还是 webpack,在寻找资源时,如果 package.json 中存在 module 字段,那么会优先使用 module 字段指向的资源来代替 main 字段指向的资源
2.5 特性开关
- 对于用户关闭的特性,我们可以利用 Tree-Shaking 机制让其不包含在最终的资源中
- 该机制为框架设计带来了灵活性,可以通过特性开关任意为框架添加新的特性,而不用担心资源体积变大
js
// example
// webpack.DefinePlugin 插件配置
new webpack.DefinePlugin({
__VUE_OPTIONS_API__: JSON.stringify(true), // 开启特性
});
2.6 错误处理
框架错误处理机制的好坏直接决定了用户应用程序的健壮性,还决定了用户开发时处理错误的心智负担
Vue.js 错误处理的原理
js
// utils.js
let handleError = null;
export default {
foo(fn) {
callWithErrorHandling(fn);
},
// 用户可以调用该函数注册统一的错误处理函数
registerErrorHandler(fn) {
handleError = fn;
},
};
function callWithErrorHandling(fn) {
try {
fn && fn();
} catch (e) {
// 将捕获到的错误传递给用户的错误处理程序
handleError(e);
}
}
// 使用
import utils from "utils.js";
// 注册错误处理程序
utils.registerErrorHandler((e) => {
console.log(e);
});
utils.foo(() => {
/*...*/
});
2.7 良好的 TypeScript 类型支持
- 使用 TS 的好处有很多,如代码即文档、编辑器自动提示、一定程度上能够避免低级 bug、代码的可维护性更强等
- 使用 TS 编写代码与对 TS 类型支持友好是两件事