@sveltejs/kit
Version:
SvelteKit is the fastest way to build Svelte apps
160 lines (139 loc) • 4.18 kB
JavaScript
import { dedent, isSvelte5Plus, write_if_changed } from './utils.js';
/**
* @param {import('types').ManifestData} manifest_data
* @param {string} output
*/
export function write_root(manifest_data, output) {
// TODO remove default layout altogether
const max_depth = Math.max(
...manifest_data.routes.map((route) =>
route.page ? route.page.layouts.filter(Boolean).length + 1 : 0
),
1
);
const levels = [];
for (let i = 0; i <= max_depth; i += 1) {
levels.push(i);
}
let l = max_depth;
let pyramid = dedent`
${
isSvelte5Plus()
? `<!-- svelte-ignore binding_property_non_reactive -->
<Pyramid_${l} bind:this={components[${l}]} data={data_${l}} {form} />`
: `<svelte:component this={constructors[${l}]} bind:this={components[${l}]} data={data_${l}} {form} />`
}`;
while (l--) {
pyramid = dedent`
{#if constructors[${l + 1}]}
${
isSvelte5Plus()
? dedent`{@const Pyramid_${l} = constructors[${l}]}
<!-- svelte-ignore binding_property_non_reactive -->
<Pyramid_${l} bind:this={components[${l}]} data={data_${l}} {form}>
${pyramid}
</Pyramid_${l}>`
: dedent`<svelte:component this={constructors[${l}]} bind:this={components[${l}]} data={data_${l}}>
${pyramid}
</svelte:component>`
}
{:else}
${
isSvelte5Plus()
? dedent`
{@const Pyramid_${l} = constructors[${l}]}
<!-- svelte-ignore binding_property_non_reactive -->
<Pyramid_${l} bind:this={components[${l}]} data={data_${l}} {form} />
`
: dedent`<svelte:component this={constructors[${l}]} bind:this={components[${l}]} data={data_${l}} {form} />`
}
{/if}
`;
}
write_if_changed(
`${output}/root.svelte`,
dedent`
<!-- This file is generated by @sveltejs/kit — do not edit it! -->
${isSvelte5Plus() ? '<svelte:options runes={true} />' : ''}
<script>
import { setContext, ${isSvelte5Plus() ? '' : 'afterUpdate, '}onMount, tick } from 'svelte';
import { browser } from '$app/environment';
// stores
${
isSvelte5Plus()
? dedent`
let { stores, page, constructors, components = [], form, ${levels
.map((l) => `data_${l} = null`)
.join(', ')} } = $props();
`
: dedent`
export let stores;
export let page;
export let constructors;
export let components = [];
export let form;
${levels.map((l) => `export let data_${l} = null;`).join('\n')}
`
}
if (!browser) {
setContext('__svelte__', stores);
}
${
isSvelte5Plus()
? dedent`
if (browser) {
$effect.pre(() => stores.page.set(page));
} else {
stores.page.set(page);
}
`
: '$: stores.page.set(page);'
}
${
isSvelte5Plus()
? dedent`
$effect(() => {
stores;page;constructors;components;form;${levels.map((l) => `data_${l}`).join(';')};
stores.page.notify();
});
`
: 'afterUpdate(stores.page.notify);'
}
let mounted = ${isSvelte5Plus() ? '$state(false)' : 'false'};
let navigated = ${isSvelte5Plus() ? '$state(false)' : 'false'};
let title = ${isSvelte5Plus() ? '$state(null)' : 'null'};
onMount(() => {
const unsubscribe = stores.page.subscribe(() => {
if (mounted) {
navigated = true;
tick().then(() => {
title = document.title || 'untitled page';
});
}
});
mounted = true;
return unsubscribe;
});
${isSvelte5Plus() ? `const Pyramid_${max_depth}=$derived(constructors[${max_depth}])` : ''}
</script>
${pyramid}
{#if mounted}
<div id="svelte-announcer" aria-live="assertive" aria-atomic="true" style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px">
{#if navigated}
{title}
{/if}
</div>
{/if}
`
);
if (isSvelte5Plus()) {
write_if_changed(
`${output}/root.js`,
dedent`
import { asClassComponent } from 'svelte/legacy';
import Root from './root.svelte';
export default asClassComponent(Root);
`
);
}
}