Svelte v2 已通過時了!

帶你蜻蜓點水,細看新版變化。

注意:原文發表於2018-04-18,隨着框架不斷演進,部份內容可能已不適用。javascript

大約是一年以前,咱們首次在 Svelte 的 issue 跟蹤器上討論過 v2 版本,如今是時候進行一些重大變動了。css

咱們的座右銘是「按部就班,破舊立新」。html

……好吧,我錯了,看來我要改過自新了。java

這篇博文闡述了新版本的變化,都變了哪些地方、爲何要變以及應對的策略。git

長話短說,先看梗概

咱們會不厭其詳地描述每個變動細項,若是你仍是遇到了困難,請在咱們氣氛友好的 Discord 聊天室 中尋求幫助。github

  • 從 npm 安裝 Svelte v2
  • svelte-upgrade 升級你的模板
  • 刪除對 component.observe 方法的調用,或者從 svelte-extras 中添加 observe 方法
  • 將對 component.get('foo') 的調用重寫爲 component.get().foo
  • 從你的自定義事件處理程序中返回 destroy,而不是 teardown
  • 確保沒有將值是數字類型的字符串做爲 props 傳遞給組件

最新的模板語法

最明顯的變化是:咱們對模板語法作了一些改進。npm

咱們常常聽到的反饋是,「哎呀,又是Mustache」或者「哎呀,這不Handlebars嘛」。canvas

在 Web 開發的較早時期,許多開發者使用基於字符串的模板系統,但他們彷佛對模板深痛惡絕。瀏覽器

因爲 Svelte 也採用了這種 {{表達式}} 的語法,所以許多人覺得咱們也在某種程度上有那些相同的侷限性,好比奇怪的做用域規則,或者沒法隨意使用 JavaScript 表達式。bash

提示:若是你須要顯示一個 '{' 字符,那麼它能夠簡單地用 '{' 來表示。

除此之外,JSX 證實了使用雙大括號其實大可沒必要。

因此咱們使得模板更加的 …… 怎麼說呢,

Svelte 採用單個大括號括起表達式。

應該說結果彷佛看起來更輕鬆了,打字時也更愉快了:

<h1>Hello {name}!</h1>

固然也還有一些其餘的更新的。

好消息是你不須要手動去一個一個地改,只須要在代碼庫上運行 svelte-upgrade 就行:

npx svelte-upgrade v2 src

這假定 src 目錄下的任何 .html 文件都是一個小組件。

源目錄和目標目錄都可以任君自由指定,例如,你可使用 npx svelte-upgrade v2 routes 更新 Sapper 應用。

要查看完整的變動列表,請移尊步到 svelte-upgrade 的 README 文檔

計算屬性

人們常常對 Svelte 感到困惑的一件事情是計算屬性的工做方式。

回顧一下,若是你有這麼一個組件……

export  default  {
  computed:  {
    d: (a, b, c)  => a = b + c
  }
};

……Svelte 首先檢查函數的參數,以便計算出 d 所依賴的參數是什麼,而後它會自動編寫好代碼,在這些值發生改變時,經過將新值注入到函數中,從而更新 d

很酷吧!

由於它容許你從組件的輸入中獲取複雜的值,而沒必要擔憂什麼時候須要從新計算它們,但這用法也怪里怪氣的。

JavaScript 語法不支持這麼寫。

在 v2,咱們用解構來代替:

export  default  { 
  computed:  {  
    d: ({ a, b, c })  => a = b + c 
  }  
};

Svelte 編譯器仍然能夠知道 d 依賴哪一個值,但再也不注入值,而是將整個組件狀態對象丟給每一個計算的屬性中。

友情提示:你一樣不須要手動進行此更改,只須要對組件運行 svelte-upgrade,如上所示。

IE11,很差意思,好自爲之

Svelte v1 生成的是 ES5 的代碼,這樣你就不會被迫使用轉譯器。

但如今都 2018 年了,幾乎全部瀏覽器都支持現代 JavaScript。若是能拋棄 ES5 的束縛,咱們就能夠生成更精簡的代碼。

不過你若是還須要友好地支持 IE11,你仍是能夠用 Babel 或者 Bublé 之類的轉譯器的。

新的生命週期 Hook

除了 oncreateondestroy 外,Svelte v2 還添加了兩個生命週期函數來響應狀態更改:

export default {  
  onstate({ changed, current, previous }) {  
    // 在 oncreate 以前以及狀態變動時觸發  
  },  
  onupdate({ changed, current, previous }) {  
    // 在 oncreate 以後觸發, 而且狀態變動後更新了 DOM 時觸發  
  }  
};

你還能夠經過編寫代碼的方式監聽這些事件:

component.on('state',  ({ changed, current, previous })  => {  
  // ...  
});

component.observe

使用新的生命週期函數,咱們再也不須要 component.observe(...) 方法:

// 以前  
export default {  
  oncreate() {  
    this.observe('foo', foo => { 
      console.log(`foo is now ${foo}`);  
    });  
  }  
};  

// 以後
export default {
  onstate({ changed, current }) {
    if (changed.foo) {
      console.log(`foo is now ${current.foo}`);  
    }  
  }  
};

這能夠減小 Svelte 生成的代碼量,併爲你提供了更大的靈活性。

例如,如今能夠十分容易在幾個屬性中的任何一個發生變動時響應這些動做,比方說在不釋放觀察者的狀況下進行重繪 canvas。

不過若是你實在喜歡使用 component.observe(...),你能夠經過 svelte-extras 來支持這玩意。

import { observe } from 'svelte-extras';

export default {
  methods: { observe } 
};

component.get

這個方法再也不接收可選的 key 參數 —— 相反,它總數返回整個 state 對象:

// 以前  
const foo =  this.get('foo');
const bar =  this.get('bar');  

// 以後
const  { foo, bar }  =  this.get();

初時,這種改變可能看起來很煩人,但這是正確的方向:

除了其餘特殊狀況外,未來咱們會更充分地探索這個方面,它可能會在類型系統中發揮更好的做用。

event_handler.destroy

若是你的應用程序具備自定義的事件處理器,那麼它必須返回一個帶有 destroy 方法,而不是 teardown 方法。這樣事件處理器就和組件的 API 對齊了。

再也不嚴格要求類型

之前,傳遞給組件的數字類型的值會被視爲純數字:

<Counter  start='1'  />

這可能會致使一些意外行爲。如今已經被更改了。

若是你須要傳遞數字的字面量,能夠直接用表達式:

<Counter  start={1}  />

編譯器方面的變動

在大多數狀況下,你是永遠不須要直接和編譯器打交道的,所以編譯器方面你其實不須要什麼對策的。

無論怎麼說,值得注意的是:編譯器的 API 也是有變動的。

如今編譯器將返回 jscssaststats,而不是有一大堆屬性的對象:

const { js, css, ast, stats }  = svelte.compile(source, options);

jscss 都是 {code, map} 對象,其中 code 是代碼字符串,map 表明 sourcemap。

ast 是組件的抽象語法樹,而且 stats 對象包含有關組件的元數據以及編譯信息。

之前是有一個 svelte.validate 方法來檢查你的組件是否有效的。

不過它已經被刪掉了,若是你只需檢查組件,而不實際對其進行編譯的話,那麼僅僅傳遞一個 generate: false 選項便可。

個人應用還有問題要尋求幫助

但願以上的內容已經覆蓋了全部可能的問題,而且更新對你來講,應該比較輕鬆從容的。

若是你發現錯誤或者本文未盡事項,請進入 Discord 聊天室 裏頭轉轉看,或者在 issue 跟蹤器 反饋給咱們。

< The End >

  • 窗明几淨,靜候時日變遷 -
相關文章
相關標籤/搜索