Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(nuxt): run page meta plugin on all pages (and only pages) #20628

Merged
merged 2 commits into from May 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 1 addition & 4 deletions packages/nuxt/src/pages/module.ts
Expand Up @@ -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))
Expand Down
27 changes: 1 addition & 26 deletions packages/nuxt/src/pages/page-meta.ts
Expand Up @@ -10,7 +10,6 @@ import MagicString from 'magic-string'
import { isAbsolute, normalize } from 'pathe'

export interface PageMetaPluginOptions {
dirs: Array<string | RegExp>
dev?: boolean
sourcemap?: boolean
}
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
10 changes: 10 additions & 0 deletions 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 {
Expand Down Expand Up @@ -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')
}
}
4 changes: 2 additions & 2 deletions packages/schema/src/config/build.ts
Expand Up @@ -170,15 +170,15 @@ 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']
}
)
},
client: {
$resolve: async (val, get) => defu(val || {},
await get('dev') ? {} : {
vue: ['onServerPrefetch', 'onRenderTracked', 'onRenderTriggered'],
'#app': ['definePayloadReducer']
'#app': ['definePayloadReducer', 'definePageMeta']
}
)
}
Expand Down
5 changes: 5 additions & 0 deletions test/basic.test.ts
Expand Up @@ -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)
Expand Down
19 changes: 19 additions & 0 deletions 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')
})
})
}
})
17 changes: 17 additions & 0 deletions test/fixtures/basic/modules/runtime/page.vue
@@ -0,0 +1,17 @@
<script setup lang="ts">
import { setResponseHeader } from 'h3'

definePageMeta({
value: 'added in pages:extend'
})

if (process.server) {
setResponseHeader(useRequestEvent(), 'x-extend', useRoute().meta.value as string)
}
</script>

<template>
<div>
added in pages:extend
</div>
</template>
5 changes: 5 additions & 0 deletions test/fixtures/minimal/app.vue
@@ -1,6 +1,11 @@
<script setup lang="ts">
import { componentNames } from '#components'
console.log(componentNames)
// @ts-expect-error this is not usable outside a pages directory
definePageMeta({
// this should be fully tree-shaken out
title: 'jet common fruit chose bright planning exercise herself position wealth stiff known prepare listen leader eleven found boat dollar eye come author won thought pony biggest feel organized die vast class ask cost ball wrong chicken origin model little properly dangerous dull corner jar mighty solution pilot city locate guide gradually affect curve about snake single silly against fireplace money another involved origin sport where thin stop question go stretch although arrow rush mixture fallen power pay fifteen layers play slightly heavy built needed sing sentence diagram quarter yesterday list faster been having construction curious shoe'
})
</script>

<template>
Expand Down