mirror of https://github.com/sveltejs/svelte
commit
a11820f71d
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: properly separate multiline html blocks from each other in `print()`
|
||||
@ -1,91 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
import { busy } from './util.js';
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let computed1 = $.derived(() => $.get(head));
|
||||
let computed2 = $.derived(() => ($.get(computed1), 0));
|
||||
let computed3 = $.derived(() => (busy(), $.get(computed2) + 1)); // heavy computation
|
||||
let computed4 = $.derived(() => $.get(computed3) + 2);
|
||||
let computed5 = $.derived(() => $.get(computed4) + 3);
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(computed5);
|
||||
busy(); // heavy side effect
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(computed5) === 6);
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(computed5) === 6);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_avoidable_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_avoidable_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_avoidable_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_avoidable_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let last = head;
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let current = $.derived(() => {
|
||||
return $.get(head) + i;
|
||||
});
|
||||
let current2 = $.derived(() => {
|
||||
return $.get(current) + 1;
|
||||
});
|
||||
$.render_effect(() => {
|
||||
$.get(current2);
|
||||
counter++;
|
||||
});
|
||||
last = current2;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
counter = 0;
|
||||
for (let i = 0; i < 50; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(last) === i + 50);
|
||||
}
|
||||
assert(counter === 50 * 50);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_broad_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_broad_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_broad_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_broad_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let len = 50;
|
||||
const iter = 50;
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let current = head;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let c = current;
|
||||
current = $.derived(() => {
|
||||
return $.get(c) + 1;
|
||||
});
|
||||
}
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
counter = 0;
|
||||
for (let i = 0; i < iter; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(current) === len + i);
|
||||
}
|
||||
assert(counter === iter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_deep_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_deep_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_deep_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_deep_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let width = 5;
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let current = [];
|
||||
for (let i = 0; i < width; i++) {
|
||||
current.push(
|
||||
$.derived(() => {
|
||||
return $.get(head) + 1;
|
||||
})
|
||||
);
|
||||
}
|
||||
let sum = $.derived(() => {
|
||||
return current.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||
});
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(sum);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(sum) === 2 * width);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 500; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(sum) === (i + 1) * width);
|
||||
}
|
||||
assert(counter === 500);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_diamond_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_diamond_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_diamond_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_diamond_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,94 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
function setup() {
|
||||
let heads = new Array(100).fill(null).map((_) => $.state(0));
|
||||
const mux = $.derived(() => {
|
||||
return Object.fromEntries(heads.map((h) => $.get(h)).entries());
|
||||
});
|
||||
const splited = heads
|
||||
.map((_, index) => $.derived(() => $.get(mux)[index]))
|
||||
.map((x) => $.derived(() => $.get(x) + 1));
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
splited.forEach((x) => {
|
||||
$.render_effect(() => {
|
||||
$.get(x);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
$.flush(() => {
|
||||
$.set(heads[i], i);
|
||||
});
|
||||
assert($.get(splited[i]) === i + 1);
|
||||
}
|
||||
for (let i = 0; i < 10; i++) {
|
||||
$.flush(() => {
|
||||
$.set(heads[i], i * 2);
|
||||
});
|
||||
assert($.get(splited[i]) === i * 2 + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_mux_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_mux_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_mux_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_mux_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,98 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let size = 30;
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let current = $.derived(() => {
|
||||
let result = 0;
|
||||
for (let i = 0; i < size; i++) {
|
||||
result += $.get(head);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(current) === size);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(current) === i * size);
|
||||
}
|
||||
assert(counter === 100);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_repeated_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_repeated_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_repeated_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_repeated_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,111 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let width = 10;
|
||||
|
||||
function count(number) {
|
||||
return new Array(number)
|
||||
.fill(0)
|
||||
.map((_, i) => i + 1)
|
||||
.reduce((x, y) => x + y, 0);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
let current = head;
|
||||
let list = [];
|
||||
for (let i = 0; i < width; i++) {
|
||||
let c = current;
|
||||
list.push(current);
|
||||
current = $.derived(() => {
|
||||
return $.get(c) + 1;
|
||||
});
|
||||
}
|
||||
let sum = $.derived(() => {
|
||||
return list.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(sum);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
const constant = count(width);
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(sum) === constant);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert($.get(sum) === constant - width + i * width);
|
||||
}
|
||||
assert(counter === 100);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_triangle_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_triangle_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_triangle_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_triangle_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
import { assert, fastest_test } from '../../../utils.js';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
function setup() {
|
||||
let head = $.state(0);
|
||||
const double = $.derived(() => $.get(head) * 2);
|
||||
const inverse = $.derived(() => -$.get(head));
|
||||
let current = $.derived(() => {
|
||||
let result = 0;
|
||||
for (let i = 0; i < 20; i++) {
|
||||
result += $.get(head) % 2 ? $.get(double) : $.get(inverse);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert($.get(current) === 40);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
}
|
||||
assert(counter === 100);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_unstable_unowned() {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_unstable_unowned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
|
||||
export async function kairo_unstable_owned() {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run();
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const { timing } = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run();
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return {
|
||||
benchmark: 'kairo_unstable_owned',
|
||||
time: timing.time.toFixed(2),
|
||||
gc_time: timing.gc_time.toFixed(2)
|
||||
};
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
export function busy() {
|
||||
let a = 0;
|
||||
for (let i = 0; i < 1_00; i++) {
|
||||
a++;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
import { busy } from '../util.js';
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let computed1 = $.derived(() => $.get(head));
|
||||
let computed2 = $.derived(() => ($.get(computed1), 0));
|
||||
let computed3 = $.derived(() => (busy(), $.get(computed2) + 1)); // heavy computation
|
||||
let computed4 = $.derived(() => $.get(computed3) + 2);
|
||||
let computed5 = $.derived(() => $.get(computed4) + 3);
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(computed5);
|
||||
busy(); // heavy side effect
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(computed5), 6);
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(computed5), 6);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,41 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let last = head;
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let current = $.derived(() => {
|
||||
return $.get(head) + i;
|
||||
});
|
||||
let current2 = $.derived(() => {
|
||||
return $.get(current) + 1;
|
||||
});
|
||||
$.render_effect(() => {
|
||||
$.get(current2);
|
||||
counter++;
|
||||
});
|
||||
last = current2;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
counter = 0;
|
||||
for (let i = 0; i < 50; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(last), i + 50);
|
||||
}
|
||||
assert.equal(counter, 50 * 50);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,41 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let len = 50;
|
||||
const iter = 50;
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let current = head;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let c = current;
|
||||
current = $.derived(() => {
|
||||
return $.get(c) + 1;
|
||||
});
|
||||
}
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
counter = 0;
|
||||
for (let i = 0; i < iter; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(current), len + i);
|
||||
}
|
||||
assert.equal(counter, iter);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,45 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let width = 5;
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let current = [];
|
||||
for (let i = 0; i < width; i++) {
|
||||
current.push(
|
||||
$.derived(() => {
|
||||
return $.get(head) + 1;
|
||||
})
|
||||
);
|
||||
}
|
||||
let sum = $.derived(() => {
|
||||
return current.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||
});
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(sum);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(sum), 2 * width);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 500; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(sum), (i + 1) * width);
|
||||
}
|
||||
assert.equal(counter, 500);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,38 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
export default () => {
|
||||
let heads = new Array(100).fill(null).map((_) => $.state(0));
|
||||
const mux = $.derived(() => {
|
||||
return Object.fromEntries(heads.map((h) => $.get(h)).entries());
|
||||
});
|
||||
const splited = heads
|
||||
.map((_, index) => $.derived(() => $.get(mux)[index]))
|
||||
.map((x) => $.derived(() => $.get(x) + 1));
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
splited.forEach((x) => {
|
||||
$.render_effect(() => {
|
||||
$.get(x);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
$.flush(() => {
|
||||
$.set(heads[i], i);
|
||||
});
|
||||
assert.equal($.get(splited[i]), i + 1);
|
||||
}
|
||||
for (let i = 0; i < 10; i++) {
|
||||
$.flush(() => {
|
||||
$.set(heads[i], i * 2);
|
||||
});
|
||||
assert.equal($.get(splited[i]), i * 2 + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,42 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let size = 30;
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let current = $.derived(() => {
|
||||
let result = 0;
|
||||
for (let i = 0; i < size; i++) {
|
||||
result += $.get(head);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(current), size);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(current), i * size);
|
||||
}
|
||||
assert.equal(counter, 100);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,55 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
let width = 10;
|
||||
|
||||
function count(number) {
|
||||
return new Array(number)
|
||||
.fill(0)
|
||||
.map((_, i) => i + 1)
|
||||
.reduce((x, y) => x + y, 0);
|
||||
}
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
let current = head;
|
||||
let list = [];
|
||||
for (let i = 0; i < width; i++) {
|
||||
let c = current;
|
||||
list.push(current);
|
||||
current = $.derived(() => {
|
||||
return $.get(c) + 1;
|
||||
});
|
||||
}
|
||||
let sum = $.derived(() => {
|
||||
return list.map((x) => $.get(x)).reduce((a, b) => a + b, 0);
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(sum);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
const constant = count(width);
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(sum), constant);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
assert.equal($.get(sum), constant - width + i * width);
|
||||
}
|
||||
assert.equal(counter, 100);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,41 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
export default () => {
|
||||
let head = $.state(0);
|
||||
const double = $.derived(() => $.get(head) * 2);
|
||||
const inverse = $.derived(() => -$.get(head));
|
||||
let current = $.derived(() => {
|
||||
let result = 0;
|
||||
for (let i = 0; i < 20; i++) {
|
||||
result += $.get(head) % 2 ? $.get(double) : $.get(inverse);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(current);
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
$.flush(() => {
|
||||
$.set(head, 1);
|
||||
});
|
||||
assert.equal($.get(current), 40);
|
||||
counter = 0;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
$.flush(() => {
|
||||
$.set(head, i);
|
||||
});
|
||||
}
|
||||
assert.equal(counter, 100);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,35 @@
|
||||
import assert from 'node:assert';
|
||||
import * as $ from 'svelte/internal/client';
|
||||
|
||||
const ARRAY_SIZE = 1000;
|
||||
|
||||
export default () => {
|
||||
const signals = Array.from({ length: ARRAY_SIZE }, (_, i) => $.state(i));
|
||||
const order = $.state(0);
|
||||
|
||||
// break skipped_deps fast path by changing order of reads
|
||||
const total = $.derived(() => {
|
||||
const ord = $.get(order);
|
||||
let sum = 0;
|
||||
for (let i = 0; i < ARRAY_SIZE; i++) {
|
||||
sum += /** @type {number} */ ($.get(signals[(i + ord) % ARRAY_SIZE]));
|
||||
}
|
||||
return sum;
|
||||
});
|
||||
|
||||
const destroy = $.effect_root(() => {
|
||||
$.render_effect(() => {
|
||||
$.get(total);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
destroy,
|
||||
run() {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
$.flush(() => $.set(order, i));
|
||||
assert.equal($.get(total), (ARRAY_SIZE * (ARRAY_SIZE - 1)) / 2); // sum of 0..999
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,71 @@
|
||||
import * as $ from 'svelte/internal/client';
|
||||
import { fastest_test } from '../../utils.js';
|
||||
|
||||
export function busy() {
|
||||
let a = 0;
|
||||
for (let i = 0; i < 1_00; i++) {
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} label
|
||||
* @param {() => { run: (i?: number) => void, destroy: () => void }} setup
|
||||
*/
|
||||
export function create_test(label, setup) {
|
||||
return {
|
||||
unowned: {
|
||||
label: `${label}_unowned`,
|
||||
fn: async () => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run(0);
|
||||
destroy();
|
||||
}
|
||||
|
||||
const { run, destroy } = setup();
|
||||
|
||||
const result = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run(i);
|
||||
}
|
||||
});
|
||||
|
||||
destroy();
|
||||
|
||||
return result;
|
||||
}
|
||||
},
|
||||
owned: {
|
||||
label: `${label}_owned`,
|
||||
fn: async () => {
|
||||
let run, destroy;
|
||||
|
||||
const destroy_owned = $.effect_root(() => {
|
||||
// Do 10 loops to warm up JIT
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const { run, destroy } = setup();
|
||||
run(0);
|
||||
destroy();
|
||||
}
|
||||
|
||||
({ run, destroy } = setup());
|
||||
});
|
||||
|
||||
const result = await fastest_test(10, () => {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
run(i);
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
destroy();
|
||||
destroy_owned();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1,10 +1,13 @@
|
||||
import { reactivity_benchmarks } from '../benchmarks/reactivity/index.js';
|
||||
|
||||
const results = [];
|
||||
for (const benchmark of reactivity_benchmarks) {
|
||||
const result = await benchmark();
|
||||
console.error(result.benchmark);
|
||||
results.push(result);
|
||||
|
||||
for (let i = 0; i < reactivity_benchmarks.length; i += 1) {
|
||||
const benchmark = reactivity_benchmarks[i];
|
||||
|
||||
process.stderr.write(`Running ${i + 1}/${reactivity_benchmarks.length} ${benchmark.label} `);
|
||||
results.push({ benchmark: benchmark.label, ...(await benchmark.fn()) });
|
||||
process.stderr.write('\x1b[2K\r');
|
||||
}
|
||||
|
||||
process.send(results);
|
||||
|
||||
@ -0,0 +1,123 @@
|
||||
---
|
||||
title: Hydratable data
|
||||
---
|
||||
|
||||
In Svelte, when you want to render asynchronous content data on the server, you can simply `await` it. This is great! However, it comes with a pitfall: when hydrating that content on the client, Svelte has to redo the asynchronous work, which blocks hydration for however long it takes:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { getUser } from 'my-database-library';
|
||||
|
||||
// This will get the user on the server, render the user's name into the h1,
|
||||
// and then, during hydration on the client, it will get the user _again_,
|
||||
// blocking hydration until it's done.
|
||||
const user = await getUser();
|
||||
</script>
|
||||
|
||||
<h1>{user.name}</h1>
|
||||
```
|
||||
|
||||
That's silly, though. If we've already done the hard work of getting the data on the server, we don't want to get it again during hydration on the client. `hydratable` is a low-level API built to solve this problem. You probably won't need this very often — it will be used behind the scenes by whatever datafetching library you use. For example, it powers [remote functions in SvelteKit](/docs/kit/remote-functions).
|
||||
|
||||
To fix the example above:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { hydratable } from 'svelte';
|
||||
import { getUser } from 'my-database-library';
|
||||
|
||||
// During server rendering, this will serialize and stash the result of `getUser`, associating
|
||||
// it with the provided key and baking it into the `head` content. During hydration, it will
|
||||
// look for the serialized version, returning it instead of running `getUser`. After hydration
|
||||
// is done, if it's called again, it'll simply invoke `getUser`.
|
||||
const user = await hydratable('user', () => getUser());
|
||||
</script>
|
||||
|
||||
<h1>{user.name}</h1>
|
||||
```
|
||||
|
||||
This API can also be used to provide access to random or time-based values that are stable between server rendering and hydration. For example, to get a random number that doesn't update on hydration:
|
||||
|
||||
```ts
|
||||
import { hydratable } from 'svelte';
|
||||
const rand = hydratable('random', () => Math.random());
|
||||
```
|
||||
|
||||
If you're a library author, be sure to prefix the keys of your `hydratable` values with the name of your library so that your keys don't conflict with other libraries.
|
||||
|
||||
## Serialization
|
||||
|
||||
All data returned from a `hydratable` function must be serializable. But this doesn't mean you're limited to JSON — Svelte uses [`devalue`](https://npmjs.com/package/devalue), which can serialize all sorts of things including `Map`, `Set`, `URL`, and `BigInt`. Check the documentation page for a full list. In addition to these, thanks to some Svelte magic, you can also fearlessly use promises:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { hydratable } from 'svelte';
|
||||
const promises = hydratable('random', () => {
|
||||
return {
|
||||
one: Promise.resolve(1),
|
||||
two: Promise.resolve(2)
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{await promises.one}
|
||||
{await promises.two}
|
||||
```
|
||||
|
||||
## CSP
|
||||
|
||||
`hydratable` adds an inline `<script>` block to the `head` returned from `render`. If you're using [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP) (CSP), this script will likely fail to run. You can provide a `nonce` to `render`:
|
||||
|
||||
```js
|
||||
/// file: server.js
|
||||
import { render } from 'svelte/server';
|
||||
import App from './App.svelte';
|
||||
// ---cut---
|
||||
const nonce = crypto.randomUUID();
|
||||
|
||||
const { head, body } = await render(App, {
|
||||
csp: { nonce }
|
||||
});
|
||||
```
|
||||
|
||||
This will add the `nonce` to the script block, on the assumption that you will later add the same nonce to the CSP header of the document that contains it:
|
||||
|
||||
```js
|
||||
/// file: server.js
|
||||
let response = new Response();
|
||||
let nonce = 'xyz123';
|
||||
// ---cut---
|
||||
response.headers.set(
|
||||
'Content-Security-Policy',
|
||||
`script-src 'nonce-${nonce}'`
|
||||
);
|
||||
```
|
||||
|
||||
It's essential that a `nonce` — which, British slang definition aside, means 'number used once' — is only used when dynamically server rendering an individual response.
|
||||
|
||||
If instead you are generating static HTML ahead of time, you must use hashes instead:
|
||||
|
||||
```js
|
||||
/// file: server.js
|
||||
import { render } from 'svelte/server';
|
||||
import App from './App.svelte';
|
||||
// ---cut---
|
||||
const { head, body, hashes } = await render(App, {
|
||||
csp: { hash: true }
|
||||
});
|
||||
```
|
||||
|
||||
`hashes.script` will be an array of strings like `["sha256-abcd123"]`. As with `nonce`, the hashes should be used in your CSP header:
|
||||
|
||||
```js
|
||||
/// file: server.js
|
||||
let response = new Response();
|
||||
let hashes = { script: ['sha256-xyz123'] };
|
||||
// ---cut---
|
||||
response.headers.set(
|
||||
'Content-Security-Policy',
|
||||
`script-src ${hashes.script.map((hash) => `'${hash}'`).join(' ')}`
|
||||
);
|
||||
```
|
||||
|
||||
We recommend using `nonce` over hash if you can, as `hash` will interfere with streaming SSR in the future.
|
||||
@ -0,0 +1,34 @@
|
||||
<!-- This file is generated by scripts/process-messages/index.js. Do not edit! -->
|
||||
|
||||
### unresolved_hydratable
|
||||
|
||||
```
|
||||
A `hydratable` value with key `%key%` was created, but at least part of it was not used during the render.
|
||||
|
||||
The `hydratable` was initialized in:
|
||||
%stack%
|
||||
```
|
||||
|
||||
The most likely cause of this is creating a `hydratable` in the `script` block of your component and then `await`ing
|
||||
the result inside a `svelte:boundary` with a `pending` snippet:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { hydratable } from 'svelte';
|
||||
import { getUser } from '$lib/get-user.js';
|
||||
|
||||
const user = hydratable('user', getUser);
|
||||
</script>
|
||||
|
||||
<svelte:boundary>
|
||||
<h1>{(await user).name}</h1>
|
||||
|
||||
{#snippet pending()}
|
||||
<div>Loading...</div>
|
||||
{/snippet}
|
||||
</svelte:boundary>
|
||||
```
|
||||
|
||||
Consider inlining the `hydratable` call inside the boundary so that it's not called on the server.
|
||||
|
||||
Note that this can also happen when a `hydratable` contains multiple promises and some but not all of them have been used.
|
||||
@ -0,0 +1,60 @@
|
||||
## async_local_storage_unavailable
|
||||
|
||||
> The node API `AsyncLocalStorage` is not available, but is required to use async server rendering.
|
||||
|
||||
Some platforms require configuration flags to enable this API. Consult your platform's documentation.
|
||||
|
||||
## await_invalid
|
||||
|
||||
> Encountered asynchronous work while rendering synchronously.
|
||||
|
||||
You (or the framework you're using) called [`render(...)`](svelte-server#render) with a component containing an `await` expression. Either `await` the result of `render` or wrap the `await` (or the component containing it) in a [`<svelte:boundary>`](svelte-boundary) with a `pending` snippet.
|
||||
|
||||
## html_deprecated
|
||||
|
||||
> The `html` property of server render results has been deprecated. Use `body` instead.
|
||||
|
||||
## hydratable_clobbering
|
||||
|
||||
> Attempted to set `hydratable` with key `%key%` twice with different values.
|
||||
>
|
||||
> %stack%
|
||||
|
||||
This error occurs when using `hydratable` multiple times with the same key. To avoid this, you can:
|
||||
- Ensure all invocations with the same key result in the same value
|
||||
- Update the keys to make both instances unique
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { hydratable } from 'svelte';
|
||||
|
||||
// which one should "win" and be serialized in the rendered response?
|
||||
const one = hydratable('not-unique', () => 1);
|
||||
const two = hydratable('not-unique', () => 2);
|
||||
</script>
|
||||
```
|
||||
|
||||
## hydratable_serialization_failed
|
||||
|
||||
> Failed to serialize `hydratable` data for key `%key%`.
|
||||
>
|
||||
> `hydratable` can serialize anything [`uneval` from `devalue`](https://npmjs.com/package/uneval) can, plus Promises.
|
||||
>
|
||||
> Cause:
|
||||
> %stack%
|
||||
|
||||
## invalid_csp
|
||||
|
||||
> `csp.nonce` was set while `csp.hash` was `true`. These options cannot be used simultaneously.
|
||||
|
||||
## lifecycle_function_unavailable
|
||||
|
||||
> `%name%(...)` is not available on the server
|
||||
|
||||
Certain methods such as `mount` cannot be invoked while running in a server context. Avoid calling them eagerly, i.e. not during render.
|
||||
|
||||
## server_context_required
|
||||
|
||||
> Could not resolve `render` context.
|
||||
|
||||
Certain functions such as `hydratable` cannot be invoked outside of a `render(...)` call, such as at the top level of a module.
|
||||
@ -1,5 +0,0 @@
|
||||
## lifecycle_function_unavailable
|
||||
|
||||
> `%name%(...)` is not available on the server
|
||||
|
||||
Certain methods such as `mount` cannot be invoked while running in a server context. Avoid calling them eagerly, i.e. not during render.
|
||||
@ -0,0 +1,30 @@
|
||||
## unresolved_hydratable
|
||||
|
||||
> A `hydratable` value with key `%key%` was created, but at least part of it was not used during the render.
|
||||
>
|
||||
> The `hydratable` was initialized in:
|
||||
> %stack%
|
||||
|
||||
The most likely cause of this is creating a `hydratable` in the `script` block of your component and then `await`ing
|
||||
the result inside a `svelte:boundary` with a `pending` snippet:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { hydratable } from 'svelte';
|
||||
import { getUser } from '$lib/get-user.js';
|
||||
|
||||
const user = hydratable('user', getUser);
|
||||
</script>
|
||||
|
||||
<svelte:boundary>
|
||||
<h1>{(await user).name}</h1>
|
||||
|
||||
{#snippet pending()}
|
||||
<div>Loading...</div>
|
||||
{/snippet}
|
||||
</svelte:boundary>
|
||||
```
|
||||
|
||||
Consider inlining the `hydratable` call inside the boundary so that it's not called on the server.
|
||||
|
||||
Note that this can also happen when a `hydratable` contains multiple promises and some but not all of them have been used.
|
||||
@ -0,0 +1,20 @@
|
||||
import { DEV } from 'esm-env';
|
||||
|
||||
var bold = 'font-weight: bold';
|
||||
var normal = 'font-weight: normal';
|
||||
|
||||
/**
|
||||
* MESSAGE
|
||||
* @param {string} PARAMETER
|
||||
*/
|
||||
export function CODE(PARAMETER) {
|
||||
if (DEV) {
|
||||
console.warn(
|
||||
`%c[svelte] ${'CODE'}\n%c${MESSAGE}\nhttps://svelte.dev/e/${'CODE'}`,
|
||||
bold,
|
||||
normal
|
||||
);
|
||||
} else {
|
||||
console.warn(`https://svelte.dev/e/${'CODE'}`);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
/** @import { Context } from '../types' */
|
||||
/** @import { AST } from '#compiler'; */
|
||||
import * as e from '../../../errors.js';
|
||||
|
||||
/**
|
||||
* @param {AST.AnimateDirective} node
|
||||
* @param {Context} context
|
||||
*/
|
||||
export function AnimateDirective(node, context) {
|
||||
context.next({ ...context.state, expression: node.metadata.expression });
|
||||
|
||||
if (node.metadata.expression.has_await) {
|
||||
e.illegal_await_expression(node);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue