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) {
switch (item.type) {
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) {
const value = item.attributes[key];
attributes.value.properties.push(
attributes.properties.push(
b.prop(
'init',
b.key(fix_attribute_casing(key)),
@ -35,13 +35,13 @@ function build(item) {
);
}
if (attributes.value.properties.length > 0) {
element.properties.push(attributes);
if (attributes.properties.length > 0 || item.children.length > 0) {
element.elements.push(attributes.properties.length > 0 ? attributes : b.null);
}
if (item.children.length > 0) {
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>`
if (item.name === 'pre' || item.name === 'textarea') {
@ -59,7 +59,7 @@ function build(item) {
}
case 'anchor': {
return item.data ? b.array([b.literal(item.data)]) : null;
return item.data ? b.array([b.literal(`// ${item.data}`)]) : null;
}
case 'text': {

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

@ -3,17 +3,17 @@ import * as $ from 'svelte/internal/client';
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
);

@ -2,7 +2,7 @@ import 'svelte/internal/disclose-version';
import 'svelte/internal/flags/legacy';
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) {
var fragment = $.comment();

@ -2,7 +2,7 @@ import 'svelte/internal/disclose-version';
import 'svelte/internal/flags/legacy';
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) {
var h1 = root();

@ -2,7 +2,7 @@ import 'svelte/internal/disclose-version';
import 'svelte/internal/flags/legacy';
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) {
var h1 = root();

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

@ -2,7 +2,7 @@ import 'svelte/internal/disclose-version';
import 'svelte/internal/flags/legacy';
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) {
var fragment = root();

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

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

@ -1,7 +1,7 @@
import 'svelte/internal/disclose-version';
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) {
let count1 = 0;

Loading…
Cancel
Save