02-框架设计核心要素

182 阅读3分钟

框架设计的核心要素

提升用户开发体验

在开发过程中需要有良好的警告信息,在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类型支持友好是两件不同的事