From 202c7ca73483d5f76ec41a187404a11126e99b84 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 15 May 2025 23:36:22 +0800 Subject: [PATCH 01/14] don't cache during dev --- packages/kit/src/exports/vite/dev/index.js | 20 ++++++++++--------- .../src/exports/vite/static_analysis/index.js | 10 +--------- packages/kit/test/apps/writes/test/test.js | 17 +++++++++++----- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index 9ed6dd17c4af..08b287dcf11c 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -102,8 +102,15 @@ export async function dev(vite, vite_config, svelte_config) { return { module, module_node, url }; } - /** @type {(file: string) => void} */ - let invalidate_page_options; + /** + * + * @param {string} server_node + * @returns {Promise>} + */ + const resolve_server_node = async (server_node) => { + const { module } = await resolve(server_node); + return module; + }; function update_manifest() { try { @@ -128,12 +135,6 @@ export async function dev(vite, vite_config, svelte_config) { return; } - const static_analyser = create_static_analyser(async (server_node) => { - const { module } = await resolve(server_node); - return module; - }); - invalidate_page_options = static_analyser.invalidate_page_options; - manifest = { appDir: svelte_config.kit.appDir, appPath: svelte_config.kit.appDir, @@ -211,6 +212,8 @@ export async function dev(vite, vite_config, svelte_config) { }; } + const static_analyser = create_static_analyser(resolve_server_node); + if (node.universal) { const page_options = await static_analyser.get_page_options(node); if (page_options?.ssr === false) { @@ -360,7 +363,6 @@ export async function dev(vite, vite_config, svelte_config) { if (timeout || restarting) return; sync.update(svelte_config, manifest_data, file); - invalidate_page_options(path.relative(cwd, file)); }); const { appTemplate, errorTemplate, serviceWorker, hooks } = svelte_config.kit.files; diff --git a/packages/kit/src/exports/vite/static_analysis/index.js b/packages/kit/src/exports/vite/static_analysis/index.js index 125319e1c0de..963306f32df0 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.js +++ b/packages/kit/src/exports/vite/static_analysis/index.js @@ -247,13 +247,5 @@ export function create_static_analyser(resolve) { return page_options; }; - /** - * @param {string} file - * @returns {void} - */ - const invalidate_page_options = (file) => { - static_exports.delete(file); - }; - - return { get_page_options, invalidate_page_options }; + return { get_page_options }; } diff --git a/packages/kit/test/apps/writes/test/test.js b/packages/kit/test/apps/writes/test/test.js index 5ebc88f92e75..b68212f7eac0 100644 --- a/packages/kit/test/apps/writes/test/test.js +++ b/packages/kit/test/apps/writes/test/test.js @@ -64,20 +64,27 @@ test.describe('Filesystem updates', () => { const file = fileURLToPath(new URL('../src/routes/universal/+page.js', import.meta.url)); const contents = fs.readFileSync(file, 'utf-8'); - await page.goto('/universal'); + try { + fs.writeFileSync(file, contents.replace(/export const ssr = false;\n/, '')); + await page.goto('/universal', { wait_for_started: false }); + expect(await get_computed_style('body', 'background-color')).not.toBe('rgb(255, 0, 0)'); + await expect(page.locator('h1')).toHaveText('Internal Error'); + } finally { + fs.writeFileSync(file, contents); + } + await page.waitForTimeout(500); // this is the rare time we actually need waitForTimeout; we have no visibility into whether the module graph has been invalidated + await page.reload(); expect(await get_computed_style('body', 'background-color')).toBe('rgb(255, 0, 0)'); try { fs.writeFileSync(file, contents.replace(/export const ssr = .*;/, 'export const ssr = !1;')); await page.waitForTimeout(500); // this is the rare time we actually need waitForTimeout; we have no visibility into whether the module graph has been invalidated + await page.goto('/universal', { wait_for_started: false }); expect(await get_computed_style('body', 'background-color')).not.toBe('rgb(255, 0, 0)'); await expect(page.locator('h1')).toHaveText('Internal Error'); } finally { - fs.writeFileSync( - file, - contents.replace(/export const ssr = .*;/, 'export const ssr = false;') - ); + fs.writeFileSync(file, contents.replace(/\\nexport const ssr = false;\\n/, '')); } }); }); From 99597184bc7976bcd9c812073254bac22f0e52bf Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 15 May 2025 23:37:08 +0800 Subject: [PATCH 02/14] changeset --- .changeset/big-eels-watch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/big-eels-watch.md diff --git a/.changeset/big-eels-watch.md b/.changeset/big-eels-watch.md new file mode 100644 index 000000000000..c8e5611d984b --- /dev/null +++ b/.changeset/big-eels-watch.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: avoid static analysis stale cache results From 897458241d3566906e174e4ea98b492b5d7766c4 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 15 May 2025 23:48:29 +0800 Subject: [PATCH 03/14] ok we can cache --- .changeset/big-eels-watch.md | 2 +- packages/kit/src/exports/vite/dev/index.js | 30 ++++++++++--------- .../src/exports/vite/static_analysis/index.js | 10 ++++++- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/.changeset/big-eels-watch.md b/.changeset/big-eels-watch.md index c8e5611d984b..1ac258f5d11e 100644 --- a/.changeset/big-eels-watch.md +++ b/.changeset/big-eels-watch.md @@ -2,4 +2,4 @@ '@sveltejs/kit': patch --- -fix: avoid static analysis stale cache results +fix: correctly invalidate static analysis cache when modifying a universal `+page`/`+layout` file diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index 08b287dcf11c..eca66ef49e4e 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -102,15 +102,8 @@ export async function dev(vite, vite_config, svelte_config) { return { module, module_node, url }; } - /** - * - * @param {string} server_node - * @returns {Promise>} - */ - const resolve_server_node = async (server_node) => { - const { module } = await resolve(server_node); - return module; - }; + /** @type {(file: string) => void} */ + let invalidate_page_options; function update_manifest() { try { @@ -135,6 +128,12 @@ export async function dev(vite, vite_config, svelte_config) { return; } + const static_analyser = create_static_analyser(async (server_node) => { + const { module } = await resolve(server_node); + return module; + }); + invalidate_page_options = static_analyser.invalidate_page_options; + manifest = { appDir: svelte_config.kit.appDir, appPath: svelte_config.kit.appDir, @@ -212,8 +211,6 @@ export async function dev(vite, vite_config, svelte_config) { }; } - const static_analyser = create_static_analyser(resolve_server_node); - if (node.universal) { const page_options = await static_analyser.get_page_options(node); if (page_options?.ssr === false) { @@ -363,6 +360,7 @@ export async function dev(vite, vite_config, svelte_config) { if (timeout || restarting) return; sync.update(svelte_config, manifest_data, file); + invalidate_page_options(path.relative(cwd, file)); }); const { appTemplate, errorTemplate, serviceWorker, hooks } = svelte_config.kit.files; @@ -389,10 +387,14 @@ export async function dev(vite, vite_config, svelte_config) { } }); - // changing the svelte config requires restarting the dev server - // the config is only read on start and passed on to vite-plugin-svelte - // which needs up-to-date values to operate correctly vite.watcher.on('change', async (file) => { + if (file.match(/\+(page|layout).*$/)) { + invalidate_page_options(path.relative(cwd, file)); + } + + // changing the svelte config requires restarting the dev server + // the config is only read on start and passed on to vite-plugin-svelte + // which needs up-to-date values to operate correctly if (path.basename(file) === 'svelte.config.js') { console.log(`svelte config changed, restarting vite dev-server. changed file: ${file}`); restarting = true; diff --git a/packages/kit/src/exports/vite/static_analysis/index.js b/packages/kit/src/exports/vite/static_analysis/index.js index 963306f32df0..125319e1c0de 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.js +++ b/packages/kit/src/exports/vite/static_analysis/index.js @@ -247,5 +247,13 @@ export function create_static_analyser(resolve) { return page_options; }; - return { get_page_options }; + /** + * @param {string} file + * @returns {void} + */ + const invalidate_page_options = (file) => { + static_exports.delete(file); + }; + + return { get_page_options, invalidate_page_options }; } From 3134271c1b0a23412bbb0c3a8b6a86a03fc4dc40 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 15 May 2025 23:50:09 +0800 Subject: [PATCH 04/14] Update .changeset/big-eels-watch.md --- .changeset/big-eels-watch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/big-eels-watch.md b/.changeset/big-eels-watch.md index 1ac258f5d11e..33921d83b024 100644 --- a/.changeset/big-eels-watch.md +++ b/.changeset/big-eels-watch.md @@ -2,4 +2,4 @@ '@sveltejs/kit': patch --- -fix: correctly invalidate static analysis cache when modifying a universal `+page`/`+layout` file +fix: correctly invalidate static analysis cache when modifying a universal `+page`/`+layout` file during dev From e42e93d065ddb976a95a7c6c194eb93505af1bfa Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Fri, 16 May 2025 09:57:02 +0800 Subject: [PATCH 05/14] fix universal file check --- packages/kit/src/exports/vite/dev/index.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index eca66ef49e4e..ad14961bd4ca 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -359,8 +359,11 @@ export async function dev(vite, vite_config, svelte_config) { // Don't run for a single file if the whole manifest is about to get updated if (timeout || restarting) return; + if (is_universal_file(file)) { + invalidate_page_options(path.relative(cwd, file)); + } + sync.update(svelte_config, manifest_data, file); - invalidate_page_options(path.relative(cwd, file)); }); const { appTemplate, errorTemplate, serviceWorker, hooks } = svelte_config.kit.files; @@ -388,7 +391,7 @@ export async function dev(vite, vite_config, svelte_config) { }); vite.watcher.on('change', async (file) => { - if (file.match(/\+(page|layout).*$/)) { + if (is_universal_file(file)) { invalidate_page_options(path.relative(cwd, file)); } @@ -651,3 +654,11 @@ function has_correct_case(file, assets) { return false; } + +/** + * @param {string} file + * @returns {boolean} + */ +function is_universal_file(file) { + return /\+(page|layout).*$/.test(file); +} From d44e2de174d9b0809dde425de7bb124de30b3ecc Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Fri, 16 May 2025 11:05:00 +0800 Subject: [PATCH 06/14] add correct test --- .changeset/big-eels-watch.md | 2 +- packages/kit/src/exports/vite/dev/index.js | 15 ++--------- .../src/exports/vite/static_analysis/index.js | 1 + .../universal/parent-changed/+layout.js | 1 + .../routes/universal/parent-changed/+page.js | 1 + .../universal/parent-changed/+page.svelte | 1 + packages/kit/test/apps/writes/test/test.js | 25 ++++++++++++++++++- 7 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 packages/kit/test/apps/writes/src/routes/universal/parent-changed/+layout.js create mode 100644 packages/kit/test/apps/writes/src/routes/universal/parent-changed/+page.js create mode 100644 packages/kit/test/apps/writes/src/routes/universal/parent-changed/+page.svelte diff --git a/.changeset/big-eels-watch.md b/.changeset/big-eels-watch.md index 33921d83b024..f2eed653a812 100644 --- a/.changeset/big-eels-watch.md +++ b/.changeset/big-eels-watch.md @@ -2,4 +2,4 @@ '@sveltejs/kit': patch --- -fix: correctly invalidate static analysis cache when modifying a universal `+page`/`+layout` file during dev +fix: correctly invalidate static analysis cache of child nodes when modifying a universal `+layout` file during dev diff --git a/packages/kit/src/exports/vite/dev/index.js b/packages/kit/src/exports/vite/dev/index.js index ad14961bd4ca..36b590334678 100644 --- a/packages/kit/src/exports/vite/dev/index.js +++ b/packages/kit/src/exports/vite/dev/index.js @@ -353,13 +353,14 @@ export async function dev(vite, vite_config, svelte_config) { // Debounce add/unlink events because in case of folder deletion or moves // they fire in rapid succession, causing needless invocations. + // These watchers only run for routes, param matchers, and client hooks. watch('add', () => debounce(update_manifest)); watch('unlink', () => debounce(update_manifest)); watch('change', (file) => { // Don't run for a single file if the whole manifest is about to get updated if (timeout || restarting) return; - if (is_universal_file(file)) { + if (/\+(page|layout).*$/.test(file)) { invalidate_page_options(path.relative(cwd, file)); } @@ -391,10 +392,6 @@ export async function dev(vite, vite_config, svelte_config) { }); vite.watcher.on('change', async (file) => { - if (is_universal_file(file)) { - invalidate_page_options(path.relative(cwd, file)); - } - // changing the svelte config requires restarting the dev server // the config is only read on start and passed on to vite-plugin-svelte // which needs up-to-date values to operate correctly @@ -654,11 +651,3 @@ function has_correct_case(file, assets) { return false; } - -/** - * @param {string} file - * @returns {boolean} - */ -function is_universal_file(file) { - return /\+(page|layout).*$/.test(file); -} diff --git a/packages/kit/src/exports/vite/static_analysis/index.js b/packages/kit/src/exports/vite/static_analysis/index.js index 125319e1c0de..911df159be4f 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.js +++ b/packages/kit/src/exports/vite/static_analysis/index.js @@ -252,6 +252,7 @@ export function create_static_analyser(resolve) { * @returns {void} */ const invalidate_page_options = (file) => { + // TODO: this needs to invalidate nodes lower in the branch too static_exports.delete(file); }; diff --git a/packages/kit/test/apps/writes/src/routes/universal/parent-changed/+layout.js b/packages/kit/test/apps/writes/src/routes/universal/parent-changed/+layout.js new file mode 100644 index 000000000000..a3d15781a772 --- /dev/null +++ b/packages/kit/test/apps/writes/src/routes/universal/parent-changed/+layout.js @@ -0,0 +1 @@ +export const ssr = false; diff --git a/packages/kit/test/apps/writes/src/routes/universal/parent-changed/+page.js b/packages/kit/test/apps/writes/src/routes/universal/parent-changed/+page.js new file mode 100644 index 000000000000..b01f93ba591a --- /dev/null +++ b/packages/kit/test/apps/writes/src/routes/universal/parent-changed/+page.js @@ -0,0 +1 @@ +document.body.style.backgroundColor = 'red'; diff --git a/packages/kit/test/apps/writes/src/routes/universal/parent-changed/+page.svelte b/packages/kit/test/apps/writes/src/routes/universal/parent-changed/+page.svelte new file mode 100644 index 000000000000..48aa4cb69f99 --- /dev/null +++ b/packages/kit/test/apps/writes/src/routes/universal/parent-changed/+page.svelte @@ -0,0 +1 @@ +

hello world

diff --git a/packages/kit/test/apps/writes/test/test.js b/packages/kit/test/apps/writes/test/test.js index b68212f7eac0..0cf27bf831a7 100644 --- a/packages/kit/test/apps/writes/test/test.js +++ b/packages/kit/test/apps/writes/test/test.js @@ -74,17 +74,40 @@ test.describe('Filesystem updates', () => { } await page.waitForTimeout(500); // this is the rare time we actually need waitForTimeout; we have no visibility into whether the module graph has been invalidated + // a reload is required because Vite HMR doesn't trigger if the page has never loaded successfully await page.reload(); expect(await get_computed_style('body', 'background-color')).toBe('rgb(255, 0, 0)'); try { fs.writeFileSync(file, contents.replace(/export const ssr = .*;/, 'export const ssr = !1;')); await page.waitForTimeout(500); // this is the rare time we actually need waitForTimeout; we have no visibility into whether the module graph has been invalidated - await page.goto('/universal', { wait_for_started: false }); expect(await get_computed_style('body', 'background-color')).not.toBe('rgb(255, 0, 0)'); await expect(page.locator('h1')).toHaveText('Internal Error'); } finally { fs.writeFileSync(file, contents.replace(/\\nexport const ssr = false;\\n/, '')); } }); + + test('Universal node is updated when parent page options change', async ({ + page, + javaScriptEnabled, + get_computed_style + }) => { + test.skip(!process.env.DEV || !javaScriptEnabled); + + const file = fileURLToPath(new URL('../src/routes/universal/parent-changed/+layout.js', import.meta.url)); + const contents = fs.readFileSync(file, 'utf-8'); + + try { + await page.goto('/universal/parent-changed'); + expect(await get_computed_style('body', 'background-color')).toBe('rgb(255, 0, 0)'); + + fs.writeFileSync(file, contents.replace(/export const ssr = false;/, '')); + await page.waitForTimeout(500); // this is the rare time we actually need waitForTimeout; we have no visibility into whether the module graph has been invalidated + expect(await get_computed_style('body', 'background-color')).not.toBe('rgb(255, 0, 0)'); + await expect(page.locator('h1')).toHaveText('Internal Error'); + } finally { + fs.writeFileSync(file, contents); + } + }); }); From d4d0bbf64d622a506b08e52eeb80a3a78105622a Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Fri, 16 May 2025 11:06:50 +0800 Subject: [PATCH 07/14] format --- packages/kit/test/apps/writes/test/test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/kit/test/apps/writes/test/test.js b/packages/kit/test/apps/writes/test/test.js index 0cf27bf831a7..e513c647f37d 100644 --- a/packages/kit/test/apps/writes/test/test.js +++ b/packages/kit/test/apps/writes/test/test.js @@ -95,7 +95,9 @@ test.describe('Filesystem updates', () => { }) => { test.skip(!process.env.DEV || !javaScriptEnabled); - const file = fileURLToPath(new URL('../src/routes/universal/parent-changed/+layout.js', import.meta.url)); + const file = fileURLToPath( + new URL('../src/routes/universal/parent-changed/+layout.js', import.meta.url) + ); const contents = fs.readFileSync(file, 'utf-8'); try { @@ -103,7 +105,7 @@ test.describe('Filesystem updates', () => { expect(await get_computed_style('body', 'background-color')).toBe('rgb(255, 0, 0)'); fs.writeFileSync(file, contents.replace(/export const ssr = false;/, '')); - await page.waitForTimeout(500); // this is the rare time we actually need waitForTimeout; we have no visibility into whether the module graph has been invalidated + await page.waitForTimeout(500); // this is the rare time we actually need waitForTimeout; we have no visibility into whether the module graph has been invalidated expect(await get_computed_style('body', 'background-color')).not.toBe('rgb(255, 0, 0)'); await expect(page.locator('h1')).toHaveText('Internal Error'); } finally { From 3de08a1e0c674977637b56f936414d31d027494a Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Fri, 16 May 2025 17:10:34 +0800 Subject: [PATCH 08/14] cleanup --- .../src/exports/vite/static_analysis/index.js | 100 +++++++++--------- .../vite/static_analysis/index.spec.js | 16 +-- 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/packages/kit/src/exports/vite/static_analysis/index.js b/packages/kit/src/exports/vite/static_analysis/index.js index 911df159be4f..ea8172697788 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.js +++ b/packages/kit/src/exports/vite/static_analysis/index.js @@ -4,23 +4,22 @@ import { read } from '../../../utils/filesystem.js'; const inheritable_page_options = new Set(['ssr', 'prerender', 'csr', 'trailingSlash', 'config']); -const page_options = new Set([...inheritable_page_options, 'entries']); +const valid_page_options = new Set([...inheritable_page_options, 'entries']); const skip_parsing_regex = new RegExp( - `${Array.from(page_options).join('|')}|(?:export[\\s\\n]+\\*[\\s\\n]+from)` + `${Array.from(valid_page_options).join('|')}|(?:export[\\s\\n]+\\*[\\s\\n]+from)` ); const parser = Parser.extend(tsPlugin()); /** - * Collects exported page options from a +page.js/+layout.js file. - * We ignore reassignments and use the declared value. - * Returns `null` if any export is too difficult to analyse. - * @param {string} filename + * Collects page options from a +page.js/+layout.js file, ignoring reassignments + * and using the declared value. Returns `null` if any export is too difficult to analyse. + * @param {string} filename The name of the file to report when an error occurs * @param {string} input * @returns {Record | null} */ -export function statically_analyse_exports(filename, input) { +export function statically_analyse_page_options(filename, input) { // if there's a chance there are no page exports or export all declaration, // then we can skip the AST parsing which is expensive if (!skip_parsing_regex.test(input)) { @@ -34,14 +33,14 @@ export function statically_analyse_exports(filename, input) { }); /** @type {Map} */ - const static_exports = new Map(); + const page_options = new Map(); for (const statement of source.body) { // ignore export all declarations with aliases that are not page options if ( statement.type === 'ExportAllDeclaration' && statement.exported && - !page_options.has(get_name(statement.exported)) + !valid_page_options.has(get_name(statement.exported)) ) { continue; } @@ -60,7 +59,7 @@ export function statically_analyse_exports(filename, input) { const export_specifiers = new Map(); for (const specifier of statement.specifiers) { const exported_name = get_name(specifier.exported); - if (!page_options.has(exported_name)) { + if (!valid_page_options.has(exported_name)) { continue; } @@ -109,7 +108,7 @@ export function statically_analyse_exports(filename, input) { } if (variable_declarator.init?.type === 'Literal') { - static_exports.set( + page_options.set( /** @type {string} */ (export_specifiers.get(variable_declarator.id.name)), variable_declarator.init.value ); @@ -138,7 +137,7 @@ export function statically_analyse_exports(filename, input) { // class and function declarations if (statement.declaration.type !== 'VariableDeclaration') { - if (page_options.has(statement.declaration.id.name)) { + if (valid_page_options.has(statement.declaration.id.name)) { return null; } continue; @@ -149,12 +148,12 @@ export function statically_analyse_exports(filename, input) { return null; } - if (!page_options.has(declaration.id.name)) { + if (!valid_page_options.has(declaration.id.name)) { continue; } if (declaration.init?.type === 'Literal') { - static_exports.set(declaration.id.name, declaration.init.value); + page_options.set(declaration.id.name, declaration.init.value); continue; } @@ -163,10 +162,10 @@ export function statically_analyse_exports(filename, input) { } } - return Object.fromEntries(static_exports); + return Object.fromEntries(page_options); } catch (error) { if (error instanceof Error) { - error.message = `Failed to statically analyse ${filename}. ${error.message}`; + error.message = `Failed to statically analyse page options for ${filename}. ${error.message}`; } throw error; } @@ -185,75 +184,72 @@ export function get_name(node) { */ export function create_static_analyser(resolve) { /** @type {Map | null>} */ - const static_exports = new Map(); + const cache = new Map(); /** * Computes the final page options for a node (if possible). Otherwise, returns `null`. * @param {import('types').PageNode} node - * @returns {Promise} + * @returns {Promise | null>} */ const get_page_options = async (node) => { - if (node.universal && static_exports.has(node.universal)) { - return /** @type {import('types').UniversalNode | null} */ ( - static_exports.get(node.universal) - ); + const key = node.universal || node.server; + if (key && cache.has(key)) { + return /** @type {Record | null} */ (cache.get(key)); } - /** @type {Record | null} */ + /** @type {Record} */ let page_options = {}; + if (node.parent) { + const parent_options = await get_page_options(node.parent); + if (parent_options === null) { + // if the parent cannot be analysed, we can't know what page options + // the child node inherits, so we also mark it as unanalysable + if (key) { + cache.set(key, null); + } + return null; + } + + page_options = { ...parent_options.page_options }; + } + if (node.server) { const module = await resolve(node.server); - for (const key in inheritable_page_options) { - if (key in module) { - page_options[key] = module[key]; + for (const page_option in inheritable_page_options) { + if (page_option in module) { + page_options[page_option] = module[page_option]; } } } if (node.universal) { - let universal_exports = static_exports.get(node.universal); - if (universal_exports === undefined) { - const input = read(node.universal); - universal_exports = statically_analyse_exports(node.universal, input); - } + const input = read(node.universal); + const universal_page_options = statically_analyse_page_options(node.universal, input); - if (universal_exports === null) { - static_exports.set(node.universal, null); + if (universal_page_options === null) { + cache.set(node.universal, null); return null; } - page_options = { ...page_options, ...universal_exports }; + page_options = { ...page_options, ...universal_page_options }; } - if (node.parent) { - const parent_options = await get_page_options(node.parent); - if (parent_options === null) { - // if the parent cannot be statically analysed, we can't know what - // page options the current node inherits, so we invalidate it too - if (node.universal) { - static_exports.set(node.universal, null); - } - return null; - } - - page_options = { ...parent_options, ...page_options }; + if (key) { + cache.set(key, page_options); } - if (node.universal) { - static_exports.set(node.universal, page_options); - } + console.log(node.server, node.universal, node.component, page_options); return page_options; }; /** * @param {string} file - * @returns {void} */ const invalidate_page_options = (file) => { - // TODO: this needs to invalidate nodes lower in the branch too - static_exports.delete(file); + // TODO: invalidate children if it's a layout + cache.delete(file); }; return { get_page_options, invalidate_page_options }; diff --git a/packages/kit/src/exports/vite/static_analysis/index.spec.js b/packages/kit/src/exports/vite/static_analysis/index.spec.js index 2514555d3033..6c94431b6fb6 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.spec.js +++ b/packages/kit/src/exports/vite/static_analysis/index.spec.js @@ -1,5 +1,5 @@ import { expect, test } from 'vitest'; -import { statically_analyse_exports } from './index.js'; +import { statically_analyse_page_options } from './index.js'; test.each([ [ @@ -18,7 +18,7 @@ test.each([ ` ] ])('page option is assigned a literal value: %s', (_, input) => { - const exports = statically_analyse_exports('', input); + const exports = statically_analyse_page_options('', input); expect(exports).toEqual({ ssr: false, csr: true, prerender: 'auto', trailingSlash: 'always' }); }); @@ -52,7 +52,7 @@ test.each([ ], ['export all declaration alias', "export * as ssr from './foo'"] ])('fails when page option is assigned a dynamic value: %s', (_, input) => { - const exports = statically_analyse_exports('', input); + const exports = statically_analyse_page_options('', input); expect(exports).toEqual(null); }); @@ -62,7 +62,7 @@ test.each([ ['export all declaration alias', 'export * as bar from "./foo"'], ['non-page option export', "export const foo = 'bar'"] ])('ignores %s', (_, input) => { - const exports = statically_analyse_exports('', input); + const exports = statically_analyse_page_options('', input); expect(exports).toEqual({}); }); @@ -72,7 +72,7 @@ test.each([ ['whitespace', 'export * from "./foo";'], ['multiple lines and whitespace', "export \n *\n from 'abc'; "] ])('fails when export all declaration is used: %s', (_, input) => { - const exports = statically_analyse_exports('', input); + const exports = statically_analyse_page_options('', input); expect(exports).toEqual(null); }); @@ -131,7 +131,7 @@ test.each([ ` ] ])('non-reassigned page options: %s', (_, input) => { - const exports = statically_analyse_exports('', input); + const exports = statically_analyse_page_options('', input); expect(exports).toEqual({ ssr: true, prerender: true }); }); @@ -151,7 +151,7 @@ test.each([ ` ] ])('export specifier references: %s', (_, input) => { - const exports = statically_analyse_exports('', input); + const exports = statically_analyse_page_options('', input); expect(exports).toEqual({ ssr: false }); }); @@ -185,6 +185,6 @@ test.each([ ` ] ])('fails when export specifier references: %s', (_, input) => { - const exports = statically_analyse_exports('', input); + const exports = statically_analyse_page_options('', input); expect(exports).toEqual(null); }); From 129c2bb70c119f1fcdaf4dc7f8206193a7ba3723 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Fri, 16 May 2025 17:39:43 +0800 Subject: [PATCH 09/14] fix --- packages/kit/src/exports/vite/static_analysis/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/exports/vite/static_analysis/index.js b/packages/kit/src/exports/vite/static_analysis/index.js index ea8172697788..a01b3b658ad4 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.js +++ b/packages/kit/src/exports/vite/static_analysis/index.js @@ -194,13 +194,14 @@ export function create_static_analyser(resolve) { const get_page_options = async (node) => { const key = node.universal || node.server; if (key && cache.has(key)) { - return /** @type {Record | null} */ (cache.get(key)); + return { .../** @type {Record | null} */ (cache.get(key)) }; } /** @type {Record} */ let page_options = {}; if (node.parent) { + // TODO: dedupe analysis from other nodes being loaded const parent_options = await get_page_options(node.parent); if (parent_options === null) { // if the parent cannot be analysed, we can't know what page options @@ -211,7 +212,7 @@ export function create_static_analyser(resolve) { return null; } - page_options = { ...parent_options.page_options }; + page_options = { ...parent_options }; } if (node.server) { From 3f1a4d401826ca5f62cfb703cdef5e170a9bc7e2 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 29 May 2025 17:04:26 +0800 Subject: [PATCH 10/14] ensure nodes are analysed sequentially --- .../vite/static_analysis/fixtures/+layout.js | 1 + .../fixtures/nested/+layout.js | 1 + .../static_analysis/fixtures/nested/+page.js | 1 + .../src/exports/vite/static_analysis/index.js | 18 +++-- .../vite/static_analysis/index.spec.js | 66 ++++++++++++++++++- 5 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 packages/kit/src/exports/vite/static_analysis/fixtures/+layout.js create mode 100644 packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js create mode 100644 packages/kit/src/exports/vite/static_analysis/fixtures/nested/+page.js diff --git a/packages/kit/src/exports/vite/static_analysis/fixtures/+layout.js b/packages/kit/src/exports/vite/static_analysis/fixtures/+layout.js new file mode 100644 index 000000000000..a3d15781a772 --- /dev/null +++ b/packages/kit/src/exports/vite/static_analysis/fixtures/+layout.js @@ -0,0 +1 @@ +export const ssr = false; diff --git a/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js b/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js new file mode 100644 index 000000000000..c8cacf089534 --- /dev/null +++ b/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js @@ -0,0 +1 @@ +export const prerender = true; \ No newline at end of file diff --git a/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+page.js b/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+page.js new file mode 100644 index 000000000000..d43d0cd2a55d --- /dev/null +++ b/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+page.js @@ -0,0 +1 @@ +export const prerender = false; diff --git a/packages/kit/src/exports/vite/static_analysis/index.js b/packages/kit/src/exports/vite/static_analysis/index.js index a89d4da906f7..6a2acfcd89fc 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.js +++ b/packages/kit/src/exports/vite/static_analysis/index.js @@ -186,6 +186,9 @@ export function get_name(node) { * }} opts */ export function create_node_analyser({ resolve, static_exports = new Map() }) { + /** @type {Promise | null> | undefined} */ + let current_task; + /** * Computes the final page options for a node (if possible). Otherwise, returns `null`. * @param {import('types').PageNode} node @@ -201,8 +204,12 @@ export function create_node_analyser({ resolve, static_exports = new Map() }) { let page_options = {}; if (node.parent) { - // TODO: dedupe analysis from other nodes being loaded - const parent_options = await get_page_options(node.parent); + // this await allows us to suspend early and let the previous layout analysis + // complete before we start analysing the same layout + if (current_task) await current_task; + const task = get_page_options(node.parent); + current_task = task; + const parent_options = await task; if (parent_options === null) { // if the parent cannot be analysed, we can't know what page options // the child node inherits, so we also mark it as unanalysable @@ -240,8 +247,6 @@ export function create_node_analyser({ resolve, static_exports = new Map() }) { static_exports.set(key, page_options); } - console.log(node.server, node.universal, node.component, page_options); - return page_options; }; @@ -253,5 +258,8 @@ export function create_node_analyser({ resolve, static_exports = new Map() }) { static_exports.delete(file); }; - return { get_page_options, invalidate_page_options }; + return { + get_page_options, + invalidate_page_options + }; } diff --git a/packages/kit/src/exports/vite/static_analysis/index.spec.js b/packages/kit/src/exports/vite/static_analysis/index.spec.js index 6c94431b6fb6..e130395fc811 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.spec.js +++ b/packages/kit/src/exports/vite/static_analysis/index.spec.js @@ -1,5 +1,7 @@ import { expect, test } from 'vitest'; -import { statically_analyse_page_options } from './index.js'; +import { create_node_analyser, statically_analyse_page_options } from './index.js'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; test.each([ [ @@ -188,3 +190,65 @@ test.each([ const exports = statically_analyse_page_options('', input); expect(exports).toEqual(null); }); + +const dir = path.dirname(fileURLToPath(import.meta.url)); + +test('nodes are analysed sequentially so that layout analysis is done only once', async () => { + /** @type {string[]} */ + const cache_used = []; + + /** @type {Map | null>} */ + const static_exports = new Map(); + + const originalGet = static_exports.get; + static_exports.get = function (key) { + cache_used.push(key); + return originalGet.call(this, key); + }; + + const node_analyser = create_node_analyser({ + resolve: () => Promise.resolve({}), + static_exports + }); + + const root_layout = { + depth: 0, + universal: path.join(dir, 'fixtures/+layout.js') + }; + const layout = { + depth: 1, + universal: path.join(dir, 'fixtures/nested/+layout.js'), + parent: root_layout + }; + const leaf = { depth: 1, universal: path.join(dir, 'fixtures/nested/+page.js'), parent: layout }; + + const nodes = [ + async () => { + return { + universal: await node_analyser.get_page_options(root_layout) + }; + }, + async () => { + return { + universal: await node_analyser.get_page_options(layout) + }; + }, + async () => { + return { + universal: await node_analyser.get_page_options(leaf) + }; + } + ]; + + const results = await Promise.all(nodes.map((node) => node())); + + expect(cache_used.map((key) => key.slice(dir.length + 1))).toEqual([ + 'fixtures/+layout.js', + 'fixtures/nested/+layout.js' + ]); + expect(results).toEqual([ + { universal: { ssr: false } }, + { universal: { ssr: false, prerender: true } }, + { universal: { ssr: false, prerender: false } } + ]); +}); From c65f2559295dcb4544efeea630079e5ed659f75f Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 29 May 2025 17:20:48 +0800 Subject: [PATCH 11/14] correctly invalidate child nodes when universal node is updated --- packages/kit/src/core/postbuild/analyse.js | 1 + .../kit/src/exports/vite/build/build_server.js | 2 +- .../static_analysis/fixtures/nested/+layout.js | 2 +- .../src/exports/vite/static_analysis/index.js | 18 ++++++++++++------ .../exports/vite/static_analysis/index.spec.js | 4 +++- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/kit/src/core/postbuild/analyse.js b/packages/kit/src/core/postbuild/analyse.js index 713f4ea66141..ba8a013b32f0 100644 --- a/packages/kit/src/core/postbuild/analyse.js +++ b/packages/kit/src/core/postbuild/analyse.js @@ -63,6 +63,7 @@ async function analyse({ internal.set_manifest(manifest); internal.set_read_implementation((file) => createReadableStream(`${server_root}/server/${file}`)); + /** @type {Map | null, children: string[] }>} */ const static_exports = new Map(); // first, build server nodes without the client manifest so we can analyse it diff --git a/packages/kit/src/exports/vite/build/build_server.js b/packages/kit/src/exports/vite/build/build_server.js index 9332322aa572..20f7bf683842 100644 --- a/packages/kit/src/exports/vite/build/build_server.js +++ b/packages/kit/src/exports/vite/build/build_server.js @@ -15,7 +15,7 @@ import { create_node_analyser } from '../static_analysis/index.js'; * @param {import('vite').Manifest | null} client_manifest * @param {import('vite').Rollup.OutputAsset[] | null} css * @param {import('types').RecursiveRequired} output_config - * @param {Map | null>} static_exports + * @param {Map | null, children: string[] }>} static_exports */ export async function build_server_nodes(out, kit, manifest_data, server_manifest, client_manifest, css, output_config, static_exports) { mkdirp(`${out}/server/nodes`); diff --git a/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js b/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js index c8cacf089534..189f71e2e1b3 100644 --- a/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js +++ b/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js @@ -1 +1 @@ -export const prerender = true; \ No newline at end of file +export const prerender = true; diff --git a/packages/kit/src/exports/vite/static_analysis/index.js b/packages/kit/src/exports/vite/static_analysis/index.js index 6a2acfcd89fc..d4295efa1f98 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.js +++ b/packages/kit/src/exports/vite/static_analysis/index.js @@ -182,7 +182,7 @@ export function get_name(node) { /** * @param {{ * resolve: (file: string) => Promise>; - * static_exports?: Map | null>; + * static_exports?: Map | null, children: string[] }>; * }} opts */ export function create_node_analyser({ resolve, static_exports = new Map() }) { @@ -197,7 +197,7 @@ export function create_node_analyser({ resolve, static_exports = new Map() }) { const get_page_options = async (node) => { const key = node.universal || node.server; if (key && static_exports.has(key)) { - return { .../** @type {Record | null} */ (static_exports.get(key)) }; + return { ...static_exports.get(key)?.page_options }; } /** @type {Record} */ @@ -210,11 +210,17 @@ export function create_node_analyser({ resolve, static_exports = new Map() }) { const task = get_page_options(node.parent); current_task = task; const parent_options = await task; + + const parent_key = node.parent.universal || node.parent.server; + if (key && parent_key && static_exports.has(parent_key)) { + static_exports.get(parent_key)?.children.push(key); + } + if (parent_options === null) { // if the parent cannot be analysed, we can't know what page options // the child node inherits, so we also mark it as unanalysable if (key) { - static_exports.set(key, null); + static_exports.set(key, { page_options: null, children: [] }); } return null; } @@ -236,7 +242,7 @@ export function create_node_analyser({ resolve, static_exports = new Map() }) { const universal_page_options = statically_analyse_page_options(node.universal, input); if (universal_page_options === null) { - static_exports.set(node.universal, null); + static_exports.set(node.universal, { page_options: null, children: [] }); return null; } @@ -244,7 +250,7 @@ export function create_node_analyser({ resolve, static_exports = new Map() }) { } if (key) { - static_exports.set(key, page_options); + static_exports.set(key, { page_options, children: [] }); } return page_options; @@ -254,7 +260,7 @@ export function create_node_analyser({ resolve, static_exports = new Map() }) { * @param {string} file */ const invalidate_page_options = (file) => { - // TODO: invalidate children if it's a layout + static_exports.get(file)?.children.forEach((child) => static_exports.delete(child)); static_exports.delete(file); }; diff --git a/packages/kit/src/exports/vite/static_analysis/index.spec.js b/packages/kit/src/exports/vite/static_analysis/index.spec.js index e130395fc811..ea0690919b62 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.spec.js +++ b/packages/kit/src/exports/vite/static_analysis/index.spec.js @@ -197,7 +197,7 @@ test('nodes are analysed sequentially so that layout analysis is done only once' /** @type {string[]} */ const cache_used = []; - /** @type {Map | null>} */ + /** @type {Map | null, children: string[] }>} */ const static_exports = new Map(); const originalGet = static_exports.get; @@ -244,6 +244,8 @@ test('nodes are analysed sequentially so that layout analysis is done only once' expect(cache_used.map((key) => key.slice(dir.length + 1))).toEqual([ 'fixtures/+layout.js', + 'fixtures/+layout.js', + 'fixtures/nested/+layout.js', 'fixtures/nested/+layout.js' ]); expect(results).toEqual([ From 84418953b8fec7b276a7c8090cf1a3881d96e850 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 29 May 2025 17:28:29 +0800 Subject: [PATCH 12/14] windows path separators :)))) --- .../vite/static_analysis/index.spec.js | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/kit/src/exports/vite/static_analysis/index.spec.js b/packages/kit/src/exports/vite/static_analysis/index.spec.js index ea0690919b62..0c53d26c829a 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.spec.js +++ b/packages/kit/src/exports/vite/static_analysis/index.spec.js @@ -211,16 +211,23 @@ test('nodes are analysed sequentially so that layout analysis is done only once' static_exports }); + const root_layout_path = path.join('fixtures', '+layout.js'); + const nested_layout_path = path.join('fixtures', 'nested', '+layout.js'); + const root_layout = { depth: 0, - universal: path.join(dir, 'fixtures/+layout.js') + universal: path.join(dir, root_layout_path) }; - const layout = { + const nested_layout = { depth: 1, - universal: path.join(dir, 'fixtures/nested/+layout.js'), + universal: path.join(dir, nested_layout_path), parent: root_layout }; - const leaf = { depth: 1, universal: path.join(dir, 'fixtures/nested/+page.js'), parent: layout }; + const leaf = { + depth: 1, + universal: path.join(dir, 'fixtures/nested/+page.js'), + parent: nested_layout + }; const nodes = [ async () => { @@ -230,7 +237,7 @@ test('nodes are analysed sequentially so that layout analysis is done only once' }, async () => { return { - universal: await node_analyser.get_page_options(layout) + universal: await node_analyser.get_page_options(nested_layout) }; }, async () => { @@ -243,10 +250,10 @@ test('nodes are analysed sequentially so that layout analysis is done only once' const results = await Promise.all(nodes.map((node) => node())); expect(cache_used.map((key) => key.slice(dir.length + 1))).toEqual([ - 'fixtures/+layout.js', - 'fixtures/+layout.js', - 'fixtures/nested/+layout.js', - 'fixtures/nested/+layout.js' + root_layout, + root_layout, + nested_layout, + nested_layout ]); expect(results).toEqual([ { universal: { ssr: false } }, From 456fbe48e39dedea347296cef0ef86ab9bb15f97 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 29 May 2025 17:40:55 +0800 Subject: [PATCH 13/14] we'll come back to this later --- .../vite/static_analysis/fixtures/+layout.js | 1 - .../fixtures/nested/+layout.js | 1 - .../static_analysis/fixtures/nested/+page.js | 1 - .../src/exports/vite/static_analysis/index.js | 12 +--- .../vite/static_analysis/index.spec.js | 71 ------------------- 5 files changed, 2 insertions(+), 84 deletions(-) delete mode 100644 packages/kit/src/exports/vite/static_analysis/fixtures/+layout.js delete mode 100644 packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js delete mode 100644 packages/kit/src/exports/vite/static_analysis/fixtures/nested/+page.js diff --git a/packages/kit/src/exports/vite/static_analysis/fixtures/+layout.js b/packages/kit/src/exports/vite/static_analysis/fixtures/+layout.js deleted file mode 100644 index a3d15781a772..000000000000 --- a/packages/kit/src/exports/vite/static_analysis/fixtures/+layout.js +++ /dev/null @@ -1 +0,0 @@ -export const ssr = false; diff --git a/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js b/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js deleted file mode 100644 index 189f71e2e1b3..000000000000 --- a/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+layout.js +++ /dev/null @@ -1 +0,0 @@ -export const prerender = true; diff --git a/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+page.js b/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+page.js deleted file mode 100644 index d43d0cd2a55d..000000000000 --- a/packages/kit/src/exports/vite/static_analysis/fixtures/nested/+page.js +++ /dev/null @@ -1 +0,0 @@ -export const prerender = false; diff --git a/packages/kit/src/exports/vite/static_analysis/index.js b/packages/kit/src/exports/vite/static_analysis/index.js index d4295efa1f98..e6e56df7b8e9 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.js +++ b/packages/kit/src/exports/vite/static_analysis/index.js @@ -186,9 +186,6 @@ export function get_name(node) { * }} opts */ export function create_node_analyser({ resolve, static_exports = new Map() }) { - /** @type {Promise | null> | undefined} */ - let current_task; - /** * Computes the final page options for a node (if possible). Otherwise, returns `null`. * @param {import('types').PageNode} node @@ -204,15 +201,10 @@ export function create_node_analyser({ resolve, static_exports = new Map() }) { let page_options = {}; if (node.parent) { - // this await allows us to suspend early and let the previous layout analysis - // complete before we start analysing the same layout - if (current_task) await current_task; - const task = get_page_options(node.parent); - current_task = task; - const parent_options = await task; + const parent_options = await get_page_options(node.parent); const parent_key = node.parent.universal || node.parent.server; - if (key && parent_key && static_exports.has(parent_key)) { + if (key && parent_key) { static_exports.get(parent_key)?.children.push(key); } diff --git a/packages/kit/src/exports/vite/static_analysis/index.spec.js b/packages/kit/src/exports/vite/static_analysis/index.spec.js index 0c53d26c829a..fcfa477a829b 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.spec.js +++ b/packages/kit/src/exports/vite/static_analysis/index.spec.js @@ -190,74 +190,3 @@ test.each([ const exports = statically_analyse_page_options('', input); expect(exports).toEqual(null); }); - -const dir = path.dirname(fileURLToPath(import.meta.url)); - -test('nodes are analysed sequentially so that layout analysis is done only once', async () => { - /** @type {string[]} */ - const cache_used = []; - - /** @type {Map | null, children: string[] }>} */ - const static_exports = new Map(); - - const originalGet = static_exports.get; - static_exports.get = function (key) { - cache_used.push(key); - return originalGet.call(this, key); - }; - - const node_analyser = create_node_analyser({ - resolve: () => Promise.resolve({}), - static_exports - }); - - const root_layout_path = path.join('fixtures', '+layout.js'); - const nested_layout_path = path.join('fixtures', 'nested', '+layout.js'); - - const root_layout = { - depth: 0, - universal: path.join(dir, root_layout_path) - }; - const nested_layout = { - depth: 1, - universal: path.join(dir, nested_layout_path), - parent: root_layout - }; - const leaf = { - depth: 1, - universal: path.join(dir, 'fixtures/nested/+page.js'), - parent: nested_layout - }; - - const nodes = [ - async () => { - return { - universal: await node_analyser.get_page_options(root_layout) - }; - }, - async () => { - return { - universal: await node_analyser.get_page_options(nested_layout) - }; - }, - async () => { - return { - universal: await node_analyser.get_page_options(leaf) - }; - } - ]; - - const results = await Promise.all(nodes.map((node) => node())); - - expect(cache_used.map((key) => key.slice(dir.length + 1))).toEqual([ - root_layout, - root_layout, - nested_layout, - nested_layout - ]); - expect(results).toEqual([ - { universal: { ssr: false } }, - { universal: { ssr: false, prerender: true } }, - { universal: { ssr: false, prerender: false } } - ]); -}); From 28f12278afcce8cc5dfac017aa63ac6db9902f49 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Thu, 29 May 2025 17:56:14 +0800 Subject: [PATCH 14/14] lint --- packages/kit/src/exports/vite/static_analysis/index.spec.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/kit/src/exports/vite/static_analysis/index.spec.js b/packages/kit/src/exports/vite/static_analysis/index.spec.js index fcfa477a829b..6c94431b6fb6 100644 --- a/packages/kit/src/exports/vite/static_analysis/index.spec.js +++ b/packages/kit/src/exports/vite/static_analysis/index.spec.js @@ -1,7 +1,5 @@ import { expect, test } from 'vitest'; -import { create_node_analyser, statically_analyse_page_options } from './index.js'; -import { fileURLToPath } from 'node:url'; -import path from 'node:path'; +import { statically_analyse_page_options } from './index.js'; test.each([ [