スヴェルト・ノート (2): コンパイラはあなたが散らかすよりも賢い

作成者:カランカラン
💡

質問やフィードバックがありましたら、フォームからお願いします

目次

    本文は台湾華語で、ChatGPT で翻訳している記事なので、不確かな部分や間違いがあるかもしれません。ご了承ください

    今日は Svelte のソースコードを見に行き、構造を把握しながら、練習できる簡単な issue がないか探してみました。すると、こちらの — emits warningを見つけました。

    この issue の説明を見た感じでは、href がない a タグは不正であるべきだと思いました(少なくとも a11y に合致しません)。その後調べてみたところ、StackOverflow では現在の規範にいくつかの不統一な点があることが言及されていました。

    基本的には href は空でも問題ないのですが、その場合は a を使うのではなく、button などのタグを検討するべきです。そうすることで、スクリーンリーダーにとってより親切になります。

    その後、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}' は無効な ${attribute.name} 属性です`
    					});
    				}
    			} else {
    				component.warn(this, {
    					code: `a11y-missing-attribute`,
    					message: `A11y: <a> 要素には href 属性が必要です`
    				});
    			}
    		}

    この段階で、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 になるだけです。

    これは新しいアイデアでもありませんが、LiveScriptElm なども、ある程度このような概念です。しかし、Svelte が注目されやすい理由は、大部分の JavaScript 構文を保持しているため、template の学習コストがほぼゼロ(もし React や Vue を知っていれば)であり、HTML、CSS、JavaScript が一緒に書かれている Vue のように感じられるからだと思います。

    さらに、Svelte のリアクティブ機構とアニメーション制御は、フロントエンドがページを実装する際に特に考慮されるべき点であり、他のコンパイラでは提供できないものです。みんなが関数型プログラミングを望んでいますが、実際に開発者の真の問題を解決しなければ、それは単なる一部の愛好者の執念に過ぎません。

    この記事が役に立ったと思ったら、下のリンクからコーヒーを奢ってくれると嬉しいです ☕ 私の普通の一日が輝かしいものになります ✨

    Buy me a coffee