Merge branch 'main' into better-deferred-heuristic

pull/11810/head
Dominic Gannaway 2 years ago
commit 50fb8c76e7

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: `$state.is` missing second argument on the server

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: prevent buggy ownership warning when reassigning state

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: address regressed memory leak

@ -203,7 +203,7 @@ export function serialize_set_binding(node, context, fallback, options) {
assignment.right =
private_state.kind === 'frozen_state'
? b.call('$.freeze', value)
: b.call('$.proxy', value);
: serialize_proxy_reassignment(value, private_state.id, state);
return assignment;
}
}
@ -216,7 +216,7 @@ export function serialize_set_binding(node, context, fallback, options) {
should_proxy_or_freeze(value, context.state.scope)
? private_state.kind === 'frozen_state'
? b.call('$.freeze', value)
: b.call('$.proxy', value)
: serialize_proxy_reassignment(value, private_state.id, state)
: value
);
}
@ -240,7 +240,7 @@ export function serialize_set_binding(node, context, fallback, options) {
assignment.right =
public_state.kind === 'frozen_state'
? b.call('$.freeze', value)
: b.call('$.proxy', value);
: serialize_proxy_reassignment(value, public_state.id, state);
return assignment;
}
}
@ -305,7 +305,7 @@ export function serialize_set_binding(node, context, fallback, options) {
context.state.analysis.runes &&
!options?.skip_proxy_and_freeze &&
should_proxy_or_freeze(value, context.state.scope)
? b.call('$.proxy', value)
? serialize_proxy_reassignment(value, left_name, state)
: value
);
} else if (binding.kind === 'frozen_state') {
@ -410,6 +410,25 @@ export function serialize_set_binding(node, context, fallback, options) {
return serialize();
}
/**
* @param {import('estree').Expression} value
* @param {import('estree').PrivateIdentifier | string} proxy_reference
* @param {import('./types').ClientTransformState} state
*/
export function serialize_proxy_reassignment(value, proxy_reference, state) {
return state.options.dev
? b.call(
'$.proxy',
value,
b.true,
b.null,
typeof proxy_reference === 'string'
? b.id(proxy_reference)
: b.member(b.this, proxy_reference)
)
: b.call('$.proxy', value);
}
/**
* @param {import('estree').ArrowFunctionExpression | import('estree').FunctionExpression} node
* @param {import('./types').ComponentContext} context

@ -2,7 +2,12 @@ import { get_rune } from '../../../scope.js';
import { is_hoistable_function, transform_inspect_rune } from '../../utils.js';
import * as b from '../../../../utils/builders.js';
import * as assert from '../../../../utils/assert.js';
import { get_prop_source, is_state_source, should_proxy_or_freeze } from '../utils.js';
import {
get_prop_source,
is_state_source,
serialize_proxy_reassignment,
should_proxy_or_freeze
} from '../utils.js';
import { extract_paths } from '../../../../utils/ast.js';
import { regex_invalid_identifier_chars } from '../../../patterns.js';
@ -139,7 +144,11 @@ export const javascript_visitors_runes = {
'set',
definition.key,
[value],
[b.stmt(b.call('$.set', member, b.call('$.proxy', value)))]
[
b.stmt(
b.call('$.set', member, serialize_proxy_reassignment(value, field.id, state))
)
]
)
);
}

@ -791,7 +791,8 @@ const javascript_visitors_runes = {
if (rune === '$state.is') {
return b.call(
'Object.is',
/** @type {import('estree').Expression} */ (context.visit(node.arguments[0]))
/** @type {import('estree').Expression} */ (context.visit(node.arguments[0])),
/** @type {import('estree').Expression} */ (context.visit(node.arguments[1]))
);
}

@ -469,6 +469,7 @@ export function do_while(test, body) {
const true_instance = literal(true);
const false_instance = literal(false);
const null_instane = literal(null);
/** @type {import('estree').DebuggerStatement} */
const debugger_builder = {
@ -630,6 +631,7 @@ export {
return_builder as return,
if_builder as if,
this_instance as this,
null_instane as null,
debugger_builder as debugger
};

@ -4,6 +4,7 @@ import { current_effect, get } from '../../runtime.js';
import { is_array } from '../../utils.js';
import { hydrate_nodes, hydrating } from '../hydration.js';
import { create_fragment_from_html, remove } from '../reconciler.js';
import { push_template_node } from '../template.js';
/**
* @param {import('#client').Effect} effect
@ -37,7 +38,7 @@ export function html(anchor, get_value, svg, mathml) {
let value = derived(get_value);
render_effect(() => {
var dom = html_to_dom(anchor, get(value), svg, mathml);
var dom = html_to_dom(anchor, parent_effect, get(value), svg, mathml);
if (dom) {
return () => {
@ -55,12 +56,13 @@ export function html(anchor, get_value, svg, mathml) {
* inserts it before the target anchor and returns the new nodes.
* @template V
* @param {Element | Text | Comment} target
* @param {import('#client').Effect | null} effect
* @param {V} value
* @param {boolean} svg
* @param {boolean} mathml
* @returns {Element | Comment | (Element | Comment | Text)[]}
*/
function html_to_dom(target, value, svg, mathml) {
function html_to_dom(target, effect, value, svg, mathml) {
if (hydrating) return hydrate_nodes;
var html = value + '';
@ -79,6 +81,9 @@ function html_to_dom(target, value, svg, mathml) {
if (node.childNodes.length === 1) {
var child = /** @type {Text | Element | Comment} */ (node.firstChild);
target.before(child);
if (effect !== null) {
push_template_node(child, effect);
}
return child;
}
@ -92,5 +97,9 @@ function html_to_dom(target, value, svg, mathml) {
target.before(node);
}
if (effect !== null) {
push_template_node(nodes, effect);
}
return nodes;
}

@ -10,8 +10,31 @@ import {
} from '../../reactivity/effects.js';
import { set_should_intro } from '../../render.js';
import { current_each_item, set_current_each_item } from './each.js';
import { current_component_context } from '../../runtime.js';
import { current_component_context, current_effect } from '../../runtime.js';
import { DEV } from 'esm-env';
import { is_array } from '../../utils.js';
import { push_template_node } from '../template.js';
/**
* @param {import('#client').Effect} effect
* @param {Element} from
* @param {Element} to
* @returns {void}
*/
function swap_block_dom(effect, from, to) {
const dom = effect.dom;
if (is_array(dom)) {
for (let i = 0; i < dom.length; i++) {
if (dom[i] === from) {
dom[i] = to;
break;
}
}
} else if (dom === from) {
effect.dom = to;
}
}
/**
* @param {Comment} anchor
@ -23,6 +46,7 @@ import { DEV } from 'esm-env';
* @returns {void}
*/
export function element(anchor, get_tag, is_svg, render_fn, get_namespace, location) {
const parent_effect = /** @type {import('#client').Effect} */ (current_effect);
const filename = DEV && location && current_component_context?.function.filename;
/** @type {string | null} */
@ -78,6 +102,7 @@ export function element(anchor, get_tag, is_svg, render_fn, get_namespace, locat
if (next_tag && next_tag !== current_tag) {
effect = branch(() => {
const prev_element = element;
element = hydrating
? /** @type {Element} */ (hydrate_start)
: ns
@ -111,9 +136,12 @@ export function element(anchor, get_tag, is_svg, render_fn, get_namespace, locat
anchor.before(element);
return () => {
element?.remove();
};
if (prev_element) {
swap_block_dom(parent_effect, prev_element, element);
prev_element.remove();
} else if (!hydrating) {
push_template_node(element, parent_effect);
}
});
}

@ -4,17 +4,32 @@ import { create_fragment_from_html } from './reconciler.js';
import { current_effect } from '../runtime.js';
import { TEMPLATE_FRAGMENT, TEMPLATE_USE_IMPORT_NODE } from '../../../constants.js';
import { effect } from '../reactivity/effects.js';
import { is_array } from '../utils.js';
/**
* @template {import("#client").TemplateNode | import("#client").TemplateNode[]} T
* @param {T} dom
* @param {import("#client").Effect} effect
*/
function push_template_node(dom) {
var effect = /** @type {import('#client').Effect} */ (current_effect);
if (effect.dom === null) {
export function push_template_node(
dom,
effect = /** @type {import('#client').Effect} */ (current_effect)
) {
var current_dom = effect.dom;
if (current_dom === null) {
effect.dom = dom;
} else {
if (!is_array(current_dom)) {
current_dom = effect.dom = [current_dom];
}
if (is_array(dom)) {
current_dom.push(...dom);
} else {
current_dom.push(dom);
}
}
return dom;
}
/**
@ -41,7 +56,15 @@ export function template(content, flags) {
if (!is_fragment) node = /** @type {Node} */ (node.firstChild);
}
return use_import_node ? document.importNode(node, true) : node.cloneNode(true);
var clone = use_import_node ? document.importNode(node, true) : node.cloneNode(true);
push_template_node(
is_fragment
? /** @type {import('#client').TemplateNode[]} */ ([...clone.childNodes])
: /** @type {import('#client').TemplateNode} */ (clone)
);
return clone;
};
}
@ -102,7 +125,15 @@ export function ns_template(content, flags, ns = 'svg') {
}
}
return node.cloneNode(true);
var clone = node.cloneNode(true);
push_template_node(
is_fragment
? /** @type {import('#client').TemplateNode[]} */ ([...clone.childNodes])
: /** @type {import('#client').TemplateNode} */ (clone)
);
return clone;
};
}
@ -177,7 +208,7 @@ function run_scripts(node) {
*/
/*#__NO_SIDE_EFFECTS__*/
export function text(anchor) {
if (!hydrating) return empty();
if (!hydrating) return push_template_node(empty());
var node = hydrate_start;
@ -201,6 +232,7 @@ export function comment() {
var frag = document.createDocumentFragment();
var anchor = empty();
frag.append(anchor);
push_template_node([anchor]);
return frag;
}
@ -213,13 +245,9 @@ export function comment() {
*/
export function append(anchor, dom) {
if (hydrating) return;
var effect = /** @type {import('#client').Effect} */ (current_effect);
effect.dom =
dom.nodeType === 11
? /** @type {import('#client').TemplateNode[]} */ ([...dom.childNodes])
: /** @type {Element | Comment} */ (dom);
// We intentionally do not assign the `dom` property of the effect here because it's far too
// late. If we try, we will capture additional DOM elements that we cannot control the lifecycle
// for and will inevitably cause memory leaks. See https://github.com/sveltejs/svelte/pull/11832
anchor.before(/** @type {Node} */ (dom));
}

@ -27,9 +27,10 @@ import * as e from './errors.js';
* @param {T} value
* @param {boolean} [immutable]
* @param {import('#client').ProxyMetadata | null} [parent]
* @param {import('#client').Source<T>} [prev] dev mode only
* @returns {import('#client').ProxyStateObject<T> | T}
*/
export function proxy(value, immutable = true, parent = null) {
export function proxy(value, immutable = true, parent = null, prev) {
if (typeof value === 'object' && value != null && !is_frozen(value)) {
// If we have an existing proxy, return it...
if (STATE_SYMBOL in value) {
@ -71,13 +72,22 @@ export function proxy(value, immutable = true, parent = null) {
// @ts-expect-error
value[STATE_SYMBOL].parent = parent;
// @ts-expect-error
value[STATE_SYMBOL].owners =
parent === null
? current_component_context !== null
? new Set([current_component_context.function])
: null
: new Set();
if (prev) {
// Reuse owners from previous state; necessary because reassignment is not guaranteed to have correct component context.
// If no previous proxy exists we play it safe and assume ownerless state
// @ts-expect-error
const prev_owners = prev?.v?.[STATE_SYMBOL]?.owners;
// @ts-expect-error
value[STATE_SYMBOL].owners = prev_owners ? new Set(prev_owners) : null;
} else {
// @ts-expect-error
value[STATE_SYMBOL].owners =
parent === null
? current_component_context !== null
? new Set([current_component_context.function])
: null
: new Set();
}
}
return proxy;

@ -1,8 +1,8 @@
<script>
/** @type {{ object: { count: number }}} */
let { object = $bindable() } = $props();
let { object = $bindable(), reset } = $props();
</script>
<button onclick={() => object.count += 1}>
clicks: {object.count}
</button>
<button onclick={reset}>reset</button>

@ -1,36 +1,30 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
/** @type {typeof console.trace} */
let trace;
export default test({
html: `<button>clicks: 0</button>`,
html: `<button>clicks: 0</button> <button>reset</button>`,
compileOptions: {
dev: true
},
before_test: () => {
trace = console.trace;
console.trace = () => {};
},
after_test: () => {
console.trace = trace;
},
test({ assert, target, warnings }) {
const btn = target.querySelector('button');
flushSync(() => {
btn?.click();
});
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button>`);
assert.deepEqual(warnings, [
'Counter.svelte mutated a value owned by main.svelte. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead'
]);
const warning =
'Counter.svelte mutated a value owned by main.svelte. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead';
const [btn1, btn2] = target.querySelectorAll('button');
btn1.click();
flushSync();
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button> <button>reset</button>`);
assert.deepEqual(warnings, [warning]);
btn2.click();
flushSync();
assert.htmlEqual(target.innerHTML, `<button>clicks: 0</button> <button>reset</button>`);
btn1.click();
flushSync();
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button> <button>reset</button>`);
assert.deepEqual(warnings, [warning, warning]);
}
});

@ -1,7 +1,7 @@
<script>
import Counter from './Counter.svelte';
const object = $state({ count: 0 });
let object = $state({ count: 0 });
</script>
<Counter {object} />
<Counter {object} reset={() => object = {count: 0}} />

@ -0,0 +1,11 @@
import { test } from '../../test';
export default test({
compileOptions: {
dev: true
},
async test({ assert, warnings }) {
assert.deepEqual(warnings, []);
}
});

@ -0,0 +1,18 @@
<script context="module">
let toast1 = $state();
let toast2 = $state({});
export async function show_toast() {
toast1 = {
message: 'foo',
show: true
};
toast1.show = false;
toast2 = {
message: 'foo',
show: true
};
toast2.show = false;
}
</script>

@ -0,0 +1,5 @@
<script>
import { show_toast } from "./child.svelte";
show_toast();
</script>

@ -0,0 +1,4 @@
<p>true</p>
<p>true</p>
<p>true</p>
<p>true</p>

@ -0,0 +1,10 @@
<script>
const obj = {};
const a = $state(obj)
const b= $state(obj)
</script>
<p>{a === obj}</p>
<p>{$state.is(a, obj)}</p>
<p>{a === b}</p>
<p>{$state.is(a, b)}</p>

@ -16,7 +16,7 @@ importers:
version: 2.27.1
'@sveltejs/eslint-config':
specifier: ^7.0.1
version: 7.0.1(@stylistic/eslint-plugin-js@1.8.0(eslint@9.0.0))(eslint-config-prettier@9.1.0(eslint@9.0.0))(eslint-plugin-svelte@2.38.0(eslint@9.0.0)(svelte@5.0.0-next.141))(eslint-plugin-unicorn@52.0.0(eslint@9.0.0))(eslint@9.0.0)(typescript-eslint@7.6.0(eslint@9.0.0)(typescript@5.3.3))(typescript@5.3.3)
version: 7.0.1(@stylistic/eslint-plugin-js@1.8.0(eslint@9.0.0))(eslint-config-prettier@9.1.0(eslint@9.0.0))(eslint-plugin-svelte@2.38.0(eslint@9.0.0)(svelte@5.0.0-next.143))(eslint-plugin-unicorn@52.0.0(eslint@9.0.0))(eslint@9.0.0)(typescript-eslint@7.6.0(eslint@9.0.0)(typescript@5.3.3))(typescript@5.3.3)
'@svitejs/changesets-changelog-github-compact':
specifier: ^1.1.0
version: 1.1.0
@ -49,7 +49,7 @@ importers:
version: 3.2.4
prettier-plugin-svelte:
specifier: ^3.1.2
version: 3.1.2(prettier@3.2.4)(svelte@5.0.0-next.141)
version: 3.1.2(prettier@3.2.4)(svelte@5.0.0-next.143)
typescript:
specifier: ^5.3.3
version: 5.3.3
@ -274,6 +274,9 @@ importers:
'@types/marked':
specifier: ^6.0.0
version: 6.0.0
'@vercel/speed-insights':
specifier: ^1.0.0
version: 1.0.11(@sveltejs/kit@2.5.2(@sveltejs/vite-plugin-svelte@3.1.0(svelte@packages+svelte)(vite@5.0.13(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@5.0.13(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)
esrap:
specifier: ^1.2.2
version: 1.2.2
@ -1736,6 +1739,29 @@ packages:
engines: {node: '>=16'}
hasBin: true
'@vercel/speed-insights@1.0.11':
resolution: {integrity: sha512-l9hzSNmJvb2Yqpgd/BzpiT0J0aQDdtqxOf3Xm+iW4PICxVvhY1ef7Otdx4GXI+88dVkws57qMzXiShz19gXzSQ==}
peerDependencies:
'@sveltejs/kit': ^1 || ^2
next: '>= 13'
react: ^18 || ^19
svelte: ^4
vue: ^3
vue-router: ^4
peerDependenciesMeta:
'@sveltejs/kit':
optional: true
next:
optional: true
react:
optional: true
svelte:
optional: true
vue:
optional: true
vue-router:
optional: true
'@vitest/coverage-v8@1.2.1':
resolution: {integrity: sha512-fJEhKaDwGMZtJUX7BRcGxooGwg1Hl0qt53mVup/ZJeznhvL5EodteVnb/mcByhEcvVWbK83ZF31c7nPEDi4LOQ==}
peerDependencies:
@ -4553,8 +4579,8 @@ packages:
resolution: {integrity: sha512-hsoB/WZGEPFXeRRLPhPrbRz67PhP6sqYgvwcAs+gWdSQSvNDw+/lTeUJSWe5h2xC97Fz/8QxAOqItwBzNJPU8w==}
engines: {node: '>=16'}
svelte@5.0.0-next.141:
resolution: {integrity: sha512-zT74TUo0vOOrbxRfdlWXu+ac4O9lqPFG0YoZB3uOfrOewT1GKxKm0qwG/jo9bGvgZ++TSHjR7AtV091LY2FhBA==}
svelte@5.0.0-next.143:
resolution: {integrity: sha512-hRm52FjYUfd24eUlkBS41JSmqHOx6wt0cV+wMzgwqhhxIpJoz96eiMcnvcLqXx+gTxM1m0Pt/+7xP3vlm2QvPg==}
engines: {node: '>=18'}
symbol-tree@3.2.4:
@ -6432,12 +6458,12 @@ snapshots:
- encoding
- supports-color
'@sveltejs/eslint-config@7.0.1(@stylistic/eslint-plugin-js@1.8.0(eslint@9.0.0))(eslint-config-prettier@9.1.0(eslint@9.0.0))(eslint-plugin-svelte@2.38.0(eslint@9.0.0)(svelte@5.0.0-next.141))(eslint-plugin-unicorn@52.0.0(eslint@9.0.0))(eslint@9.0.0)(typescript-eslint@7.6.0(eslint@9.0.0)(typescript@5.3.3))(typescript@5.3.3)':
'@sveltejs/eslint-config@7.0.1(@stylistic/eslint-plugin-js@1.8.0(eslint@9.0.0))(eslint-config-prettier@9.1.0(eslint@9.0.0))(eslint-plugin-svelte@2.38.0(eslint@9.0.0)(svelte@5.0.0-next.143))(eslint-plugin-unicorn@52.0.0(eslint@9.0.0))(eslint@9.0.0)(typescript-eslint@7.6.0(eslint@9.0.0)(typescript@5.3.3))(typescript@5.3.3)':
dependencies:
'@stylistic/eslint-plugin-js': 1.8.0(eslint@9.0.0)
eslint: 9.0.0
eslint-config-prettier: 9.1.0(eslint@9.0.0)
eslint-plugin-svelte: 2.38.0(eslint@9.0.0)(svelte@5.0.0-next.141)
eslint-plugin-svelte: 2.38.0(eslint@9.0.0)(svelte@5.0.0-next.143)
eslint-plugin-unicorn: 52.0.0(eslint@9.0.0)
globals: 15.0.0
typescript: 5.3.3
@ -6768,6 +6794,11 @@ snapshots:
- encoding
- supports-color
'@vercel/speed-insights@1.0.11(@sveltejs/kit@2.5.2(@sveltejs/vite-plugin-svelte@3.1.0(svelte@packages+svelte)(vite@5.0.13(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@5.0.13(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)':
optionalDependencies:
'@sveltejs/kit': 2.5.2(@sveltejs/vite-plugin-svelte@3.1.0(svelte@packages+svelte)(vite@5.0.13(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0)))(svelte@packages+svelte)(vite@5.0.13(@types/node@20.12.7)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))
svelte: link:packages/svelte
'@vitest/coverage-v8@1.2.1(vitest@1.2.1(@types/node@20.11.5)(jsdom@22.0.0)(lightningcss@1.23.0)(sass@1.70.0)(terser@5.27.0))':
dependencies:
'@ampproject/remapping': 2.2.1
@ -7551,7 +7582,7 @@ snapshots:
eslint-plugin-lube@0.4.3: {}
eslint-plugin-svelte@2.38.0(eslint@9.0.0)(svelte@5.0.0-next.141):
eslint-plugin-svelte@2.38.0(eslint@9.0.0)(svelte@5.0.0-next.143):
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0)
'@jridgewell/sourcemap-codec': 1.4.15
@ -7565,9 +7596,9 @@ snapshots:
postcss-safe-parser: 6.0.0(postcss@8.4.38)
postcss-selector-parser: 6.0.16
semver: 7.6.0
svelte-eslint-parser: 0.35.0(svelte@5.0.0-next.141)
svelte-eslint-parser: 0.35.0(svelte@5.0.0-next.143)
optionalDependencies:
svelte: 5.0.0-next.141
svelte: 5.0.0-next.143
transitivePeerDependencies:
- supports-color
- ts-node
@ -9075,10 +9106,10 @@ snapshots:
prettier: 3.2.4
svelte: 4.2.9
prettier-plugin-svelte@3.1.2(prettier@3.2.4)(svelte@5.0.0-next.141):
prettier-plugin-svelte@3.1.2(prettier@3.2.4)(svelte@5.0.0-next.143):
dependencies:
prettier: 3.2.4
svelte: 5.0.0-next.141
svelte: 5.0.0-next.143
prettier@2.8.8: {}
@ -9707,7 +9738,7 @@ snapshots:
- stylus
- sugarss
svelte-eslint-parser@0.35.0(svelte@5.0.0-next.141):
svelte-eslint-parser@0.35.0(svelte@5.0.0-next.143):
dependencies:
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
@ -9715,7 +9746,7 @@ snapshots:
postcss: 8.4.38
postcss-scss: 4.0.9(postcss@8.4.38)
optionalDependencies:
svelte: 5.0.0-next.141
svelte: 5.0.0-next.143
svelte-hmr@0.16.0(svelte@4.2.9):
dependencies:
@ -9790,7 +9821,7 @@ snapshots:
magic-string: 0.30.5
periscopic: 3.1.0
svelte@5.0.0-next.141:
svelte@5.0.0-next.143:
dependencies:
'@ampproject/remapping': 2.2.1
'@jridgewell/sourcemap-codec': 1.4.15

@ -20,6 +20,7 @@
"@sveltejs/site-kit": "6.0.0-next.64",
"@sveltejs/vite-plugin-svelte": "^3.1.0",
"@types/marked": "^6.0.0",
"@vercel/speed-insights": "^1.0.0",
"esrap": "^1.2.2",
"marked": "^9.0.0",
"publint": "^0.2.7",

@ -1,9 +1,12 @@
<script>
import { injectSpeedInsights } from '@vercel/speed-insights/sveltekit';
import { page } from '$app/stores';
import { Icon, Shell } from '@sveltejs/site-kit/components';
import { Nav, Separator } from '@sveltejs/site-kit/nav';
import '@sveltejs/site-kit/styles/index.css';
injectSpeedInsights();
export let data;
</script>

Loading…
Cancel
Save