新聞中心
1、寫在前面
在前面文章中,了解到框架的設(shè)計是一種權(quán)衡的藝術(shù),是需要宏觀把握各方面因素從而盡可能完善。其實,框架設(shè)計比想象中的復(fù)雜,并不是只有功能實現(xiàn)就完事,需要考慮如何提供給使用者構(gòu)建產(chǎn)物、如何讓其快速定位問題,需要有良好的使用交互體驗。

成都創(chuàng)新互聯(lián)公司是專業(yè)的鄂溫克網(wǎng)站建設(shè)公司,鄂溫克接單;提供網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè),網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行鄂溫克網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊,希望更多企業(yè)前來合作!
2、提升用戶體驗
衡量框架是否優(yōu)秀的重要指標(biāo),就是看它的開發(fā)體驗是否達(dá)到預(yù)期,需要為用戶提供良好直觀的交互指引和錯誤警示,幫助用戶快速理解和錯誤定位。
3、控制代碼體積
在進(jìn)行項目開發(fā)中,在實現(xiàn)相同功能代碼越簡潔、越少,在進(jìn)行打包壓縮體積后,在瀏覽器渲染加載資源的時間更少,就能夠換取提升用戶的使用體驗。在前面提到要給用戶完善豐富的警告信息,那么也就意味著編寫更多的代碼,這就違背了控制代碼體積的初衷。
對此,Vue3框架在設(shè)計源碼時,采用_DEV_進(jìn)行判斷是否為開發(fā)環(huán)境,從而讓一些代碼只在開發(fā)時進(jìn)行調(diào)用,也會構(gòu)建對應(yīng)的開發(fā)資源。在Vue.js中采用的打包工具是rollup,_DEV_ 是使用插件進(jìn)行預(yù)定義的,在進(jìn)行資源輸出時用于區(qū)分生產(chǎn)環(huán)境還是開發(fā)環(huán)境。
if(_DEV_ && !res){
warn(`Failed to mount app: mount target selector "${container}" returned null.`)
}當(dāng)在構(gòu)建生產(chǎn)環(huán)境的資源時,_DEV_的值為false,這時候上面的這段代碼將永遠(yuǎn)不會進(jìn)行執(zhí)行,這樣就成為了dead code,在構(gòu)建資源時就會被打包工具所移除(Tree-shaking)。
4、Tree-shaking
事實上,在我們實際項目開發(fā)中,有些Vue.js內(nèi)置的組件壓根沒有用不上,那么在構(gòu)建生產(chǎn)環(huán)境的資源時就不能讓它出現(xiàn),也就是Tree-shaking。Tree-shaking概念是由rollup推廣普及的,指的是消除那些永遠(yuǎn)不會被執(zhí)行的代碼,即排除dead code。
實現(xiàn)Tree-shaking功能,前提是依賴于文件的模塊必須是ESM(ES Module),即文件的靜態(tài)結(jié)構(gòu)是ESM。
在rollup中Tree-shaking是如何工作的呢?
demo文件結(jié)構(gòu):
|-- home
| |__ package.json
| |__ ping.js
| |__ chuan.js
安裝rollup:
yarn add rollup -D
ping.js和chuan.js文件內(nèi)容:
// ping.js
export function foo(obj){
obj && obj.foo
}
export function bar(obj){
obj && obj.bar
}
export function fun(obj){
obj && obj.fun
}
注意,我們在chuan.js文件中并沒有導(dǎo)入ping.js中的bar函數(shù)。
import {foo, fun} from "./ping"
// 告知rollup這是個純函數(shù),不會產(chǎn)生任何副作用,可以放心tree-shaking
/*#__PURE__*/ foo()
fun()使用命令進(jìn)行構(gòu)建,以chuan.js文件作為打包的入口,輸出ESM的文件模塊,打包后的輸出文件是bundle.js。
npx roolup chuan.js -f esm -o bundle.js
在執(zhí)行命令打包成功過后,我們可以輸出的bundle.js文件中只包含fun函數(shù)的相關(guān)代碼。而bar函數(shù)因為入口文件沒有導(dǎo)入,不會打包進(jìn)去,而foo函數(shù)前面加了/*#__PURE__*/代碼,即告知rollup這是個純函數(shù),不會產(chǎn)生任何副作用,可以放心tree-shaking。這樣,打包后的文件就只剩fun函數(shù)了。
//bundle.js
function fun(obj){
obj && obj.fun;
}
fun();
什么是tree-shaking的副作用呢?
經(jīng)常提到的副作用其實就是:當(dāng)調(diào)用函數(shù)時,會對外部產(chǎn)生影響,在rollup中如果函數(shù)調(diào)用時產(chǎn)生了副作用,就不能將其移除,因為會潛在的影響其他代碼。
打包工具是怎么知道哪些代碼可以放心移除呢?
rollup提供/*#__PURE__*/代碼,可以告知rollup這是個純函數(shù),不會產(chǎn)生任何副作用,可以放心tree-shaking。上面代碼片段中,在foo函數(shù)前添加/*#__PURE__*/,就可以做個標(biāo)記告知rollup可以對其tree-shaking,打包后的bundle.js文件也對應(yīng)將代碼進(jìn)行移除。其實/*#__PURE__*/可以用于任何代碼,不單單是函數(shù)。
在Vue.js框架的源碼中,我們可以發(fā)現(xiàn)大量的/*#__PURE__*/,但其實這并不會對使用者產(chǎn)生心智負(fù)擔(dān),因為通常產(chǎn)生副作用的代碼都是模塊內(nèi)頂級調(diào)用的,而沒有被頂級調(diào)用的代碼是不會產(chǎn)生副作用的。
什么是頂級調(diào)用?
fun();//頂級調(diào)用
function fun(obj){
obj && obj.fun;
}
function foo(){
fun();//函數(shù)中調(diào)用
}
5、構(gòu)建產(chǎn)物
Vue.js會不同的環(huán)境輸出不同的包,vue.global.js用于開發(fā)環(huán)境,vue.global.prod.js用于生產(chǎn)環(huán)境,在構(gòu)建產(chǎn)物時,會根據(jù)不同的需求輸出不同的構(gòu)建產(chǎn)物。
首先用戶直接可以在html頁面中使用script引入框架使用,根據(jù)不同需求構(gòu)建不同產(chǎn)物,需要輸出一種IIFE(立即調(diào)用的函數(shù)表達(dá)式)格式的資源。
const Vue = (function(){
//...
exports.createApp = createApp;
//...
return exports
})()這樣,在使用
_DEV_根據(jù)不同的值構(gòu)建不同的產(chǎn)物,當(dāng)_DEV_設(shè)置為true時,可用于生產(chǎn)環(huán)境從而被Tree-Shaking移除代碼。但是,當(dāng)我們構(gòu)建提供給打包工具的ESM格式的資源時,不能直接設(shè)置_DEV_的值,要使用process.env.NODE_ENV1=="production"進(jìn)行替換。在帶有-bundler后綴的資源文件會變成:
if(process.env.NODE_ENV1=="production"){
warn(`useCssModule() is not supported in the global build.`)
}6、特性開關(guān)
在設(shè)計框架時會為用戶提供諸多特性功能,用戶可以根據(jù)自己的需要開啟或關(guān)閉對應(yīng)的特性。
- 對于用戶關(guān)閉的特性,可以使用Tree-Shaking機制將代碼從資源中清除。
- 開關(guān)特性可以提升框架的靈活性,可以通過特性開關(guān)在框架任意添加新特性,在框架升級時可以開啟使用上版本API的支持,從而減少代碼打包資源的體積。
在Vue.js3框架設(shè)計中,為了減少框架升級對于之前版本的兼容性,為用戶提供了__VUE_OPTIONS_API__開關(guān)來判斷是否要開啟對options API的兼容。
7、錯誤處理
錯誤處理是框架設(shè)計最重要的環(huán)節(jié),可以決定用戶應(yīng)用程序的健壯性,降低開發(fā)者在處理報錯時的心智負(fù)擔(dān)。在utils.js的模塊可以導(dǎo)出一個包含foo函數(shù),接收一個回調(diào)函數(shù)作為參數(shù),調(diào)用foo函數(shù)時會執(zhí)行回調(diào)函數(shù)。
//utils.js
export default {
foo(fn){
fn && fn();
}
}
使用進(jìn)行開發(fā)時,直接導(dǎo)入utils.js文件調(diào)用foo函數(shù)。
import utils from "utils.js";
utils.foo(()=>{
//...
})
如果用戶提供了回調(diào)函數(shù)在執(zhí)行時報錯,那么就需要用戶不斷地使用try...catch...捕獲和拋出錯誤,毫無疑問這會增加用戶的心智負(fù)擔(dān)。如果Vue.js框架已經(jīng)在內(nèi)部封裝了許多try...catch...的錯誤處理函數(shù)callWithErrorHandling,那么用戶在使用的時候代碼就簡潔很多,而且能夠為用戶提供統(tǒng)一處理的接口。
//utils.js
let handlerError = null;
export default {
foo(fn){
callWithErrorHandling(fn)
},
//用戶可以調(diào)用該函數(shù)注冊統(tǒng)一的錯誤處理函數(shù)
registerErrorHandling(fn){
handlError = fn
}
}
function registerErrorHandling(fn){
try{
fn && fn()
}catch(e){
//將捕獲到的錯誤拋出給用戶進(jìn)行處理
handlerError(e)
}
}
此外,Vue.js提供了registerErrorHandler函數(shù)注冊錯誤處理程序,callWithErrorHandling函數(shù)捕獲錯誤后會拋出給用戶注冊的錯誤處理程序。
import utils from "utils.js";
//注冊錯誤處理程序
utils.registerErrorHandler(e=>{
console.log(e)
})
utils.foo(()=>{//...})
utils.bar(()=>{//...})
此時用戶的代碼非常簡潔健壯,錯誤的處理能力就完全由用戶控制,也可以在Vue.js文件中注冊統(tǒng)一的錯誤處理函數(shù)。
import App from "App.vue"
const app = createApp(App);
app.config.errHandler = ()=>{
//錯誤處理程序
}
8、寫在最后
在本文中主要介紹了開發(fā)體驗、tree-shaking以及錯誤處理等對框架設(shè)計的重要性,提供良好的警告信息可以有助于開發(fā)者快速定位問題,框架提供錯誤處理API能夠提升用戶應(yīng)用程序的健壯性。tree-shaking可以用于打包文件的時候移除dead code,根據(jù)不同的環(huán)境構(gòu)建不同的資源產(chǎn)物,從而減少代碼打包的體積。此外還給用戶提供了各種特性開關(guān),__VUE_OPTIONS_API__可以用于設(shè)置Vue.js3對于option API的兼容性。
當(dāng)前名稱:Vue.js設(shè)計與實現(xiàn)-框架設(shè)計的核心要素
網(wǎng)頁地址:http://fisionsoft.com.cn/article/djjpgih.html


咨詢
建站咨詢
