Vue 1.x 升級至 2.0 的辛酸歷程
Migration Vue 1.x to 2.0
前言
雖然知道 Vue 2.0 推出也好一陣子了,但是原本的專案一直在猶豫該不該升級到 2.0 版本,之前嘗試了一兩次要升級,最後都因為無法順利編譯過而放棄。但由於考量到之後還要再開發的功能也需要使用前端框架,所以這幾天還是痛下決心再試一次。
目前專案用到的東西真的好複雜,gulp 流程要跑完都要好長一段時間,光 CSS 處理就從,純 CSS 到 CSS 前處理器(包含 Less, Sass)甚至還有後處理器 PostCSS,而 JS Framework 也使用了兩個 React.js 與 Vue.js,而原本 gulpfile 也從單純自己安裝套件到後來改為 Laravel Elixir 的方式來處理,這些全都算是一種技術債吧!
而這次 Vue 的版本升級,也順便更新了 Laravel Elixir 的版本從 5 到 6,但似乎遇到了一個滿多人遇到的情況,在執行 gulp watch 時,會因為產生亂數版本號(version) 的動作出問題而程序終止,也因為這個問題讓我一度猶豫是否該把 elixir 版本降回去 5.0.x 版,但是昨晚也為了這付出了許多代價,結果還是失敗,只能放棄 gulp watch 這個美好的指令….XD
升級前後版本比較
這裡先將有相關工具升級前後,版本的資料紀錄一下,
Tools | Before | After | 備註 |
---|---|---|---|
laravel-elixir | 5.0.0 | 6.0.0-14 | |
laravel-elixir-webpack-official | —- | 1.0.2 | elixir 6 使用 webpack |
laravel-elixir-rollup-official | —- | 1.1.0 | elixir 6 採用 Rollup 來轉譯 JS 到 ES 5 |
laravel-elixir-browserify-official | —- | 0.1.3 | elixir 6 在執行 browserSync 用到,不過本身沒用到,似乎白裝了 |
laravel-elixir-postcss | 0.3.6 | 0.5.0 | 順便更新 |
laravel-elixir-vueify | 1.0.3 | —- | elixir 5 編譯 Vue 1.0 時會用,要編譯 vue 2.0 改用 laravel-elixir-vueify-2.0 |
laravel-elixir-vueify-2.0 | —- | 1.0.3 | elixir 5 編譯 Vue 2.0 時用到,只是我實驗結果失敗了,所以 elixir 才升級到 6 |
vue | 1.0.26 | 2.0.1 | 這次的主角 Vue 2.0 |
vuex | 0.6.3 | 1.0.1 | Vuex 搭背 Vue 來處理狀態機制,類似 React.js 搭配 Redux |
laravel-elixir-vue-2 | —- | 0.2.0 | elixir 6 搭配這個總算順利編譯 Vue 2.0 了 |
vueify | 8.7.0 | 9.4.0 | 用來處理單一 Vue Compoment 檔案,不曉得需不需要也是升級了 |
很希望有人來指導這次的升級該怎麼做才是最佳做法,我不是很聰明,只能一直 try & error,經過了好幾個小時的時間消耗,才順利把 Vue 2.0 給編譯出來,而且可以正常執行,覺得這真的是個打擊信心的做法
升級 Step 1
當然先去找升級提示工具來提示,然後在 Vue 1.0 還能編譯的範圍,先將一些細節修改,使用的是官方推薦的工具 - Vue migration helper,第一次檢查專案時,跑出了37個建議,因為之前有過一些經驗,知道有些問題可以先處理,這裡列出來給後人參考
Vue 1.0 內可無痛修改
在真的 npm install vue@2.0 之前,還是有些建議寫法可以先改起來放,可能會有人問說,就乾脆安裝 Vue 2.0 然後再一口氣改不就好了,我也很想這麼做,但是 gulp 一開始就跑不過,不可控制的變數太多,我失敗了幾次後學到的教訓,還是慢慢來就好,如果本身已經是大神的,可能就沒差,直接上吧!
所以試誤了幾次後,大概歸納出下面幾個可以先在 Vue 1.x 改了也還能編譯過的方法:
原本屬性內的計算插值要改寫法
Interpolation within attributes has been removed
Vue 1.x 寫法 |
HTML 計算插值改用 v-html 替換
HTML interpolation with {{{}}} has been removed
Vue 1.x 寫法 |
這裡有踩到雷的經驗,因為在 1.x 時,輸出的 html 內容還可以再搭配其他 DOM 元素,但是改用 v-html 後,裡面再放其他 DOM 元素都會消失,只剩下原本要輸出的 html 內容
__踩到的地雷__,原本寫法如下
<div> {{{ foo }}} <button>OK</button> </div> |
在 1.x 版本還能顯示 button,若改成 2.0 寫法
<div v-html="foo"> <button>OK</button> </div> |
這時候裡面的 button 就無法顯示了,需拆成兩個元件來寫
<div v-html="foo"></div> <button>OK</button> |
雖然可能覺得沒什麼,但是原本寫好的一些邏輯判斷就要小心,是否因為 DOM 排列變化而出問題
移除 v-for 中隱含變數 $index, $key
$index has been removed to avoid implicitly defined (i.e. “magic”) variables
Vue 1.x 寫法 |
__注意事項__,在還沒真的升級到 Vue 2.0 前,v-for 裡增加 index 的寫法,index 擺在前面,如下面的過渡寫法
<div v-for="(index, item) in items"> |
升級 Step 2
當然就是安裝 Vue 2.0,然後再根據 vue-migration-helper 剩下的建議,把語法改一改,再來找合適的編譯工具
因為還有使用 vuex 來做狀態的管理,為了配合 Vue 2.0,vuex 也需要從原本的 0.6 升級啦 (Migration form Vuex 0.6.x to 1.0),雖然 vuex 也有 2.0版本,但是寫法也改了,我暫時不想再搞自己了,先把 vue 升到 2.0 就快搞死我了,不想多折磨自己
安裝主要工具
當然是 vue 2.0 與 vuex
npm install --save vue@2.0.1 vuex@1.0.1 |
安裝編譯工具
經過了很長時間的 try & error,總結出應該就是下面這幾個工具,不然就在參考上面的表格吧
- laravel-elixir@6.0.0-14
- laravel-elixir-vue-2
- laravel-elixir-rollup-official
- laravel-elixir-webpack-official
npm install --save-dev laravel-elixir-rollup-official laravel-elixir-webpack-official |
gulpfile 調整
為了編譯 Vue 2.0,使用了 laravel-elixir-vue-2,所以基本用法如下:
var elixir = require('laravel-elixir') |
另外 laravel-elixir 版本也從 5 升級到 6,所以原本的 Bebel 寫法也要改成 Rollup
Bebel 寫法 |
語法調整
一樣繼續使用 vue-migration-helper 檢查語法,加以調整
v-for 中 index, key 變數位置
由於先前過度寫法已經加入 index or key 在 v-for 內,所以這邊只是將位置調換,為了符合 Vue 2.0 的用法
過渡時寫法 (index, value) |
Lifecycle 中的 ready 已移除
ready lifecycle hook has been removed
Vue 1.x 與 Vue 2.0 的 lifecycle 經過調整,原本的 ready 狀態更換為 mounted,所以就跟著調整
Vue 1.x |
Transition 參數替換
原本的專案內用到 modal 效果,就會需要個簡單的過場,這裡 Vue 有提供好的範例可以參考使用,還不賴 ( Vue 2.0 的 Modal Compontent 範例 )
<div class="modal-mask" v-show="show" transition="modal"> |
<transition name="modal"> |
Component 必須有個 root dom
Vue 2.0 後,每個元件都必須被包在一個 DOM 元素下,這點跟 React.js 有點像,之前沒這麼做,現在就不得不改寫了
Vue 1.x 版本 |
vm.$set (this.$set) 用法替換
原本專案內很多元件裡的 data 都透過 this.$set 的方式來更新內容,現在 vm.$set 變成 Vue.set 的別名,所以原本的用法就變啦!
vm.$set( keypath, value )
–> Vue.set( object, key, value )
底下是自己的紀錄
基本調整 |
其他自己遇到的問題
checkbox 元件的預設狀態
原本 Vue 1.x 寫成 <input type="checkbox" :checked="checked">
裡面的 checked 是從父原件傳入的 Boolean 值,但是改成 Vue 2.0 後,似乎就失效了,花了很久的時間才改正確
Vue 1.x 時 |
中間一度誤入歧途,找到了一些在討論 prop 取消雙向綁定 的問題,但等到後來解決後才想到,我根本就是用 vuex 在做狀態管理,一開始就不是 twoWay bind 的做法,還搞了半天,簡直就是白痴
大功告成?
其實還沒有經過很嚴謹的測試,但是基本的功能與操作上,似乎沒有太多問題,我該高興我好不容易花了兩三天總算順利升級了嗎?但是想到 elixir 6 在 gulp watch 會出錯 (Cannot gulp watch, but can gulp),實在一點也高興不起來,上網找了一下相關問題,似乎滿多人也都遇到了,但真正的解法我倒是還沒找到,希望有人可以來替我指點迷津。