Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

fix(nuxt): render head scripts that use body: true #6293

Merged
merged 9 commits into from
Aug 2, 2022
22 changes: 22 additions & 0 deletions docs/content/2.guide/2.features/4.head-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,28 @@ The `titleTemplate` can either be a string, where `%s` is replaced with the titl

Now, if you set the title to `My Page` with `useHead` on another page of your site, the title would appear as 'My Page - Site Title' in the browser tab. You could also pass `null` to default to the site title.

## Body Meta Tags

::StabilityEdge{title="Body Meta Tags"}
::

You can use the `body: true` option on the `link` and `script` meta tags to append them to the end of the `<body>` tag.

For example:

```vue
<script setup>
useHead({
script: [
{
src: 'https://third-party-script.com',
body: true
}
]
})
</script>
```

## Meta Components

Nuxt provides `<Title>`, `<Base>`, `<Script>`, `<Style>`, `<Meta>`, `<Link>`, `<Body>`, `<Html>` and `<Head>` components so that you can interact directly with your metadata within your component's template.
Expand Down
1 change: 1 addition & 0 deletions packages/nuxt/src/core/runtime/nitro/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export default eventHandler(async (event) => {
bodyAppend: normalizeChunks([
`<script>window.__NUXT__=${devalue(ssrContext.payload)}</script>`,
_rendered.renderScripts(),
// Note: bodyScripts may contain tags other than <script>
renderedMeta.bodyScripts
])
}
Expand Down
9 changes: 8 additions & 1 deletion packages/nuxt/src/head/runtime/lib/vueuse-head.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ export default defineNuxtPlugin((nuxtApp) => {
}

if (process.server) {
nuxtApp.ssrContext.renderMeta = () => renderHeadToString(head)
nuxtApp.ssrContext.renderMeta = () => {
const meta = renderHeadToString(head)
return {
...meta,
// resolves naming difference with NuxtMeta and @vueuse/head
bodyScripts: meta.bodyTags
}
}
}
})
1 change: 1 addition & 0 deletions test/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ describe('head tags', () => {
expect(headHtml).toMatch(/<html[^>]*class="html-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="true"></script></body>')

const indexHtml = await $fetch('/')
// should render charset by default
Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/basic/pages/head.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ useHead({
bodyAttrs: {
class: 'body-attrs-test'
},
script: [
{
src: 'https://a-body-appended-script.com',
body: true
}
],
meta: [{ name: 'description', content: 'first' }]
})
useHead({ charset: 'utf-16', meta: [{ name: 'description', content: computed(() => `${a.value} with an inline useHead call`) }] })
Expand Down