文章目录
第二章 框架设计的核心要素
2.1 提升用户的开发体验
(1)友好的警告信息(Vue内部封装JS层面的错误)。
- 收集当前发送错误的组件栈信息
warn(
'Failed to mout app: mount target selector "${container}" returned null.'
)
(2)浏览器允许用户编写自定义fomatter(源码中initCustomFormatter函数用在开发环境初始化自定义formatter)
const count = ref(0)
console.log(conunt) //打印结果不直观,修改后DevTools的设置,勾选"console"->"Enable custom formatters",可使输出内容更直观
2.2 控制框架代码的体积
(1)Vue3的源码中,每个warn函数都会调用配合常量_DEV_来控制框架体积。
if(_DEV_ && !res){
warn(
'Failed to mout app: mount target selector "${container}" returned null.'
)
}
(2)Vue在输出资源时,有两个版本,一个是开发环境(vue.global.js)和生产环境(vue.global.prod.js)。
- 在开发环境下,常量_DEV_为true,生产环境下常量为false(即为dead code,在构建资源会被移除)
(3)在开发环境中为用户提供友好的警告信息的同时,不增加生成环境代码的体积。
2.3 框架要做到良好的Tree-Shaking
(1)Tree-Sharking:消除dead code()例如Vue中用户不会用的内置组件等等。
- webpack 或者rollup.js 都支持Tree-Shaking
- 要实现Tree-Shaking必须是基于ESM(Module),依赖ESM的静态结构
- Js的动态语言,要分析哪些的是dead code有难度,因为有可能会产生函数的副作用(有可能会对外部产生影响,例如修改了全局变量,像Proxy创建的代理对象,当被读取对象属性时,会触发代理对象的get夹子trap)
(2)可人为的告诉构建工具,移除代码。
- 使用注释代码 /*#-PURE- */
2.4 框架应该输出怎样的构建产物
(1)若希望用户直接在HTML中
<body>
<script src="/path/to/vue.js"></script>
<script>
const { creatApp } = Vue
// ...
</script>
</body>
// rollup.config.js
const config = {
input: 'input.js',
output:{
file: 'output.js'
format:'iife' //指定模块形式
}
}
export default config
(2)用户还可直接引入ESM格式的资源,在rollup.js输出格式配置:format:‘esm’。
<script type="module" src="/path/to/vue.esm-browser.js"></script>
- 带有-bundler字样的ESM资源是给rollup.js或webpack等打包使用,而-browser字样的ESM资源是直接给
(3)用户还可在Node.js通过require引用资源。
- 在进行服务端渲染时,Vue.js在Node.js环境中运行,在非浏览器环境下,资源模块为CommonJS,可通过修改rollup.config.js的配置 format: ‘cjs’。
2.5 特性开关
(1)用户通过设置特性开关来选择是否遗留选项API,从而使最终打包体积最小化。
if(_vue_OPTIONS_API_) { //注意这里,构建资源时,由之前的_EFATURE_OPTIONS_API_变成这个
currentInstance = instance
pauseTracking()
applyOptions(instance, Component)
resetTracking()
currentInstance = null
}
// webpack.DefinePlugin 插件配置
new webpack.DefinePlugin({
_VUE_OPTIONS_API_: JOSN.stringify(true) //开启特性
})
- _VUE_OPTIONS_API_是个特性开关,通常用户通过webpack.DefinePlugin插件实现
(2)特性开关的重要:由于VUE3兼容VUE2,所以VUE3仍然保留选项API,若用户确保不使用选项API,则可选择关闭该特性,从而减小资源体积
2.6 错误处理
//utils.js
let handleError = null
exporst default{
foo(fn){
callWithErrorHandling(fn)
},
Bar(fn){
callWithErrorHandling(fn)
},
//用户可以调用该函数注册统一的错误处理函数
registerErrorHandler(fun){
handleError = fn
}
}
function callWithErrorHandling(fn){
try{
fn && fn()
} catch (e){
//将捕获的错误传递给用户的错误处理程序
handleError(e)
}
}
- 用户可以使用registerErrorHandler 函数注册错误处理程序,然后在callWithErrorHandling函数内部捕获错误后传递给用户注册的错误处理程序
import App from 'App.vue'
const app = createApp(App)
app.config.errorHandler = () => {
//错误处理程序
}
2.7 良好的TypeScript类型支持
- TS是JS的超集,用TS的好处:降低低级bug,代码可维护性更强等