mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
refactor(nuxt)!: move head
option support into defineNuxtComponent
(#8901)
This commit is contained in:
parent
dfce660875
commit
2c2fbdffc9
@ -5,10 +5,10 @@ description: defineNuxtComponent() is a helper function for defining type safe c
|
|||||||
|
|
||||||
# `defineNuxtComponent`
|
# `defineNuxtComponent`
|
||||||
|
|
||||||
`defineNuxtComponent()` is a helper function for defining type safe Vue components using options API similar to [defineComponent()](https://vuejs.org/api/general.html#definecomponent). `defineNuxtComponent()` wrapper also adds support for `asyncData` component option.
|
`defineNuxtComponent()` is a helper function for defining type safe Vue components using options API similar to [defineComponent()](https://vuejs.org/api/general.html#definecomponent). `defineNuxtComponent()` wrapper also adds support for `asyncData` and `head` component options.
|
||||||
|
|
||||||
::alert{type=warning}
|
::alert{type=warning}
|
||||||
Options API support for `asyncData` may well change before the stable release of Nuxt 3.
|
Options API support for `asyncData` and `head` may well change before the stable release of Nuxt 3.
|
||||||
::
|
::
|
||||||
|
|
||||||
::Alert
|
::Alert
|
||||||
@ -34,3 +34,19 @@ export default defineNuxtComponent({
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `head()`
|
||||||
|
|
||||||
|
If you choose not to use `setup()` in your app, you can use the `head()` method within your component definition:
|
||||||
|
|
||||||
|
```vue [pages/index.vue]
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineNuxtComponent({
|
||||||
|
head(nuxtApp) {
|
||||||
|
return {
|
||||||
|
title: 'My site'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
@ -4,6 +4,9 @@ import { NuxtApp, useNuxtApp } from '../nuxt'
|
|||||||
import { useAsyncData } from './asyncData'
|
import { useAsyncData } from './asyncData'
|
||||||
import { useRoute } from './router'
|
import { useRoute } from './router'
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-restricted-paths
|
||||||
|
import { useHead } from '#head'
|
||||||
|
|
||||||
export const NuxtComponentIndicator = '__nuxt_component'
|
export const NuxtComponentIndicator = '__nuxt_component'
|
||||||
|
|
||||||
async function runLegacyAsyncData (res: Record<string, any> | Promise<Record<string, any>>, fn: (nuxtApp: NuxtApp) => Promise<Record<string, any>>) {
|
async function runLegacyAsyncData (res: Record<string, any> | Promise<Record<string, any>>, fn: (nuxtApp: NuxtApp) => Promise<Record<string, any>>) {
|
||||||
@ -25,7 +28,7 @@ export const defineNuxtComponent: typeof defineComponent =
|
|||||||
const { setup } = options
|
const { setup } = options
|
||||||
|
|
||||||
// Avoid wrapping if no options api is used
|
// Avoid wrapping if no options api is used
|
||||||
if (!setup && !options.asyncData) {
|
if (!setup && !options.asyncData && !options.head) {
|
||||||
return {
|
return {
|
||||||
[NuxtComponentIndicator]: true,
|
[NuxtComponentIndicator]: true,
|
||||||
...options
|
...options
|
||||||
@ -43,6 +46,11 @@ export const defineNuxtComponent: typeof defineComponent =
|
|||||||
promises.push(runLegacyAsyncData(res, options.asyncData))
|
promises.push(runLegacyAsyncData(res, options.asyncData))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.head) {
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
useHead(typeof options.head === 'function' ? () => options.head(nuxtApp) : options.head)
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.resolve(res)
|
return Promise.resolve(res)
|
||||||
.then(() => Promise.all(promises))
|
.then(() => Promise.all(promises))
|
||||||
.then(() => res)
|
.then(() => res)
|
||||||
|
@ -10,7 +10,7 @@ export type { PageMeta } from '../pages/runtime'
|
|||||||
// eslint-disable-next-line import/no-restricted-paths
|
// eslint-disable-next-line import/no-restricted-paths
|
||||||
export type { MetaObject } from '../head/runtime'
|
export type { MetaObject } from '../head/runtime'
|
||||||
// eslint-disable-next-line import/no-restricted-paths
|
// eslint-disable-next-line import/no-restricted-paths
|
||||||
export { useHead, useMeta } from '#head'
|
export { useHead } from '#head'
|
||||||
|
|
||||||
export const isVue2 = false
|
export const isVue2 = false
|
||||||
export const isVue3 = true
|
export const isVue3 = true
|
||||||
|
@ -29,9 +29,6 @@ export default defineNuxtModule({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add mixin plugin
|
|
||||||
addPlugin({ src: resolve(runtimeDir, 'mixin-plugin') })
|
|
||||||
|
|
||||||
// Add library specific plugin
|
// Add library specific plugin
|
||||||
addPlugin({ src: resolve(runtimeDir, 'lib/vueuse-head.plugin') })
|
addPlugin({ src: resolve(runtimeDir, 'lib/vueuse-head.plugin') })
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,3 @@ import { useNuxtApp } from '#app'
|
|||||||
export function useHead (meta: MaybeComputedRef<MetaObject>) {
|
export function useHead (meta: MaybeComputedRef<MetaObject>) {
|
||||||
useNuxtApp()._useHead(meta)
|
useNuxtApp()._useHead(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove useMeta support when Nuxt 3 is stable
|
|
||||||
/** @deprecated Please use new `useHead` composable instead */
|
|
||||||
export function useMeta (meta: MaybeComputedRef<MetaObject>) {
|
|
||||||
return useHead(meta)
|
|
||||||
}
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import { getCurrentInstance } from 'vue'
|
|
||||||
import { useHead } from './composables'
|
|
||||||
import { defineNuxtPlugin, useNuxtApp } from '#app'
|
|
||||||
|
|
||||||
const metaMixin = {
|
|
||||||
created () {
|
|
||||||
const instance = getCurrentInstance()
|
|
||||||
if (!instance) { return }
|
|
||||||
|
|
||||||
const options = instance.type
|
|
||||||
if (!options || !('head' in options)) { return }
|
|
||||||
|
|
||||||
const nuxtApp = useNuxtApp()
|
|
||||||
const source = typeof options.head === 'function'
|
|
||||||
? () => options.head(nuxtApp)
|
|
||||||
: options.head
|
|
||||||
|
|
||||||
useHead(source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineNuxtPlugin((nuxtApp) => {
|
|
||||||
nuxtApp.vueApp.mixin(metaMixin)
|
|
||||||
})
|
|
@ -5,8 +5,7 @@ const commonPresets: InlinePreset[] = [
|
|||||||
defineUnimportPreset({
|
defineUnimportPreset({
|
||||||
from: '#head',
|
from: '#head',
|
||||||
imports: [
|
imports: [
|
||||||
'useHead',
|
'useHead'
|
||||||
'useMeta'
|
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
// vue-demi (mocked)
|
// vue-demi (mocked)
|
||||||
|
@ -253,7 +253,6 @@ describe('head tags', () => {
|
|||||||
expect(headHtml).toContain('<meta name="description" content="overriding with an inline useHead call">')
|
expect(headHtml).toContain('<meta name="description" content="overriding with an inline useHead call">')
|
||||||
expect(headHtml).toMatch(/<html[^>]*class="html-attrs-test"/)
|
expect(headHtml).toMatch(/<html[^>]*class="html-attrs-test"/)
|
||||||
expect(headHtml).toMatch(/<body[^>]*class="body-attrs-test"/)
|
expect(headHtml).toMatch(/<body[^>]*class="body-attrs-test"/)
|
||||||
expect(headHtml).toContain('script>console.log("works with useMeta too")</script>')
|
|
||||||
expect(headHtml).toContain('<script src="https://a-body-appended-script.com" data-meta-body></script></body>')
|
expect(headHtml).toContain('<script src="https://a-body-appended-script.com" data-meta-body></script></body>')
|
||||||
|
|
||||||
const indexHtml = await $fetch('/')
|
const indexHtml = await $fetch('/')
|
||||||
|
@ -29,6 +29,7 @@ describe.skipIf(isWindows)('minimal nuxt application', () => {
|
|||||||
expect(stats.client.totalBytes).toBeLessThan(110000)
|
expect(stats.client.totalBytes).toBeLessThan(110000)
|
||||||
expect(stats.client.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
|
expect(stats.client.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
|
||||||
[
|
[
|
||||||
|
"_nuxt/composables.js",
|
||||||
"_nuxt/entry.js",
|
"_nuxt/entry.js",
|
||||||
"_nuxt/error-404.js",
|
"_nuxt/error-404.js",
|
||||||
"_nuxt/error-500.js",
|
"_nuxt/error-500.js",
|
||||||
|
45
test/fixtures/basic/pages/head.vue
vendored
45
test/fixtures/basic/pages/head.vue
vendored
@ -1,35 +1,32 @@
|
|||||||
<script setup>
|
|
||||||
const a = ref('')
|
|
||||||
|
|
||||||
useHead({
|
|
||||||
// title template function example
|
|
||||||
titleTemplate: title => `${title} - Title Template Fn Change`,
|
|
||||||
bodyAttrs: {
|
|
||||||
class: 'body-attrs-test'
|
|
||||||
},
|
|
||||||
script: [
|
|
||||||
{
|
|
||||||
src: 'https://a-body-appended-script.com',
|
|
||||||
body: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
meta: [{ name: 'description', content: 'first' }]
|
|
||||||
})
|
|
||||||
useHead({ meta: [{ charset: 'utf-16' }, { name: 'description', content: computed(() => `${a.value} with an inline useHead call`) }] })
|
|
||||||
useMeta({ script: [{ children: 'console.log("works with useMeta too")' }] })
|
|
||||||
a.value = 'overriding'
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default defineNuxtComponent({
|
||||||
head () {
|
head () {
|
||||||
return {
|
return {
|
||||||
htmlAttrs: {
|
htmlAttrs: {
|
||||||
class: 'html-attrs-test'
|
class: 'html-attrs-test'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
setup () {
|
||||||
|
const a = ref('')
|
||||||
|
useHead({
|
||||||
|
// title template function example
|
||||||
|
titleTemplate: title => `${title} - Title Template Fn Change`,
|
||||||
|
bodyAttrs: {
|
||||||
|
class: 'body-attrs-test'
|
||||||
|
},
|
||||||
|
script: [
|
||||||
|
{
|
||||||
|
src: 'https://a-body-appended-script.com',
|
||||||
|
body: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
meta: [{ name: 'description', content: 'first' }]
|
||||||
|
})
|
||||||
|
useHead({ meta: [{ charset: 'utf-16' }, { name: 'description', content: computed(() => `${a.value} with an inline useHead call`) }] })
|
||||||
|
a.value = 'overriding'
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
Loading…
Reference in New Issue
Block a user