diff --git a/packages/nuxt/src/pages/module.ts b/packages/nuxt/src/pages/module.ts index b19e528e1e4d..11638b1c2113 100644 --- a/packages/nuxt/src/pages/module.ts +++ b/packages/nuxt/src/pages/module.ts @@ -151,10 +151,7 @@ export default defineNuxtModule({ // Extract macros from pages const pageMetaOptions: PageMetaPluginOptions = { dev: nuxt.options.dev, - sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client, - dirs: nuxt.options._layers.map( - layer => resolve(layer.config.srcDir, layer.config.dir?.pages || 'pages') - ) + sourcemap: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client } nuxt.hook('modules:done', () => { addVitePlugin(() => PageMetaPlugin.vite(pageMetaOptions)) diff --git a/packages/nuxt/src/pages/page-meta.ts b/packages/nuxt/src/pages/page-meta.ts index f970d157bcd6..7563b436fab8 100644 --- a/packages/nuxt/src/pages/page-meta.ts +++ b/packages/nuxt/src/pages/page-meta.ts @@ -10,7 +10,6 @@ import MagicString from 'magic-string' import { isAbsolute, normalize } from 'pathe' export interface PageMetaPluginOptions { - dirs: Array dev?: boolean sourcemap?: boolean } @@ -42,11 +41,7 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) => const query = parseMacroQuery(id) id = normalize(id) - const isPagesDir = options.dirs.some(dir => typeof dir === 'string' ? id.startsWith(dir) : dir.test(id)) - if (!isPagesDir && !query.macro) { return false } - - const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href)) - return /\.(m?[jt]sx?|vue)/.test(pathname) + return !!query.macro }, transform (code, id) { const query = parseMacroQuery(id) @@ -66,26 +61,6 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) => const hasMacro = code.match(/\bdefinePageMeta\s*\(\s*/) - // Remove any references to the macro from our pages - if (!query.macro) { - if (hasMacro) { - walk(this.parse(code, { - sourceType: 'module', - ecmaVersion: 'latest' - }) as Node, { - enter (_node) { - if (_node.type !== 'CallExpression' || (_node as CallExpression).callee.type !== 'Identifier') { return } - const node = _node as CallExpression & { start: number, end: number } - const name = 'name' in node.callee && node.callee.name - if (name === 'definePageMeta') { - s.overwrite(node.start, node.end, 'false && {}') - } - } - }) - } - return result() - } - const imports = findStaticImports(code) // [vite] Re-export any script imports diff --git a/packages/nuxt/src/pages/runtime/composables.ts b/packages/nuxt/src/pages/runtime/composables.ts index abe492a46a5c..5c3db581aee2 100644 --- a/packages/nuxt/src/pages/runtime/composables.ts +++ b/packages/nuxt/src/pages/runtime/composables.ts @@ -1,5 +1,7 @@ import type { KeepAliveProps, TransitionProps, UnwrapRef } from 'vue' +import { getCurrentInstance } from 'vue' import type { RouteLocationNormalized, RouteLocationNormalizedLoaded, RouteRecordRedirectOption } from 'vue-router' +import { useRoute } from 'vue-router' import type { NuxtError } from '#app' export interface PageMeta { @@ -51,6 +53,14 @@ const warnRuntimeUsage = (method: string) => // eslint-disable-next-line @typescript-eslint/no-unused-vars export const definePageMeta = (meta: PageMeta): void => { if (process.dev) { + const component = getCurrentInstance()?.type + try { + const isRouteComponent = component && useRoute().matched.some(p => Object.values(p.components || {}).includes(component)) + if (isRouteComponent) { + // don't warn if it's being used in a route component + return + } + } catch {} warnRuntimeUsage('definePageMeta') } } diff --git a/packages/schema/src/config/build.ts b/packages/schema/src/config/build.ts index c905fae4ce81..d0e0c67b7c38 100644 --- a/packages/schema/src/config/build.ts +++ b/packages/schema/src/config/build.ts @@ -170,7 +170,7 @@ export default defineUntypedSchema({ $resolve: async (val, get) => defu(val || {}, await get('dev') ? {} : { vue: ['onBeforeMount', 'onMounted', 'onBeforeUpdate', 'onRenderTracked', 'onRenderTriggered', 'onActivated', 'onDeactivated', 'onBeforeUnmount'], - '#app': ['definePayloadReviver'] + '#app': ['definePayloadReviver', 'definePageMeta'] } ) }, @@ -178,7 +178,7 @@ export default defineUntypedSchema({ $resolve: async (val, get) => defu(val || {}, await get('dev') ? {} : { vue: ['onServerPrefetch', 'onRenderTracked', 'onRenderTriggered'], - '#app': ['definePayloadReducer'] + '#app': ['definePayloadReducer', 'definePageMeta'] } ) } diff --git a/test/basic.test.ts b/test/basic.test.ts index 8f15f25096f3..af4a2f0fc6bd 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -113,6 +113,11 @@ describe('pages', () => { expect(headers.get('location')).toEqual('/') }) + it('includes page metadata from pages added in pages:extend hook', async () => { + const res = await fetch('/page-extend') + expect(res.headers.get('x-extend')).toEqual('added in pages:extend') + }) + it('validates routes', async () => { const { status, headers } = await fetch('/forbidden') expect(status).toEqual(404) diff --git a/test/fixtures/basic/modules/page-extend.ts b/test/fixtures/basic/modules/page-extend.ts new file mode 100644 index 000000000000..1f794eeee60a --- /dev/null +++ b/test/fixtures/basic/modules/page-extend.ts @@ -0,0 +1,19 @@ +import { createResolver, defineNuxtModule, useNuxt } from 'nuxt/kit' + +export default defineNuxtModule({ + meta: { + name: 'page-extend' + }, + setup () { + const nuxt = useNuxt() + const resolver = createResolver(import.meta.url) + + nuxt.hook('pages:extend', (pages) => { + pages.push({ + name: 'page-extend', + path: '/page-extend', + file: resolver.resolve('./runtime/page.vue') + }) + }) + } +}) diff --git a/test/fixtures/basic/modules/runtime/page.vue b/test/fixtures/basic/modules/runtime/page.vue new file mode 100644 index 000000000000..5174b019cb65 --- /dev/null +++ b/test/fixtures/basic/modules/runtime/page.vue @@ -0,0 +1,17 @@ + + + diff --git a/test/fixtures/minimal/app.vue b/test/fixtures/minimal/app.vue index b75ed9fa6767..b112b78c63e4 100644 --- a/test/fixtures/minimal/app.vue +++ b/test/fixtures/minimal/app.vue @@ -1,6 +1,11 @@