Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistency in SSR boolean and null attributes when using spread syntax #2916

Closed
domingues opened this issue May 31, 2019 · 4 comments · Fixed by #3797
Closed

Inconsistency in SSR boolean and null attributes when using spread syntax #2916

domingues opened this issue May 31, 2019 · 4 comments · Fixed by #3797
Labels

Comments

@domingues
Copy link

domingues commented May 31, 2019

<input type="text" disabled={true}/>
<input type="text" {...{disabled:true}}/>
<input type="text" disabled={1}/>
<input type="text" {...{disabled:1}}/>
<input type="text" value={null}/>
<input type="text" {...{value:null}}/>

will render

<input type="text" disabled>
<input type="text" disabled disabled="true">
<input type="text" disabled>
<input type="text" disabled="1">
<input type="text">
<input type="text" value="null">

The duplication on line two could also be seen in REPL with:

<script>
	import { spread } from "svelte/internal"
</script>
{spread([{disabled:true}])}
@domingues domingues changed the title SSR duplicated boolean attributes when using spread syntax Inconsistency in SSR boolean attributes when using spread syntax May 31, 2019
@domingues domingues changed the title Inconsistency in SSR boolean attributes when using spread syntax Inconsistency in SSR boolean and null attributes when using spread syntax May 31, 2019
@Conduitry Conduitry added the bug label Jul 28, 2019
@Conduitry
Copy link
Member

On latest master (3.13.0-alpha.2) I'm currently getting

<input type="text" disabled>
<input type="text" disabled disabled="true">
<input type="text" disabled>
<input type="text" disabled="1">
<input type="text">
<input type="text">

So spreading objects with nulls in them has been fixed (by #3775).

I'm undecided whether {...{disabled:1}} rendering as disabled="1" is actually a problem. It would still be nice to get that to be just disabled.

{...{disabled:true}} rendering as disabled disabled="true" is definitely a bug and is weird, and I will look into that soon.

@Conduitry
Copy link
Member

The double attribute issue is just a simple logic error, and can be fixed with

diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts
index 83e585a8..61f81016 100644
--- a/src/runtime/internal/ssr.ts
+++ b/src/runtime/internal/ssr.ts
@@ -21,7 +21,10 @@ export function spread(args, classes_to_add) {
 
 		const value = attributes[name];
 		if (value == null) return;
-		if (value === true) str += " " + name;
+		if (value === true) {
+			str += " " + name;
+			return;
+		}
 
 		const escaped = String(value)
 			.replace(/"/g, '&#34;')

It's not specifically mentioned in this issue, but I'm not sure how we'd want to deal with something like <input {...{ disabled: false }}>. Right now, this renders <input disabled="false">, which is incorrect. It seems the only way to handle this correctly is to ship the array of boolean attributes as a helper used by SSR. It doesn't seem avoidable, as there's no way to partially rely on the DOM API in SSR mode. I'd been really against including these sorts of tables of metadata in compiled DOM mode code, but including it in SSR mode code doesn't seem so bad.

@Conduitry
Copy link
Member

Pushed what I have so far to this branch. One slight wrinkle is just that this introduces code that we want to have available at build time and at run time, which I don't think has precedent. I elected to stick this shared data in src/compiler/compile/render_ssr/handlers/shared/boolean_attributes.ts, and then to also import it from there in src/runtime/internal/ssr.ts. TypeScript and ESLint don't seem to have any complaints about that.

There are also still some differences between DOM and SSR mode in how non-boolean attributes that are explicitly given foo={true} values (as opposed to simply being bare attributes) are treated - but these differences exist even without spreads involved, and it's really an edge case, so I don't think it's something that we need to worry about here.

Another difference between DOM and SSR handling of boolean attributes is that in SSR mode, no checking is done to see whether this attribute is boolean for this element. There's just a list of boolean attributes. We can revisit this later if it becomes a problem, but in the meantime it would probably be prudent to update the list of boolean attributes according to the attribute_lookup fleshing out that was done a few months ago - both the addition and the removal of attributes that are considered boolean. I'll do this shortly.

@Conduitry
Copy link
Member

So, as with a couple of these spread-related issues, the scope of my in-progress PR ends up expanding beyond the original issue, oh well.

Something that currently generates incorrect code in SSR mode is this:

<script>
	let autocomplete = 'no';
</script>

<input {autocomplete}>

Since autocomplete is (incorrectly) currently seen as a boolean attribute, it would be conditionally attached depending on whether foo is truthy. With this branch, it will be treated as a normal attribute, which it is.

Conduitry added a commit to Conduitry/sveltejs_svelte that referenced this issue Oct 26, 2019
Conduitry added a commit that referenced this issue Oct 27, 2019
* in SSR, adjust spread with boolean attributes (#2916)

* add tests

* update changelog
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants