摘要:Vue 3已經發布有一段時間了,到底有哪些新特性值得關注,如何用它構建企業級前端項目,怎樣快速上手Vue 3?本篇文章將對此進行詳細講解。
前言
工欲善其事,必先利其器 --《論語》前端
在現在被三大框架支配的前端領域,已經不多有人不知道 Vue 了。2014 年,前 Google 工程師尤雨溪發佈了所謂的漸進式(Progressive)前端應用框架 Vue,其簡化的模版綁定和組件化思想給當時仍是 jQuery 時代的前端領域產生了積極而深遠的影響。Vue 的誕生,造福了那些不習慣 TS 或 JSX 語法的前端開發者。並且,Vue 較低的學習門檻,也讓初學者很是容易上手。這也是爲何 Vue 能在短期內迅速推廣的重要緣由。從 State of JS 的調查中能夠看到,Vue 的知名度接近 100%,並且總體用戶滿意度也比較高。vue
Vue 既強大又易學,這是否是意味着 Vue 是一個完美框架呢?很遺憾,答案是否認的。雖然 Vue 的上手門檻不高,靈活易用,可是這種優點同時也成爲了一把雙刃劍,爲構建大型項目帶來了必定的侷限性。不少用 Vue 2 開發過大型項目的前端工程師對 Vue 是又愛又恨。不過,隨着 Vue 3 的發佈,這些開發大型項目時凸顯出來的劣勢獲得了有效解決,這讓 Vue 框架變得很是全能,真正具有了跟 「前端框架一哥」 React 一爭高下的潛力。Vue 3 究竟帶來了什麼重要的新特性呢?本篇文章將對此進行詳細介紹。git
Vue 概覽
Vue 是前 Google 工程師尤雨溪於 2013 年開發、2014 年發佈的前端框架。關於 Vue 的具體定義,這裏摘抄 Vue 官網裏的介紹。github
Vue (讀音 /vjuː/,相似於 view) 是一套用於構建用戶界面的漸進式框架。與其它大型框架不一樣的是,Vue 被設計爲能夠自底向上逐層應用。Vue 的核心庫只關注視圖層,不只易於上手,還便於與第三方庫或既有項目整合。另外一方面, 當與現代化的工具鏈以及各類支持類庫結合使用時, Vue 也徹底可以爲複雜的單頁應用提供驅動。vuex
漸進式框架
不少人可能不理解漸進式框架(Progressive Framework)的含義。這裏簡單解釋一下。漸進主要是針對項目開發過程來講的。傳統的軟件項目開發一般是瀑布流式(Waterfall)的,也就是說,軟件設計開發任務一般有明確的時間線,任務與任務之間有明確的依賴關係,這意味着項目的不肯定性容忍度(Intolerance to Uncertainty)比較低。這種開發模式在現代日趨複雜而快速變化的商業情景已經顯得比較過期了,由於不少時候需求是不肯定的,這會給項目帶來很大的風險。typescript
而漸進式框架或漸進式開發模式則能夠解決這種問題。以 Vue 爲例:項目開始時,功能要求簡單,能夠用一些比較簡單的 API;當項目逐漸開發,一些公共組件須要抽象出來,所以用到了 Vue 的組件化功能;當項目變得很是大的時候,能夠引用 Vue Router 或者 Vuex 等模塊來進一步工程化前端系統。看到了麼,這樣一來,開發流程變得很是敏捷,不用提早設計整個系統,只用按需開發,所以能夠快速開發產品原型以及擴展到生產系統。json
框架特性
Vue 是利用模版語法來渲染頁面的,這也稱作聲明式渲染。Vue 好上手的重要緣由也是由於這個,由於它符合了前端開發者的習慣。例以下面這個例子。後端
<div id="app"> {{message}} </div> <script> var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } }) </script>
能夠看到,el 指定 Vue 實例綁定的元素,data 中的 message 與 DOM 元素的內容進行綁定。只須要操控 JS 中的數據,HTML 內容也會隨之改變。設計模式
另外,Vue 將 HTML、CSS、JS 所有整合在同一個文件 .vue 中,以組件化應用構建的方式來組織代碼,從語法特性上鼓勵 「高內聚、低耦合」 的設計理念,讓代碼組織變得更加合理,提高了可讀性與邏輯性。下面是一個官方網站給出的基礎 .vue 文件例子。前端工程化
<template> <p>{{ greeting }} World!</p> </template> <script> module.exports = { data: function () { return { greeting: 'Hello' } } } </script> <style scoped> p { font-size: 2em; text-align: center; } </style>
組件的骨架(HTML)、樣式(CSS)和數據或操做(JS)都在同一個地方,開發者須要思考如何將整個系統拆分紅更小的子模塊,或者組件。這對於構建大型項目是很是有幫助的。
其實,除了上述兩個特色,Vue 還有不少其餘的實用特性,但限於篇幅的緣由,咱們這裏不詳細解釋了。感興趣的讀者能夠去[官方網站深刻了解。
框架缺點
沒有什麼東西是完美的,Vue 一樣如此。當 Vue 的知名度和用戶量不斷增長時,一些前端開發者開始抱怨 Vue 的靈活性過高致使構建大型項目時缺乏約束,從而容易產生大量 bug。甚至使用 Vue 生態圈裏的狀態管理系統 Vuex 也沒法有效解決。關於 Vue 是否適合大型項目的問題,網上有很多爭論,甚至尤大本人都親自上知乎參與了討論(吃瓜傳送門)。
客觀來說,Vue 雖然具備較低的上手門檻,但這並不意味着 Vue 不適合開發大型項目。然而,咱們也必須認可大型項目一般要求較高的穩定性和可維護性,而 Vue 框架較高的靈活性以及缺乏足夠的約束讓其容易被經驗不足的前端開發者所濫用,從而產生臭不可聞的、難以直視的 「屎山」 代碼。其實,代碼可維護性並不強制要求較低的靈活性與自由度,只是這種自由可能會對項目的總體穩定帶來風險。
Vue 做者尤雨溪其實很早就注意到這個問題,所以纔會打算從底層重構 Vue,讓其更好的支持 TypeScript。這就是 2020 年 9 月發佈的 Vue 3。
Vue 3 新特性
Vue 3 有不少實用的新特性,包括TS 支持、組合式 API 以及 Teleport 等等。本文不是關於 Vue 3 的參考文,所以不會介紹其中所有的新特性,咱們只會關注其中比較重要的特性,尤爲是能增強代碼約束的 TypeScript(簡稱 TS)。
TS 支持
技術上來講,TS 支持並非 Vue 3 的新特性,由於 Vue 2 版本就已經可以支持 TS 了。但 Vue 2 版本的 TS 支持, 是經過 vue-class-component 這種蹩腳的裝飾器方式來實現的。 筆者對 「蹩腳」 這個評價深有體會,由於筆者曾經遷移過 Vue 2 版本的生產環境項目,最後發現收益並不高:語法有很大的不一樣,花了大量時間來重構,發現只提高了一些代碼的規範性,可是代碼總體變得更臃腫了,可讀性變得更差。
而在 Vue 3 中,TS 是原生支持的,由於 Vue 3 自己就是用 TS 編寫的,TS 成爲了 Vue 3 中的 「一等公民」。TS 支持在我看來是 Vue 3 中最重要的特性,特別是對構建大型前端項目來講。爲何說它重要?由於 TS 有效的解決了前端工程化和規模化的問題,它在代碼規範和設計模式上極大的提升代碼質量,進而加強系統的可靠性、穩定性和可維護性。關於 TS 的重要性,筆者在該公衆號前一篇文章《爲何說 TypeScript 是開發大型前端項目的必備語言》已經作了詳細介紹,感興趣的讀者能夠繼續深刻閱讀一下。
Vue 3 定義了不少 TS 接口(Interface)和類型(Type),幫助開發者定義和約束各個變量、方法、類的種類。下面就是一個很是基礎的例子。
import { defineComponent } from 'vue' // 定義 Book 接口 interface Book { title: string author: string year: number } // defineComponent 定義組件類型 const Component = defineComponent({ data() { return { book: { title: 'Vue 3 Guide', author: 'Vue Team', year: 2020 } as Book // as Book 是一個斷言 } } })
上述代碼經過 defineComponent 定義了組件類型,而在 data 裏定義了內部變量 book,這個是經過接口 Book 來定義的。所以,其餘組件在引用該組件時,就可以自動推斷出該組件的類型、內部變量類型,等等。若是引用方與被引用方的任何一個接口、變量類型不一致,TS 就會拋錯,讓你能夠提早規避不少錯誤。
雖然 Vue 3 在傳統定義 Vue 實例方式中(Options API)可以很好的支持 TS,可是咱們更推薦用 TS 配合另外一種新的方式來定義 Vue 實例,也就是接下來要介紹的組合式 API(Compositional API)。
組合式 API
組合式 API 的誕生是來自於大型項目中沒法優雅而有效地複用大量組件的問題。若是你已經瞭解 Vue,你或許應該知道以前版本的 Vue 實例中包含不少固定的 API,包括 data、computed、methods 等。這種定義方式有個比較突出的問題:它將 Vue 實例中的功能按照類型的不一樣分別固定在不一樣的 API 中,而沒有根據實際的功能來劃分,這將致使一個複雜組件中的代碼變得很是散亂,就像以下這張圖同樣。
在這個 「科學怪人」 式的傳統組件中,同一種顏色的代碼負責同一種功能,但它們卻根據不一樣類型分散在不一樣的區域,這將致使初次接觸該組件的開發人員難以快速理解整個組件的功能和邏輯。而組合式 API 則容許開發者將組件中相關的功能和變量聚合在一個地方,在外部按需引用,從而避免了傳統方式的邏輯散亂問題。
在 Vue 3 的組合式 API 中,全部功能和邏輯只須要定義在 setup 這個方法中。setup 接受屬性 props 和上下文 context 兩個參數,並在方法內部定義所須要的變量和方法,返回值是包含公共變量和方法的對象,它們能夠供其餘組件和模塊使用。傳統 Vue 實例的大部分 API,例如 data、computed、methods 等,均可以在 setup 中定義。下面是官網關於組合式 API 的例子。
// src/components/UserRepositories.vue import { toRefs } from 'vue' import useUserRepositories from '@/composables/useUserRepositories' import useRepositoryNameSearch from '@/composables/useRepositoryNameSearch' import useRepositoryFilters from '@/composables/useRepositoryFilters' export default { // 引用子組件 components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList }, // 屬性 props: { user: { type: String } }, setup(props) { // 解構屬性,若是直接在 setup 中引用,必需要加 toRefs const { user } = toRefs(props) // 獲取 repository 相關公共方法,在其餘模塊中定義 const { repositories, getUserRepositories } = useUserRepositories(user) // 搜索 repository 相關公共方法,在其餘模塊中定義 const { searchQuery, repositoriesMatchingSearchQuery } = useRepositoryNameSearch(repositories) // 過濾 repository 相關公共方法,在其餘模塊中定義 const { filters, updateFilters, filteredRepositories } = useRepositoryFilters(repositoriesMatchingSearchQuery) return { // 由於咱們並不關心未通過濾的倉庫 // 咱們能夠在 `repositories` 名稱下暴露過濾後的結果 repositories: filteredRepositories, getUserRepositories, searchQuery, filters, updateFilters } } }
在這個例子中,該組件須要的變量或方法所有在其餘模塊定義了,並經過 useXXX 的函數暴露給外部組件,並且還能夠被其餘組件重複使用。這樣看上去是否是更清爽了呢?
你可能會思考怎麼寫 useXXX 這種函數。其實很是簡單,下面就是一個例子。
// src/composables/useUserRepositories.js import { fetchUserRepositories } from '@/api/repositories' import { ref, onMounted, watch } from 'vue' export default function useUserRepositories(user) { // 內部列表變量 const repositories = ref([]) // 獲取列表方法 const getUserRepositories = async () => { repositories.value = await fetchUserRepositories(user.value) } // 初次獲取列表,掛載後執行,至關於傳統組件中的 mounted onMounted(getUserRepositories) // 監聽 user 並根據變化來獲取最新列表,至關於傳統組件中的 watch watch(user, getUserRepositories) // 返回公共變量和方法 return { repositories, getUserRepositories } }
傳統組件中的一些 API,例如 mounted 和 watch,已經成爲了按需引用的函數,功能跟以前如出一轍。而以前的 data、computed、methods 變成 setup 函數中的內部變量,並根據是否返回來決定是否暴露給外部。
須要注意的是,Vue 3 中引入了響應式 API 的概念,以前的變量都須要根據須要用不一樣的響應式 API 來定義。其具體原理不深刻介紹了,感興趣的讀者能夠到官方文檔繼續深刻學習。
其餘新特性
Vue 3 還有其餘一些新特性,限於篇幅緣由就不詳細介紹了。這裏只列出一些比較實用的新特性及其簡單介紹。
- Teleport - 適用於 Modal、Popover 等須要掛載在全局 DOM 元素中的組件
- 片斷 - 組件支持多個根節點
- 觸發組件選項 - 關於事件的相關 API 變動
所有變動列表,請參考官方文檔(英文)。
大型項目實戰
前面介紹了這麼多理論知識,對於前端工程師來講可能還不夠,要在工做中讓所學知識發揮做用,還必需要用到項目實踐中,特別是大型項目。所以,這個小節將着重介紹如何用 Vue 3 來構建企業級項目。 本小節將用筆者的一個 Github 倉庫 做爲演示, 講解如何用 Vue 3 構建大型前端項目。
這個倉庫是筆者的一個開源項目 Crawlab 的下一個版本 v0.6 的前端部分。 它目前還處於開發中的狀態,並非成品;不過代碼組織結構已經成型,做爲演示來講已經足夠。以前的版本是用 Vue 2 寫的,用的是傳統 Vue API。這個 Vue 3 版本將使用 TS 和組合式 API 來完成重構和遷移,而後在此基礎上加入更多實用的功能。對該前端項目感興趣的讀者能夠訪問該 Github 倉庫瞭解代碼細節,同時也很是歡迎你們跟我討論任何相關問題,包括不合理或須要優化的地方。
倉庫地址: https://github.com/crawlab-team/crawlab-frontend
項目結構
該項目的代碼組織結構以下。其中忽略了一些不重要的文件或目錄。
. ├── public // 公共資源 ├── src // 源代碼目錄 │ ├── assets // 靜態資源 │ ├── components // 組件 │ ├── constants // 常量 │ ├── i18n // 國際化 │ ├── interfaces // TS 類型聲明 │ ├── layouts // 佈局 │ ├── router // 路由 │ ├── services // 服務 │ ├── store // 狀態管理 │ ├── styles // CSS/SCSS 樣式 │ ├── test // 測試 │ ├── utils // 輔助方法 │ ├── views // 頁面 │ ├── App.vue // 主應用 │ ├── main.ts // 主入口 │ └── shims-vue.d.ts // 兼容 Vue 聲明文件 ├── .eslintrc.js // ESLint 配置文件 ├── .eslintignore // ESLint Ignore 文件 ├── babel.config.js // Babel 編譯配置文件 ├── jest.config.ts // 單元測試配置文件 ├── package.json // 項目配置文件 └── tsconfig.json // TS 配置文件
能夠看到,這個前端項目有很是多的子模塊,包括組件、佈局、狀態管理等等。在 src 目錄中有十多個子目錄,也就是十多個模塊,這還不包括各個模塊下的子目錄,所以模塊很是多,結構也很是複雜。這是一個典型的大型前端項目的項目結構。企業級項目,例如 ERP、CRM、ITSM 或其餘後臺管理系統,大部分都有不少功能模塊以及清晰的項目結構。這些模塊各司其職,相互協做,共同構成了整個前端應用。
其實這種項目結構並不僅適用於 Vue,其餘框架的項目例如 React、Angular 均可以是相似的。
TS 類型聲明
TS 幾乎是現代大型前端項目的標配,其強大的類型系統能夠規避大型項目中不少常見的錯誤和風險。所以,咱們在這個前端項目中也採用了 TS 來作類型系統。
在前面的項目結構中,咱們在 src/interfaces 目錄中聲明 TS 類型。類型聲明文件用 <name>.d.ts 來表示,name 表示是跟這個模塊相關的類型聲明。例如,在 src/interfaces/layout/TabsView.d.ts 這個文件中,咱們定義了跟 TabsView 這個佈局組件相關的類型,內容以下。
interface Tab { id?: number; path: string; dragging?: boolean; }
更復雜的例子是狀態管理的類型聲明文件,例如 src/interfaces/store/spider.d.ts,這是 Vue 中狀態管理庫 Vuex 的其中一個模塊聲明文件,內容以下。
// 引入第三方類型 import {GetterTree, Module, MutationTree} from 'vuex'; // 若是引入了第三方類型,須要顯式作全局聲明 declare global { // 繼承 Vuex 的基礎類型 Module interface SpiderStoreModule extends Module<SpiderStoreState, RootStoreState> { getters: SpiderStoreGetters; mutations: SpiderStoreMutations; } // 狀態類型 // NavItem 爲自定義類型 interface SpiderStoreState { sidebarCollapsed: boolean; actionsCollapsed: boolean; tabs: NavItem[]; } // Getters // StoreGetter 爲自定義基礎類型 interface SpiderStoreGetters extends GetterTree<SpiderStoreState, RootStoreState> { tabName: StoreGetter<SpiderStoreState, RootStoreState, SpiderTabName>; } // Mutations // StoreMutation 爲自定義基礎類型 interface SpiderStoreMutations extends MutationTree<SpiderStoreState> { setSidebarCollapsed: StoreMutation<SpiderStoreState, boolean>; setActionsCollapsed: StoreMutation<SpiderStoreState, boolean>; } }
其中,尖括號 <...> 裏的內容是 TS 中的泛型,這能大幅度提升類型的通用性,一般用做基礎類型。
下面是引用 TS 類型的例子 src/store/modules/spider.ts。
import router from '@/router'; export default { namespaced: true, state: { sidebarCollapsed: false, actionsCollapsed: false, tabs: [ {id: 'overview', title: 'Overview'}, {id: 'files', title: 'Files'}, {id: 'tasks', title: 'Tasks'}, {id: 'settings', title: 'Settings'}, ], }, getters: { tabName: () => { const arr = router.currentRoute.value.path.split('/'); if (arr.length < 3) return null; return arr[3]; } }, mutations: { setSidebarCollapsed: (state: SpiderStoreState, value: boolean) => { state.sidebarCollapsed = value; }, setActionsCollapsed: (state: SpiderStoreState, value: boolean) => { state.actionsCollapsed = value; }, }, actions: {} } as SpiderStoreModule;
這裏用了 as SpiderStoreModule 的斷言,TS 靜態檢測器會自動將 SpiderStoreModule 中的元素推斷出來,並與實際的變量作比對。若是出現了不一致,就會拋錯。
組件化
組件化是現代前端項目的主流,在 Vue 3 中也不例外。Vue 3 的組件化跟 Vue 2 比較相似,都是用 Vue 實例來定義各種組件。在這個前端項目中,組件被分類成了不一樣種類,同一種類的放在一個文件夾中,以下。
. └── src └── components ├── button // 按鈕 ├── context-menu // 右鍵菜單 ├── drag // 拖拽 ├── file // 文件 ├── icon // Icon ├── nav // 導航 ├── table // 表格 └── ...
組件文件爲 <ComponentName>.vue 定義,以下是其中一個關於右鍵菜單的例子 src/components/context-menu/ContextMenu.vue。
<template> <el-popover :placement="placement" :show-arrow="false" :visible="visible" popper-class="context-menu" trigger="manual" > <template #default> <slot name="default"></slot> </template> <template #reference> <div v-click-outside="onClickOutside"> <slot name="reference"></slot> </div> </template> </el-popover> </template> <script lang="ts"> import {defineComponent} from 'vue'; import {ClickOutside} from 'element-plus/lib/directives'; // 定義屬性 export const contextMenuDefaultProps = { visible: { type: Boolean, default: false, }, placement: { type: String, default: 'right-start', }, }; // 定義觸發事件 export const contextMenuDefaultEmits = [ 'hide', ]; // 定義組件 export default defineComponent({ // 組件名稱 name: 'ContextMenu', // 引用外部指令 directives: { ClickOutside, }, // 觸發事件 emits: contextMenuDefaultEmits, // 屬性 props: contextMenuDefaultProps, // 組合式 API setup(props, {emit}) { // 點擊事件函數 const onClickOutside = () => { emit('hide'); }; // 返回公共對象 return { onClickOutside, }; }, }); </script>
你可能會有疑慮:這裏彷佛沒用到 TS 中的類型系統啊。其實這只是一個很是簡單的組件,包含完整 TS 特性的組件例子能夠參考下面這個組件。
src/file/FileEditor.vue
: https://github.com/crawlab-team/crawlab-frontend/blob/main/src/components/file/FileEditor.vue
其餘
限於篇幅緣由,本文不會詳細介紹其餘全部模塊。這裏只簡單列舉一下。
- UI 框架(UI Framework)- 用了 Element+ 做爲 UI 框架
- 佈局(Layouts)- 基礎佈局 BasicLayout 定義了頂部、側邊欄、底部等元素
- 狀態管理(State Management)- 至關於全局數據管理系統
- 路由(Routing)- 頁面路由配置
- 國際化(Internationalization)- 多語言配置
- 樣式(Styles)- 利用 SCSS 定義了全局樣式以及樣式變量等
- 服務(Services)- 包括與後端 API 的交互函數
- 常量(Constants)
- 輔助方法(Utilities)
如何學習 Vue 3
關於 Vue 3 的學習途徑,其實首先應該是閱讀官方文檔,瞭解 Vue 3 的基礎概念、高階原理以及如何工程化等等。做者尤雨溪已經在文檔中很是詳細的介紹了關於 Vue 的各個方面,圖文並茂、深刻淺出的講解了關於 Vue 3 的概念和知識。總之 Vue 3 的文檔對於初學者來講很是友好。若是你對英文比較熟悉,推薦直接閱讀英文官方文檔,其中內容通常是最新的。
除開閱讀官方文檔之外,筆者還推薦閱讀優秀的 Vue 3 開源項目, 例如 Element+、Ant Design Vue、Vue-Admin-Beautiful, Github 上有不少優秀的 Vue 3 項目,閱讀它們的源碼能夠幫助你熟悉如何使用 Vue 3,以及構建大型項目的代碼組織方式。
固然,本身動手用 Vue 3 實踐一個前端項目可以幫助你深刻理解 Vue 3 的原理和開發方式,特別是將 Vue 3 的新特性用在工做項目中。筆者在瞭解了 Vue 3 的基礎語法和新特性以後,將所學知識運用在了本身的開源項目中,邊學邊作,就很是快速的掌握了 Vue 3 的核心知識。
總結
這篇文章主要介紹了 Vue 3 在大型前端項目中的優點,尤爲是新特性 TS 支持和組合式 API,可以大幅加強代碼的可讀性和可維護性。這讓自己就上手容易的 Vue 框架變得如虎添翼,使其可以勝任大型前端項目的設計和開發。對 TS 的原生支持,可以讓 Vue 3 的項目代碼可以具備良好的可預測性。而組合式 API,可以將散亂的代碼邏輯變得更有秩序。這些都有助於加強 Vue 3 前端項目的健壯性,從而讓前端人員更容易編寫出穩定而可維護的代碼。另外,本文還經過筆者的一個開發中的前端項目(Crawlab Frontend),來演示如何利用 Vue 3 開發企業級前端項目,並展現了相關的項目結構、TS 類型聲明以及組件化,等等。
比較資深的前端工程師可能會對 Vue 3 的新特性不屑一顧,由於所謂的 TS 支持和組合式 API 都在其餘知名框架以其餘名字被率先引入,例如 React 的 React Hooks,Vue 3 彷佛只是借鑑了過去。可是,這種觀點很是不可取。在技術面前,任何方案都沒有高低貴賤,只有合不合適。就像相親同樣,只有合適的,纔是最好的。尤雨溪也認可,AngularJS 和 React 都有不少優秀的技術,Vue 也借鑑了一部分。但你毫不能所以而宣判它是抄襲。就像 C# 跟 Java 語法和特性相似,但你確定沒法證實 C# 是抄襲的 Java(其實 C# 相較於 Java 有不少優秀特性,例如隱式類型推斷,這也是筆者比較喜歡 C# 的緣由之一)。Vue 的成功,絕對不是偶然性的,它的易用性和相對豐富的文檔資源,讓初學者可以快速上手,這對於前端開發者來講是福音。咱們作技術的應該對新技術抱有包容心,可以辯證而理性的看待問題,這樣纔不致於變得偏激從而走火入魔。
參考
-
Vue 3 官方文檔: https://www.vue3js.cn/docs/zh/
-
TypeScript 官方文檔: https://www.typescriptlang.org/docs
-
Crawlab Frontend: https://github.com/crawlab-team/crawlab-frontend
-
《爲何說 TypeScript 是開發大型前端項目的必備語言》
本文分享自華爲雲社區《TS 加持的 Vue 3,如何幫你輕鬆構建企業級前端應用》,原文做者:Marvin Zhang 。