optimise for the common case

pull/15538/head
Rich Harris 4 months ago
parent 941f266827
commit faf18220e0

@ -19,14 +19,14 @@ export function template_to_functions(items) {
function build(item) { function build(item) {
switch (item.type) { switch (item.type) {
case 'element': { case 'element': {
const element = b.object([b.prop('init', b.id('e'), b.literal(item.name))]); const element = b.array([b.literal(item.name)]);
const attributes = b.prop('init', b.id('p'), b.object([])); const attributes = b.object([]);
for (const key in item.attributes) { for (const key in item.attributes) {
const value = item.attributes[key]; const value = item.attributes[key];
attributes.value.properties.push( attributes.properties.push(
b.prop( b.prop(
'init', 'init',
b.key(fix_attribute_casing(key)), b.key(fix_attribute_casing(key)),
@ -35,13 +35,13 @@ function build(item) {
); );
} }
if (attributes.value.properties.length > 0) { if (attributes.properties.length > 0 || item.children.length > 0) {
element.properties.push(attributes); element.elements.push(attributes.properties.length > 0 ? attributes : b.null);
} }
if (item.children.length > 0) { if (item.children.length > 0) {
const children = item.children.map(build); const children = item.children.map(build);
element.properties.push(b.prop('init', b.id('c'), b.array(children))); element.elements.push(...children);
// special case — strip leading newline from `<pre>` and `<textarea>` // special case — strip leading newline from `<pre>` and `<textarea>`
if (item.name === 'pre' || item.name === 'textarea') { if (item.name === 'pre' || item.name === 'textarea') {
@ -59,7 +59,7 @@ function build(item) {
} }
case 'anchor': { case 'anchor': {
return item.data ? b.array([b.literal(item.data)]) : null; return item.data ? b.array([b.literal(`// ${item.data}`)]) : null;
} }
case 'text': { case 'text': {

@ -1,4 +1,5 @@
/** @import { Effect, TemplateNode } from '#client' */ /** @import { Effect, TemplateNode } from '#client' */
/** @import { TemplateStructure } from './types' */
import { hydrate_next, hydrate_node, hydrating, set_hydrate_node } from './hydration.js'; import { hydrate_next, hydrate_node, hydrating, set_hydrate_node } from './hydration.js';
import { import {
create_text, create_text,
@ -76,46 +77,44 @@ export function template(content, flags) {
return clone; return clone;
}; };
} }
/** /**
* @typedef {{e: string, p: Record<string, string>, c: Array<TemplateStructure>} | undefined | string | [string]} TemplateStructure * @param {TemplateStructure[]} structure
*/
/**
* @param {Array<TemplateStructure>} structure
* @param {NAMESPACE_SVG | NAMESPACE_MATHML | undefined} [ns] * @param {NAMESPACE_SVG | NAMESPACE_MATHML | undefined} [ns]
*/ */
function structure_to_fragment(structure, ns) { function structure_to_fragment(structure, ns) {
var fragment = create_fragment(); var fragment = create_fragment();
for (var item of structure) { for (var item of structure) {
if (item === undefined || Array.isArray(item)) { if (typeof item === 'string') {
fragment.append(create_comment(item ? item[0] : '')); fragment.append(create_text(item));
continue; continue;
} }
if (typeof item === 'string') { // if `preserveComments === true`, comments are represented as `['// <data>']`
fragment.append(create_text(item)); if (item === undefined || item[0][0] === '/') {
fragment.append(create_comment(item ? item[0].slice(3) : ''));
continue; continue;
} }
const [name, attributes, ...children] = item;
/** @type {NAMESPACE_SVG | NAMESPACE_MATHML | undefined} */ /** @type {NAMESPACE_SVG | NAMESPACE_MATHML | undefined} */
let namespace = item.e === 'svg' ? NAMESPACE_SVG : item.e === 'math' ? NAMESPACE_MATHML : ns; let namespace = name === 'svg' ? NAMESPACE_SVG : name === 'math' ? NAMESPACE_MATHML : ns;
var element = create_element(item.e, namespace, item.p?.is); var element = create_element(name, namespace, attributes?.is);
for (var key in item.p) { for (var key in attributes) {
set_attribute(element, key, item.p[key]); set_attribute(element, key, attributes[key]);
} }
if (item.c) { if (children.length > 0) {
var target = var target =
element.tagName === 'TEMPLATE' element.tagName === 'TEMPLATE'
? /** @type {HTMLTemplateElement} */ (element).content ? /** @type {HTMLTemplateElement} */ (element).content
: element; : element;
target.append( target.append(
structure_to_fragment(item.c, element.tagName === 'foreignObject' ? undefined : namespace) structure_to_fragment(children, element.tagName === 'foreignObject' ? undefined : namespace)
); );
} }

@ -0,0 +1,4 @@
export type TemplateStructure =
| string
| undefined
| [string, Record<string, string> | undefined, ...TemplateStructure[]];

@ -5,7 +5,7 @@ function increment(_, counter) {
counter.count += 1; counter.count += 1;
} }
var root = $.template_fn([{ e: 'button', c: [' '] }, ' ', , ' '], 1); var root = $.template_fn([['button', null, ' '], ' ', , ' '], 1);
export default function Await_block_scope($$anchor) { export default function Await_block_scope($$anchor) {
let counter = $.proxy({ count: 0 }); let counter = $.proxy({ count: 0 });

@ -3,17 +3,17 @@ import * as $ from 'svelte/internal/client';
var root = $.template_fn( var root = $.template_fn(
[ [
{ e: 'div' }, ['div'],
' ', ' ',
{ e: 'svg' }, ['svg'],
' ', ' ',
{ e: 'custom-element' }, ['custom-element'],
' ', ' ',
{ e: 'div' }, ['div'],
' ', ' ',
{ e: 'svg' }, ['svg'],
' ', ' ',
{ e: 'custom-element' } ['custom-element']
], ],
3 3
); );

@ -2,7 +2,7 @@ import 'svelte/internal/disclose-version';
import 'svelte/internal/flags/legacy'; import 'svelte/internal/flags/legacy';
import * as $ from 'svelte/internal/client'; import * as $ from 'svelte/internal/client';
var root_1 = $.template_fn([{ e: 'p' }]); var root_1 = $.template_fn([['p']]);
export default function Each_index_non_null($$anchor) { export default function Each_index_non_null($$anchor) {
var fragment = $.comment(); var fragment = $.comment();

@ -2,7 +2,7 @@ import 'svelte/internal/disclose-version';
import 'svelte/internal/flags/legacy'; import 'svelte/internal/flags/legacy';
import * as $ from 'svelte/internal/client'; import * as $ from 'svelte/internal/client';
var root = $.template_fn([{ e: 'h1', c: ['hello world'] }]); var root = $.template_fn([['h1', null, 'hello world']]);
export default function Hello_world($$anchor) { export default function Hello_world($$anchor) {
var h1 = root(); var h1 = root();

@ -2,7 +2,7 @@ import 'svelte/internal/disclose-version';
import 'svelte/internal/flags/legacy'; import 'svelte/internal/flags/legacy';
import * as $ from 'svelte/internal/client'; import * as $ from 'svelte/internal/client';
var root = $.template_fn([{ e: 'h1', c: ['hello world'] }]); var root = $.template_fn([['h1', null, 'hello world']]);
function Hmr($$anchor) { function Hmr($$anchor) {
var h1 = root(); var h1 = root();

@ -5,13 +5,13 @@ var on_click = (_, count) => $.update(count);
var root = $.template_fn( var root = $.template_fn(
[ [
{ e: 'h1' }, ['h1'],
' ', ' ',
{ e: 'b' }, ['b'],
' ', ' ',
{ e: 'button', c: [' '] }, ['button', null, ' '],
' ', ' ',
{ e: 'h1' } ['h1']
], ],
1 1
); );

@ -2,7 +2,7 @@ import 'svelte/internal/disclose-version';
import 'svelte/internal/flags/legacy'; import 'svelte/internal/flags/legacy';
import * as $ from 'svelte/internal/client'; import * as $ from 'svelte/internal/client';
var root = $.template_fn([{ e: 'p' }, ' ', { e: 'p' }, ' ', ,], 1); var root = $.template_fn([['p'], ' ', ['p'], ' ', ,], 1);
export default function Purity($$anchor) { export default function Purity($$anchor) {
var fragment = root(); var fragment = root();

@ -3,92 +3,77 @@ import * as $ from 'svelte/internal/client';
var root = $.template_fn( var root = $.template_fn(
[ [
{ [
e: 'header', 'header',
c: [ null,
{ [
e: 'nav', 'nav',
c: [ null,
{ e: 'a', p: { href: '/' }, c: ['Home'] }, ['a', { href: '/' }, 'Home'],
' ', ' ',
{ ['a', { href: '/away' }, 'Away']
e: 'a',
p: { href: '/away' },
c: ['Away']
}
]
}
] ]
}, ],
' ', ' ',
{ [
e: 'main', 'main',
c: [ null,
{ e: 'h1', c: [' '] }, ['h1', null, ' '],
' ', ' ',
{ [
e: 'div', 'div',
p: { class: 'static' }, { class: 'static' },
c: [ [
{ 'p',
e: 'p', null,
c: ['we don\'t need to traverse these nodes'] 'we don\'t need to traverse these nodes'
}
] ]
}, ],
' ', ' ',
{ e: 'p', c: ['or'] }, ['p', null, 'or'],
' ', ' ',
{ e: 'p', c: ['these'] }, ['p', null, 'these'],
' ', ' ',
{ e: 'p', c: ['ones'] }, ['p', null, 'ones'],
' ', ' ',
, ,
' ', ' ',
{ e: 'p', c: ['these'] }, ['p', null, 'these'],
' ', ' ',
{ e: 'p', c: ['trailing'] }, ['p', null, 'trailing'],
' ', ' ',
{ e: 'p', c: ['nodes'] }, ['p', null, 'nodes'],
' ', ' ',
{ e: 'p', c: ['can'] }, ['p', null, 'can'],
' ', ' ',
{ e: 'p', c: ['be'] }, ['p', null, 'be'],
' ', ' ',
{ e: 'p', c: ['completely'] }, ['p', null, 'completely'],
' ', ' ',
{ e: 'p', c: ['ignored'] } ['p', null, 'ignored']
],
' ',
['cant-skip', null, ['custom-elements']],
' ',
['div', null, ['input']],
' ',
['div', null, ['source']],
' ',
['select', null, ['option', null, 'a']],
' ',
[
'img',
{ src: '...', alt: '', loading: 'lazy' }
],
' ',
[
'div',
null,
[
'img',
{ src: '...', alt: '', loading: 'lazy' }
] ]
},
' ',
{
e: 'cant-skip',
c: [{ e: 'custom-elements' }]
},
' ',
{ e: 'div', c: [{ e: 'input' }] },
' ',
{ e: 'div', c: [{ e: 'source' }] },
' ',
{
e: 'select',
c: [{ e: 'option', c: ['a'] }]
},
' ',
{
e: 'img',
p: { src: '...', alt: '', loading: 'lazy' }
},
' ',
{
e: 'div',
c: [
{
e: 'img',
p: { src: '...', alt: '', loading: 'lazy' }
}
] ]
}
], ],
3 3
); );

@ -10,11 +10,11 @@ function reset(_, str, tpl) {
var root = $.template_fn( var root = $.template_fn(
[ [
{ e: 'input' }, ['input'],
' ', ' ',
{ e: 'input' }, ['input'],
' ', ' ',
{ e: 'button', c: ['reset'] } ['button', null, 'reset']
], ],
1 1
); );

@ -1,7 +1,7 @@
import 'svelte/internal/disclose-version'; import 'svelte/internal/disclose-version';
import * as $ from 'svelte/internal/client'; import * as $ from 'svelte/internal/client';
var root = $.template_fn([{ e: 'p', c: [' '] }]); var root = $.template_fn([['p', null, ' ']]);
export default function Text_nodes_deriveds($$anchor) { export default function Text_nodes_deriveds($$anchor) {
let count1 = 0; let count1 = 0;

Loading…
Cancel
Save