Svelte: More aggressive innerHTML optimization detection

Created on 8 Apr 2019  路  2Comments  路  Source: sveltejs/svelte

Svelte will fallback to using innerHTML if a block of markup is entirely static. This results in much less generated code. I noticed that if a single item in that block is dynamic, regardless of its position, the output is deopt'd and it falls back to just using element and append for everything.

Here is an example of having a single dynamic element in a list. This can potentially result in a lot more generated code, creating local variables in create_fragment that don't really need to exist.

Instead of falling back to the imperative DOM APIs could svelte detect if using a combination of both would be beneficial? In this example you could still use innerHTML to define the n - 1 list elements and then use element / append for the one dynamic tag. This seems like it would be easiest when the dynamic element is the first or last child, but I imagine you could also do this with element.innerHTML += "..."

enhancement integrations perf

Most helpful comment

That's a good idea. I don't think we can do element.innerHTML += x, since that would break existing references, but we can do this sort of thing:

ul = element('ul');
ul.innerHTML = `<li>one</li><li>two</li>`;
li = element('li');
li.textContent = name;
li.insertAdjacentHTML('afterEnd', `'<li>four</li><li>five</li>`);

In this case, where we already know that name never changes (since it's not a prop, and isn't the subject of any assignments) we could actually go further still:

ul = element('ul');
ul.innerHTML = `<li>one</li><li>two</li><li>${name}</li><li>four</li><li>five</li>`;

A minifier ought to be able to turn that into a static string.

It's also true that in some cases we could do this sort of thing, if we did need references:

ul = element('ul');
ul.innerHTML = `<li>one</li><li>two</li><li>${ctx.name}</li><li>four</li><li>five</li>`;
t = ul.children[2].childNodes[0];

All 2 comments

That's a good idea. I don't think we can do element.innerHTML += x, since that would break existing references, but we can do this sort of thing:

ul = element('ul');
ul.innerHTML = `<li>one</li><li>two</li>`;
li = element('li');
li.textContent = name;
li.insertAdjacentHTML('afterEnd', `'<li>four</li><li>five</li>`);

In this case, where we already know that name never changes (since it's not a prop, and isn't the subject of any assignments) we could actually go further still:

ul = element('ul');
ul.innerHTML = `<li>one</li><li>two</li><li>${name}</li><li>four</li><li>five</li>`;

A minifier ought to be able to turn that into a static string.

It's also true that in some cases we could do this sort of thing, if we did need references:

ul = element('ul');
ul.innerHTML = `<li>one</li><li>two</li><li>${ctx.name}</li><li>four</li><li>five</li>`;
t = ul.children[2].childNodes[0];

This seems potentially quite similar to https://github.com/sveltejs/svelte/issues/3898

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rob-balfre picture rob-balfre  路  3Comments

1u0n picture 1u0n  路  3Comments

mmjmanders picture mmjmanders  路  3Comments

robnagler picture robnagler  路  3Comments

davidcallanan picture davidcallanan  路  3Comments