Svelte Notes (2): Compiler is more clever than you mess

Written byKalanKalan
💡

If you have any questions or feedback, pleasefill out this form

Table of Contents

    This post is translated by ChatGPT and originally written in Mandarin, so there may be some inaccuracies or mistakes.

    Today, I went to check out the Svelte source code, familiarizing myself with the architecture while also looking for some simple issues to practice on. I came across this one — emits warning.

    Although I believe that, based on the issue's description, an a tag without an href should be considered invalid (at least it doesn’t comply with a11y standards), I later found out that there are some inconsistencies in the current specifications mentioned on StackOverflow.

    Basically, an href can be empty, but in such cases, it’s better to use a button or similar tag instead, as this is more friendly for screen readers.

    Afterward, I checked out eslint-plugin-jsx-a11y and found that this ESLint plugin helps you determine if an href is a valid value. Here are some invalid values:

    <a onClick={foo} /> // Can be replaced with button
    <a href="#" /> // Only # without an id
    <a href={"#"} /> // Literal value
    <a href={`#`} /> // Literal value
    <a href="javascript:void(0)" /> // Should not use javascript:void(0)
    <a href={"javascript:void(0)"} /> // Literal value
    <a href={`javascript:void(0)`} /> // Literal value

    And cases where href is empty:

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

    Svelte performs basic a11y checks, such as missing href or invalid href values. Since Svelte itself has a compiler, these checks are carried out during the compilation phase:

    // 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`
    				});
    			}
    		}

    At this stage, Svelte transforms the syntax into an Abstract Syntax Tree (AST), which makes the checks very convenient.

    However, upon closer inspection, I noticed that the case for javascript:void(0) seems to be unhandled; currently, it only processes cases where the value is empty or #. So, I casually added a line for checking: if (value === '' || value === '#' || /^\W*javascript:/.test(value)) and proposed a Pull Request.

    Additionally, it’s worth noting that Svelte currently only checks values that are is_static, so for cases like:

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

    Since the expressions inside {} are not detected by Svelte (they are marked as is_static false), you would need to implement additional handling for these expressions. If I have time (Golden Week is approaching), I’ll look into fixing these.

    It doesn’t seem like a particularly useful feature, but since it’s done during the compilation phase, it won't affect the bundle size. I’m increasingly convinced that the path of using a compiler is viable; you can write in whatever way you prefer, as long as it compiles down to JavaScript.

    Although this isn’t a new idea—languages like LiveScript or Elm have similar concepts to varying extents—I think the reason Svelte has gained attention (and is more widely used) is that it retains most of the JavaScript syntax. The learning curve for templates is nearly zero (if you know React or Vue), and it feels like Vue with HTML, CSS, and JavaScript seamlessly integrated.

    Moreover, Svelte's reactive mechanism and animation control are aspects that frontend developers need to consider when implementing pages, which other compilers may not be able to provide. Everyone wants Functional Programming, but if it doesn’t solve the real problems developers face, it remains merely a passion for a select few.

    If you found this article helpful, please consider buying me a coffee ☕ It'll make my ordinary day shine ✨

    Buy me a coffee