概述
在9 月 30 日的Vue.js 倫敦大會上, 作者尤雨溪介紹了 Vue 下一個版本將要釋出的內容,以及 Vue 3.0 的開發路線,和後面版本的發展情況。雖然,Vue 3.0版本的正式版還沒有釋出,不過作為vue 專案快速構建工具的vue-cli 早已釋出,我們可以通過vue-cli來了解vue 3.0的一些情況。
作為Vue的主要版本,Vue 3.0帶來了諸多的重大變更,不過,開發組也非常重視相容性問題:除了渲染函式 API 和作用域插槽語法之外的所有內容都將保持不變,或者通過相容性構建讓其與 2.x 保持相容。總的來說,Vue 3.0 雖然會對頂級 API 進行重大的修整,但依然會保持與 2.x 的相容。此外,2.x 的最後一個次要版本將成為 LTS,並在 3.0 釋出後繼續享受 18 個月的 bug 和安全修復更新。
欲瞭解更多的詳情,可以參考下面的連結:Vue 3.0版本釋出計劃
重構
程式碼結構
為了實現更清晰、更易維護的原始碼架構,尤雨溪表示將從頭開始重寫 3.0,並將一些內部功能分解為單獨的包,以便隔離複雜性。如下圖是vue 3.0的原始碼目錄結構圖。
前文說過,Vue團隊打算在從零開始編寫 3.0 版本,為的是“達到更加清晰和更易維護的架構,特別是為了讓程式碼的貢獻變得容易”。為了降低複雜性,對複雜性進行隔離,開發團隊將一些內部功能拆分為了多個單獨的包。例如,observer 模組將成為一個單獨的包,擁有自己對外的 API 和自己的測試用例。
另外,程式碼庫現在改為用 TypeScript 編寫,雖然這會使得“熟練TypeScript”成為對新程式碼庫進行貢獻的一個前置要求,不過我們相信有型別資訊配合 IDE 的支援,對於一個新的貢獻者來說,要做出有意義的貢獻,實際上反而會更加容易。
除此之外,Vue還對改進編譯器、支援 IE 11、其他執行時改進和改進觀察機制等方面內容。
監測機制
3.0 將帶來一個基於 Proxy 的 observer 實現,它可以提供覆蓋語言 (JavaScript——譯註) 全範圍的響應式能力,消除了當前 Vue 2 系列中基於 Object.defineProperty 所存在的一些侷限,這些侷限包括:
- 對屬性的新增、刪除動作的監測;
- 對陣列基於下標的修改、對於 .length 修改的監測;
- 對 Map、Set、WeakMap 和 WeakSet 的支援;
另外,新的 observer還提供瞭如下的一些特性:
- 公開的用於建立 observable 的 API:這為小型到中型的應用提供了一種輕量級的、極其簡單的跨元件狀態管理解決方案。
- 預設為惰性監測(Lazy Observation)。在 2.x版本中,任何響應式資料,不管它的大小如何都會在啟動的時候監測功能。如果資料量很大的話,在應用啟動的時候就可能造成嚴重的效能消耗。而在3.x 版本中,只有應用的初始可見部分所用到的資料會被監測,更不用說這種監測方案本身其實也是更加快的。
更精準的變動通知:舉個例子:在 2.x 系列中,通過 Vue.set 強制新增一個新的屬性,將導致所有依賴於這個物件的 watch 函式都會被執行一次;而在 3.x 中,只有依賴於這個具體屬性的 watch 函式會被通知到。
不可變監測對象:我們可以建立一個物件的“不可變”版本,以此來阻止對他的修改——包括他的巢狀屬性,除非系統內部臨時解除了這個限制。這種機制可以用來凍結傳遞到元件屬性上的物件和處在 mutation 範圍外的 Vuex 狀態樹。
- 更好的除錯能力:通過使用新增的 renderTracked 和 renderTriggered鉤子,我們可以精確地追蹤到一個元件發生重渲染的觸發時機和完成時機及其原因。
編譯器
Vue 3.0與編譯器相關的程式碼編譯將會有一個大的提升,用一句話概括為:“搖樹友好”的輸出;更多的 AOT 優化;更良好的解析錯誤;支援 source map。
- 如果採用的是支援“搖樹優化”的打包器,模板中使用到的那些可選特性,在生成的程式碼中將通過 ES的模組語法匯入;而在打包後的檔案中,那些沒用到的可選特性就會被“搖掉”。
- 由於新的虛擬 DOM 實現所帶來的提升,我們可以執行一些更加高效的編譯耗時優化,如靜態樹提升(static tree hoisting)、靜態屬性提升(static props hoisting);以及為執行時提供一些來自編譯器的提示,以此避開子元件的規範過程 (children normalization);提供VNode 快速建立路徑等等。
- 解析器重寫,以便在對模板進行編譯發生錯誤時,可以提供錯誤發生的位置資訊;除此之外還可以帶來對模板的 source map支援;還可以支援第三方工具如 eslint-plugin-vue 和 IDE 的語言服務 (language services) 特性。
IE 11相容
新的程式碼庫目前只針對主流瀏覽器,而且我們假定他們都支援 ES2015。但是,哎,我們也知道在可預見的未來還有很多使用者仍然需要支援 IE11。除了 Proxy 外,大多數 ES2015 的特性都可以用轉譯或者墊片的方式在 IE11 中使用。我們的計劃是另外單獨實現一個具有同樣 API 的替代性 observer,不過是基於老式的 Object.defineProperty API;然後再通過單獨構建一個使用這個實現的 Vue 3.x 版本 (build) 進行釋出,不過這個單獨的版本還是會有 Vue 2.x 在變動探測方面所存在的問題,所以它其實並不是一個完全相容 3.x 的一個版本。我們也意識到這會給第三方庫的作者們帶來某些不便,因為他們需要考慮兩個不同版本之間的相容性問題,不過當我們真的推進到那個階段時,那時我們肯定會確保提供一份清晰的指導。
當然,Vue 3.0還處於開發階段,最早釋出也會等到2019年了,讓我們拭目以待吧。
vue-cli 3.0
vue-cli 是 vue 官方團隊推出的一款快速開發 vue 專案的構建工具,具有開箱即用並且提供簡潔的自定義配置等功能。 vue-cli 從 2.0 到 3.0 修改了眾多的東西,下面就讓我們來了解下。
建立專案
從vue-cli 3.0開始,vue的安裝命令從vue-cli 改成了 @vue/cli。例如:
npm install -g @vue/cli複製程式碼
使用vue-cli 3.0建立專案的命令如下:
vue create my-project複製程式碼
除了命令建立外,3.0還增加了圖形化介面建立以及管理vue專案的功能,在建立新專案時還可以混合選用多種整合。當我們使用vue ui命令後即可使用圖形化的方式來操作vue專案的原始碼。
需要說明的是,在初始化專案時系統會預設生成package.json和package-lock.json兩個配置檔案,它們的區別在於package.json只能鎖定大版本號,而package-lock.json則能鎖定安裝時包的版本號,以保證多人開發時專案版本號的一致。同時,Vue在3.0版本刪除了static目錄,並新增了public目錄,該目錄主要用於存放不被webpack處理的檔案和資源。
當我們使用create命令建立專案時,系統會要求我們選擇一些東西。例如:
Vue CLI v3.0.3? Please pick a preset: default (babel, eslint)>
Manually select features複製程式碼
Vue 3.0 版本支援預設配置 和 使用者自定義配置,其中自定義功能配置包括以下功能:
- TypeScript
- Progressive Web App (PWA) Support
- Router
- Vuex
- CSS Pre-processors
- Linter / Formatter
- Unit Testing
- E2E Testing
可以發現,3.0 版本新加入了 TypeScript 以及 PWA 的支援。
1,在選擇 CSS 前處理器後會提示選擇哪一種前處理器?
- Scss/Sass
- Less
- Stylus
2,eslint 規範的選擇
- ESLint with error prevention only
- ESLint + Airbnb config
- ESLint + Standard config
- ESLint + Prettier
3,選擇 Babel,PostCSS,ESLint 等自定義配置的存放位置
- In dedicated config files
- In package.json
目錄結構
相比於Vue 2.0版本來說,Vue 3.0的目錄結構則簡潔很多,下面是Vue專案檔案的具體含義及其作用說明。
- node_modules:專案依賴的第三方模組;
- public:移除static目錄,新增public目錄,並且 index.html 移動到 public 中,該目錄主要用於存放如圖片、字型等靜態資源和打包後的檔案;
- src:原始碼存放目錄,主要可以存放的有assets資原始檔和原始碼;
- babelrc:將es6程式碼轉換成瀏覽器能夠識別的程式碼;
- editorconfig:定義專案編碼規範,優先順序高於編譯器設定的優先順序;
- index.html:專案入口檔案,可以配置meta 資訊或統計程式碼等;
- package.json:專案配置檔案,該檔案主要定義了專案所需要的各種依賴模組和專案的一些配置資訊;
- package-lock.json:鎖定安裝時包的版本號,多人協作開發會用到;
- webpack.config.js:webpack模組化打包的一些配置;
自定義配置
從 3.0 版本開始,系統會在專案的根目錄生成一個 vue.config.js 檔案,可以在此檔案中新增自定義的一些配置。下面是一些常用的自定義配置:
module.exports = {
baseUrl: '/', outputDir: 'dist', lintOnSave: true, compiler: false, // 調整內部的 webpack 配置。 // 查閱 https://github.com/vuejs/vue-doc-zh-cn/vue-cli/webpack.md chainWebpack: () =>
{
}, configureWebpack: () =>
{
}, // 配置 webpack-dev-server 行為。 devServer: {
open: process.platform === 'darwin', host: '0.0.0.0', port: 8080, https: false, hotOnly: false, // 查閱 https://github.com/vuejs/vue-doc-zh-cn/vue-cli/cli-service.md#配置代理 proxy: null, // string | Object before: app =>
{
}
} ....
}複製程式碼
調整 webpack 配置最簡單的方式就是在vue.config.js中的configureWebpack選項提供一個物件,該物件將會被webpack-merge合併入最終的 webpack 配置。例如:
module.exports = {
configureWebpack: {
plugins: [ new MyAwesomeWebpackPlugin() ]
}
}複製程式碼
如果想要修改外掛選項的引數,讀者可以閱讀webpack-chain 的 API 獲取更多相關的一些原始碼。例如:
// vue.config.jsmodule.exports = {
chainWebpack: config =>
{
config .plugin('html') .tap(args =>
{
return [/* new args to pass to html-webpack-plugin's constructor */]
})
}
}複製程式碼
需要說明的是,當我們更改一個 webpack 配置的時候,可以通過vue inspect >
輸出完整的配置清單,注意它輸出的並不是一個有效的 webpack 配置檔案,而是一個用於審查的被序列化的格式。
output.js
ESLint、Babel、browserslist
- Babel 可以通過.babelrc 或 package.json 中的 babel 欄位進行配置。
- ESLint 可以通過.eslintrc 或 package.json 中的 eslintConfig 欄位進行配置。
- package.json 中的 browserslist 欄位指定了該專案的目標瀏覽器支援範圍。
browserslist
我們可以在package.json配置檔案中看到browserslist欄位。例如:
>
1%last 2 versionsnot ie <
= 8複製程式碼
使用 npx browserslist 可以檢視專案的瀏覽器相容情況,vue的支援情況如下表:
public目錄
vue 約定public/index.html作為入口模板會通過html-webpack-plugin外掛處理。在構建過程中,資源連結將會自動注入其中。除此之外,vue-cli 也自動注入資源提示(preload/prefetch),在啟用 PWA 外掛時注入manifest/icon/連結,並引入(inlines) webpack runtime / chunk manifest清單已獲得最佳效能。
在 JavaScript 或者 SCSS 中通過 相對路徑 引用的資源會經過 webpack 處理,放置在 public 資料夾的資源可以通過絕對路徑引用,這些資源將會被複制,而不經過 webpack 處理。
並且,圖片最好使用相對路徑經過 webpack 處理,這樣可以避免很多因為修改網站根目錄導致的圖片404問題。
新增功能
除此之外,Vue-cli還帶來了兩個比較有誘惑力的功能:對TypeScript和PWA的支援;
TypeScript 支援
從 3.0 版本開始中,系統選擇啟用 TypeScript 語法,從而大大的簡化了程式碼,不過也帶來了一些書寫上的約束。例如:
import {
Component, Emit, Inject, Model, Prop, Provide, Vue, Watch
} from 'vue-property-decorator'const s = Symbol('baz')@Componentexport class MyComponent extends Vue {
@Emit() addToCount(n: number){
this.count += n
} @Emit('reset') resetCount(){
this.count = 0
} @Inject() foo: string @Inject('bar') bar: string @Inject(s) baz: string @Model('change') checked: boolean @Prop() propA: number @Prop({
default: 'default value'
}) propB: string @Prop([String, Boolean]) propC: string | boolean @Provide() foo = 'foo' @Provide('bar') baz = 'bar' @Watch('child') onChildChanged(val: string, oldVal: string) {
} @Watch('person', {
immediate: true, deep: true
}) onPersonChanged(val: Person, oldVal: Person) {
}
}複製程式碼
上面的程式碼等價於下面的程式碼:
const s = Symbol('baz')export const MyComponent = Vue.extend({
name: 'MyComponent', inject: {
foo: 'foo', bar: 'bar', [s]: s
}, model: {
prop: 'checked', event: 'change'
}, props: {
checked: Boolean, propA: Number, propB: {
type: String, default: 'default value'
}, propC: [String, Boolean],
}, data () {
return {
foo: 'foo', baz: 'bar'
}
}, provide () {
return {
foo: this.foo, bar: this.baz
}
}, methods: {
addToCount(n){
this.count += n this.$emit("add-to-count", n)
}, resetCount(){
this.count = 0 this.$emit("reset")
}, onChildChanged(val, oldVal) {
}, onPersonChanged(val, oldVal) {
}
}, watch: {
'child': {
handler: 'onChildChanged', immediate: false, deep: false
}, 'person': {
handler: 'onPersonChanged', immediate: true, deep: true
}
}
})複製程式碼
可以發現,使用TypeScript語法後,程式碼大為精簡。
PWA 支援
當我們選擇啟用 PWA 功能時,在打包生成的程式碼時會預設生成 service-worker.js 和 manifest.json 相關檔案。熟悉PWA的同學都知道service-worker.js 和 manifest.json 是PWA的重要配置檔案。如果讀者還不瞭解 PWA,點選 PWA官方文件 檢視。
預設情況 service-worker 採用的是 precache,可以通過配置 pwa.workboxPluginMode 自定義快取策略。例如:
module.exports = {
// ...其它 vue-cli 外掛選項... pwa: {
workboxPluginMode: 'InjectManifest', workboxOptions: {
// swSrc 中 InjectManifest 模式下是必填的。 swSrc: 'dev/sw.js', // ...其它 Workbox 選項...
},
},
};
複製程式碼
vue-cli 致力於將 Vue 生態中的工具基礎標準化,並確保各種構建工具能夠基於智慧的預設配置即可平衡銜接,提高開發效率。雖然,vue 3.0還處於開發階段,不過相信在不久的將來一定會給開發者帶來驚喜,讓我們拭目以待吧。
參考:www.php.cn/js-tutorial…github.com/vuejs/vue-c…github.com/vuejs/vue-c…