半熟前端

軟體工程師 / 台灣人 / 在前端的路上一邊探索其他領域的可能性

前端

Svelte 筆記(2):編譯器比你聰明多惹

今天跑去看 Svelte 原始碼,摸熟架構的同時順便看看有沒有什麼簡單的 issue 可以拿來練手。然後看到了這個 — emits warning

雖然我覺得以這個 issue 的描述來看,沒有 href 的 a tag 應該是不合法的才對(至少不符合 a11y),後來我去查了一下,在 StackOverflow 上有提到目前的規範有些不統一的地方。

但基本上 href 可以是空的,只是在這種情況下就不要用 a 而是考慮用 button 之類的標籤取代,這樣對 screen reader 比較友善。

後來我去看了一下 eslint-plugin-jsx-a11y,發現這個 eslint 會去幫你判斷 href 是否為合法值,裡頭非法值有:

<a onClick={foo} /> // 可以用 button 取代
<a href="#" /> // 只有 # 沒有 id
<a href={"#"} /> // 字面值
<a href={`#`} /> // 字面值
<a href="javascript:void(0)" /> // 不應該用 javascript:void(0)
<a href={"javascript:void(0)"} /> // 字面值
<a href={`javascript:void(0)`} /> // 字面值

還有 href 為空的情況:

<a />
<a href={undefined} />
<a href={null} />

Svelte 會幫你檢查基本的 a11y,像是 missing href 或是 href value invalid 等,因為 Svelte 本身有先過一層編譯器,所以檢查都會在編譯階段做:

// compiler/compile/nodes/Element.ts
// L425
		if (this.name === 'a') {
			const attribute = attribute_map.get('href') || attribute_map.get('xlink:href');

			if (attribute) {
				const value = attribute.get_static_value();

				if (value === '' || value === '#') {
					component.warn(attribute, {
						code: `a11y-invalid-attribute`,
						message: `A11y: '${value}' is not a valid ${attribute.name} attribute`
					});
				}
			} else {
				component.warn(this, {
					code: `a11y-missing-attribute`,
					message: `A11y: <a> element should have an href attribute`
				});
			}
		}

在這個階段,svelte 幫你把語法變成了語法樹(AST),所以檢查起來也很方便。

不過定睛一看,咦? javascript:void(0) 的 case 好像沒有處理到,目前只會針對 value 為空跟 # 的情況做處理。所以就順手加了一行檢查: if (value === '' || value === '#' || /^\\W*javascript:/.test(value))Pull Request 了。

另外紀錄一下比較麻煩的是 svelte 現在只會針對值是 is_static 做檢查,所以像是:

<a href={undefined} />
<a href={null} />
<a href={`#`} />
<a href={"javascript:void(0)"} />
<a href={`javascript:void(0)`} />

因為 {} 裡都是 Expression svelte 檢查不到(會直接把 is_static 標記成 false)。想要檢查的話就要另外針對這些 Expression 做處理,有空(黃金週也快到了)再一次全部修修看。

感覺不是什麼很有用的功能啦,反正是在編譯階段做也不會影響到 bundle size,現在越來越覺得編譯器這條路感覺是行得通的耶,喜歡用什麼樣的方式寫自己決定,反正 compile 完變成 JavaScript 就好。

雖然這也不是什麼新想法,像是 LiveScript 或是 Elm 等等,或多或少都是這樣的概念,但我覺得 Svelte 能夠被大家注意到(或比較容易被使用)的原因在於它保留了大部分的 JavaScript 語法,template 學習成本幾乎是 0(如果你會 React 或 Vue),寫起來就像 HTML, CSS, JavaScript 寫在一起的 Vue 而已。

另外就是 svelte 的 Reactive 機制和動畫控制,這些東西是常常是前端在實作頁面時需要特別考慮的,也是其他編譯器沒辦法提供的。大家都想要 Functional Programming,但實際上如果沒有解決到開發者真正的問題,那麼也只是少數愛好者的執念而已。