From cb7f30a1eaf20a80f6378a7b40adca9d4c9ac123 Mon Sep 17 00:00:00 2001 From: xjccc <546534045@qq.com> Date: Fri, 24 Jan 2025 22:40:08 +0800 Subject: [PATCH] fix(nuxt): deep clone extracted page meta (#30717) --- packages/nuxt/src/pages/utils.ts | 5 ++-- packages/nuxt/test/page-metadata.test.ts | 14 ++++++++- packages/nuxt/test/pages.test.ts | 38 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/packages/nuxt/src/pages/utils.ts b/packages/nuxt/src/pages/utils.ts index dc961ef089..73455bba4c 100644 --- a/packages/nuxt/src/pages/utils.ts +++ b/packages/nuxt/src/pages/utils.ts @@ -11,6 +11,7 @@ import { transform } from 'esbuild' import type { Property } from 'estree' import type { NuxtPage } from 'nuxt/schema' +import { klona } from 'klona' import { parseAndWalk, withLocations } from '../core/utils/parse' import { getLoader, uniqueBy } from '../core/utils' import { logger, toArray } from '../utils' @@ -215,7 +216,7 @@ export async function getRouteMeta (contents: string, absolutePath: string, extr } if (absolutePath in metaCache && metaCache[absolutePath]) { - return metaCache[absolutePath] + return klona(metaCache[absolutePath]) } const loader = getLoader(absolutePath) @@ -314,7 +315,7 @@ export async function getRouteMeta (contents: string, absolutePath: string, extr } metaCache[absolutePath] = extractedMeta - return extractedMeta + return klona(extractedMeta) } const COLON_RE = /:/g diff --git a/packages/nuxt/test/page-metadata.test.ts b/packages/nuxt/test/page-metadata.test.ts index 7c1faf0a08..e6486f01bf 100644 --- a/packages/nuxt/test/page-metadata.test.ts +++ b/packages/nuxt/test/page-metadata.test.ts @@ -1,6 +1,7 @@ -import { describe, expect, it } from 'vitest' +import { type MockedFunction, describe, expect, it, vi } from 'vitest' import { compileScript, parse } from '@vue/compiler-sfc' import * as Parser from 'acorn' +import { klona } from 'klona' import { transform as esbuildTransform } from 'esbuild' import { PageMetaPlugin } from '../src/pages/plugins/page-meta' import { getRouteMeta, normalizeRoutes } from '../src/pages/utils' @@ -8,6 +9,8 @@ import type { NuxtPage } from '../schema' const filePath = '/app/pages/index.vue' +vi.mock('klona', { spy: true }) + describe('page metadata', () => { it('should not extract metadata from empty files', async () => { expect(await getRouteMeta('', filePath)).toEqual({}) @@ -67,11 +70,20 @@ definePageMeta({ name: 'bar' }) }) it('should use and invalidate cache', async () => { + const _klona = klona as unknown as MockedFunction + _klona.mockImplementation(obj => obj) const fileContents = `` const meta = await getRouteMeta(fileContents, filePath) expect(meta === await getRouteMeta(fileContents, filePath)).toBeTruthy() expect(meta === await getRouteMeta(fileContents, '/app/pages/other.vue')).toBeFalsy() expect(meta === await getRouteMeta('' + fileContents, filePath)).toBeFalsy() + _klona.mockReset() + }) + + it('should not share state between page metadata', async () => { + const fileContents = `` + const meta = await getRouteMeta(fileContents, filePath) + expect(meta === await getRouteMeta(fileContents, filePath)).toBeFalsy() }) it('should extract serialisable metadata', async () => { diff --git a/packages/nuxt/test/pages.test.ts b/packages/nuxt/test/pages.test.ts index 2e53607bd1..ff8eb57c2c 100644 --- a/packages/nuxt/test/pages.test.ts +++ b/packages/nuxt/test/pages.test.ts @@ -836,3 +836,41 @@ describe('pages:pathToNitroGlob', () => { expect(pathToNitroGlob(path)).to.equal(expected) }) }) + +describe('page:extends', () => { + const DYNAMIC_META_KEY = '__nuxt_dynamic_meta_key' as const + it('should preserve distinct metadata for multiple routes referencing the same file', async () => { + const files: NuxtPage[] = [ + { path: 'home', file: `pages/index.vue` }, + { path: 'home1', file: `pages/index.vue`, meta: { test: true } }, + { path: 'home2', file: `pages/index.vue`, meta: { snap: true } }, + ] + const vfs = Object.fromEntries( + files.map(file => [file.file, ` + + `]), + ) as Record + await augmentPages(files, vfs) + expect(files).toEqual([ + { + path: 'home', + file: `pages/index.vue`, + meta: { [DYNAMIC_META_KEY]: new Set(['meta']) }, + }, + { + path: 'home1', + file: `pages/index.vue`, + meta: { [DYNAMIC_META_KEY]: new Set(['meta']), test: true }, + }, + { + path: 'home2', + file: `pages/index.vue`, + meta: { [DYNAMIC_META_KEY]: new Set(['meta']), snap: true }, + }, + ]) + }) +})