diff --git a/packages/nuxt3/src/app/plugins/head.ts b/packages/nuxt3/src/app/plugins/head.ts deleted file mode 100644 index 3f296b23e8..0000000000 --- a/packages/nuxt3/src/app/plugins/head.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Plugin } from 'nuxt/app' -import { createHead, renderHeadToString } from '@vueuse/head' - -export default function head (nuxt) { - const { app, ssrContext } = nuxt - const head = createHead() - - app.use(head) - - if (process.server) { - ssrContext.head = () => renderHeadToString(head) - } -} diff --git a/packages/nuxt3/src/app/plugins/head/head.ts b/packages/nuxt3/src/app/plugins/head/head.ts new file mode 100644 index 0000000000..22ba9249e7 --- /dev/null +++ b/packages/nuxt3/src/app/plugins/head/head.ts @@ -0,0 +1,56 @@ +import { defineComponent } from '@vue/runtime-core' +import { useHead, HeadObject } from '@vueuse/head' + +type MappedProps> = { + [P in keyof T]: { type: () => T[P] } +} + +const props: MappedProps = { + base: { type: Object }, + bodyAttrs: { type: Object }, + htmlAttrs: { type: Object }, + link: { type: Array }, + meta: { type: Array }, + script: { type: Array }, + style: { type: Array }, + title: { type: String } +} + +export const Head = defineComponent({ + props, + setup (props, { slots }) { + useHead(() => props) + + return () => slots.default?.() + } +}) + +const createHeadComponent = (prop: keyof typeof props, isArray = false) => + defineComponent({ + setup (_props, { attrs, slots }) { + useHead(() => ({ + [prop]: isArray ? [attrs] : attrs + })) + + return () => slots.default?.() + } + }) + +const createHeadComponentFromSlot = (prop: keyof typeof props) => + defineComponent({ + setup (_props, { slots }) { + useHead(() => ({ + [prop]: slots.default?.()[0]?.children + })) + + return () => null + } + }) + +export const Html = createHeadComponent('htmlAttrs') +export const Body = createHeadComponent('bodyAttrs') +export const Title = createHeadComponentFromSlot('title') +export const Meta = createHeadComponent('meta', true) +export const Link = createHeadComponent('link', true) +export const Script = createHeadComponent('script', true) +export const Style = createHeadComponent('style', true) diff --git a/packages/nuxt3/src/app/plugins/head/index.ts b/packages/nuxt3/src/app/plugins/head/index.ts new file mode 100644 index 0000000000..b18e49f1f9 --- /dev/null +++ b/packages/nuxt3/src/app/plugins/head/index.ts @@ -0,0 +1,23 @@ +import type { Plugin } from 'nuxt/app' +import { createHead, renderHeadToString } from '@vueuse/head' +import { Head, Html, Body, Title, Meta, Link, Script, Style } from './head' + +export default function head (nuxt) { + const { app, ssrContext } = nuxt + const head = createHead() + + app.use(head) + + app.component('NuxtHead', Head) + app.component('NuxtHtml', Html) + app.component('NuxtBody', Body) + app.component('NuxtTitle', Title) + app.component('NuxtMeta', Meta) + app.component('NuxtHeadLink', Link) + app.component('NuxtScript', Script) + app.component('NuxtStyle', Style) + + if (process.server) { + ssrContext.head = () => renderHeadToString(head) + } +}