框架设计的核心要素
提升用户开发体验
在开发过程中需要有良好的警告信息,在Vue源码中,很多地方都用到了警示信息,比如:
warn(`Failed to mount app: mount target selector "${container}" returned null`)
除了警示信息,还有其他方面,如Ref,详细看P13
控制框架代码的体积
要在同样功能的情况下,使用更少的代码
提供完善的提示必然会增加代码体积,所以要解决这个问题
vue源码中,每一个warn函数都会配合__DEV__常量的检查,例如:
if(__DEV__ && !res){
warn(`Failed to mount app: mount target selector "${container}" returned null`)
}
__DEV__ 这个常量用于区分开发环境和生产环境,如果是开发环境,则__DEV__设置为true,如果为生产环境,则设置为false,所以生产环境中,上面那段代码就不会执行,也就是dead code,不会出现在最终的产物中,资源构建时会移除
做到良好的Tree-Shaking
Tree-shaking也就是摇树,指消除那些永远不会执行的代码,也就是排除dead code
实现工具(npm引入即可):rollup.js
实现Tree-shaking的前提:模块必须是ES module
Tree-shaking关键点:副作用
如果一个函数调用会产生副作用,那么就不能将其移除
- 副作用就是会对外部产生影响的函数调用
所以tree-shaking不能判断这种类型的代码,这时vue为我们提供了注释
/*__PURE__*,使用这个注释就是让代码对该函数放心地进行Tree-shaking产生副作用的代码都是顶级调用,所以我们只要对顶级调用进行注释就好了
函数内调用不会影响全局,所以不用注释,tree-shaking会自己分析
foo() //顶级调用 function bar(){ foo() //函数内调用 }
框架输出的构建产物
vue会对不同的使用场景输出不同形式的产物
-
直接使用
<script>标签引入:输出IIFE格式的资源,当使用标签引入的时候就会自动执行
rollup.js中,可以通过配置format:'iife'来输出这种形式的资源 -
支持ESM:
输出ESM格式的资源
rollup.js中,可以通过配置format:'esm'来输出这种形式的资源输出资源带有
-bundler和-browser的区别:-bundler:给roolup.js或者webpack等打包工具使用,这里不会使用__DEV__,而会使用(process.env.NODE_ENV !== 'production')来替换__DEV__,因为这样用户可以通过配置webpack来自行决定构建资源的目标环境,但是效果一样-browser:给<script type="module">使用,这里会使用前面说过的__DEV__ -
使用
require引入:Node.js环境中,资源的模块格式应该是CommonJS,为了输出cjs模块资源,可以通过修改
rollup.config.js的配置format:'cjs'来实现
特性开关
可以提供一系列特性给用户,用户需要则开启,不需要则关闭,在代码打包时也可以利用Tree-shaking对代码进行优化,在添加新特性的同时,不用担心资源体积变大
实现特性开关原理和__DEV__一样,也是通过一个常量来控制特性的开关,比如__FEATURE_OPTIONS_API__
使用例子:在vue3中推荐使用组合式API编写代码,但是同时也支持vue2的组件选项API,所以如果不需要组件选项API的话可以将其关闭,让打包时的体积减小
错误处理
错误处理是框架开发的重要环节,决定了用户应用程序的健壮性
框架提供的工具模块:
export default {
foo(fn){
fn && fn()
}
}
用户使用:
utils.foo(() => {...})
出错解决:
-
用户手动处理,使用
try catch,但是会增加用户负担 -
框架统一处理,将错误处理程序封装成一个函数
export default { foo(fn){ callWithErrorHanding(fn) } } function callWithErrorHanding(fn){ try{ fn && fn() }catch(e){ console.log(e) } }
进一步加强用户对错误的可控制性,提供一个函数,让用户可以使用它注册错误处理程序:
export default {
foo(fn){
callWithErrorHanding(fn)
},
registerErrorHanding(fn){ //用户可以调用这里的函数控制错误
handleError = fn
}
}
function callWithErrorHanding(fn){
try{
fn && fn()
}catch(e){
handleError(e)
}
}
vue中的注册统一的错误处理函数:
import App from 'APP.vue'
const app = creareApp(APP)
app.config.errHandler = () => {
//错误处理程序
}
良好的TS类型支持
使用TS编写框架和框架对TS类型支持友好是两件不同的事
略