カランのブログ

今のモード ライト

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

今日はSvelteのソースコードを見に行き、アーキテクチャを把握しながら、練習用に簡単な問題がないかを見てみました。そして、この問題 - emits warning を見つけました。

この問題の説明を見る限り、href属性のないaタグは正当ではないと思います(少なくともa11yには違反していると思います)。その後、調べてみると、StackOverflowに現在の仕様に関して統一性のない点がいくつかあることが書かれています。

しかし、基本的にはhrefは空であっても問題ありません。ただし、この場合はaではなく、代わりにボタンなどの要素を考慮するべきです。これにより、スクリーンリーダーにとってより優れたアクセシビリティが実現されます。

その後、eslint-plugin-jsx-a11yを見てみると、このeslintがhrefの値が有効かどうかを判断してくれることがわかりました。以下は無効な値の例です:

<a onClick={foo} /> // ボタンで置き換えることができます
<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チェックを行ってくれます。たとえば、hrefが欠落しているか、または無効な値であるかなどです。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)」のケースは処理されていないようです。現在は空の値と#の場合にのみ処理されます。そこで、「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に対して別途処理を行う必要があります。時間があれば(黄金週も近いですし)、すべての修正を行ってみます。

あまり役に立たない機能のように感じますが、コンパイル段階で実行されるため、バンドルサイズには影響しません。最近では、コンパイラのアプローチは有効な方法のように感じます。自分がどのような方法で書くかは自由であり、コンパイル後にJavaScriptに変換されるだけです。

これは新しい考えではありませんが、「LiveScript」や「Elm」なども同様のコンセプトを持っています。Svelteが注目される(または比較的使いやすい)理由は、ほとんどのJavaScriptの文法を保持していることと、テンプレートの学習コストがほぼゼロであることです(ReactやVueを知っている場合)。HTML、CSS、JavaScriptが一緒に書かれたVueのようなものです。

また、Svelteのリアクティブ機構やアニメーション制御も重要な点です。これらは、フロントエンド開発時に特に考慮する必要があるものであり、他のコンパイラでは提供できません。みんなが関数型プログラミングを望んでいますが、実際には開発者の真の問題を解決できない限り、それは少数の愛好家の執念に過ぎません。

この文章が役に立つと思うなら、下のリンクで応援してくれると大変嬉しいです✨

Buy me a coffee