From 19145386e3388d31d2db071a6dea0885ef18c8cf Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Tue, 5 Sep 2023 12:25:46 +0200 Subject: [PATCH] fix(nuxt): resolve head instance from Nuxt app (#22973) --- docs/1.getting-started/4.styling.md | 2 +- docs/1.getting-started/5.seo-meta.md | 2 +- docs/3.api/1.composables/use-head-safe.md | 2 +- docs/3.api/1.composables/use-head.md | 2 +- packages/nuxt/package.json | 6 +- .../nuxt/src/head/runtime/plugins/unhead.ts | 9 ++- packages/schema/package.json | 2 +- pnpm-lock.yaml | 70 ++++++++++--------- test/bundle.test.ts | 8 +-- 9 files changed, 57 insertions(+), 46 deletions(-) diff --git a/docs/1.getting-started/4.styling.md b/docs/1.getting-started/4.styling.md index 9178f331a9..2059a445a1 100644 --- a/docs/1.getting-started/4.styling.md +++ b/docs/1.getting-started/4.styling.md @@ -129,7 +129,7 @@ useHead({ }) ``` -Nuxt uses `unhead` under the hood, and you can refer to its full documentation [here](https://unhead.harlanzw.com/). +Nuxt uses `unhead` under the hood, and you can refer to its full documentation [here](https://unhead.unjs.io/). ### Modifying The Rendered Head With A Nitro Plugin diff --git a/docs/1.getting-started/5.seo-meta.md b/docs/1.getting-started/5.seo-meta.md index 5a9a336e67..74cc43861f 100644 --- a/docs/1.getting-started/5.seo-meta.md +++ b/docs/1.getting-started/5.seo-meta.md @@ -36,7 +36,7 @@ Shortcuts are available to make configuration easier: `charset` and `viewport`. ## `useHead` The [`useHead`](/docs/api/composables/use-head) composable function allows you to manage your head tags in a programmatic and reactive way, -powered by [Unhead](https://unhead.harlanzw.com/). +powered by [Unhead](https://unhead.unjs.io/). As with all composables, it can only be used with a components `setup` and lifecycle hooks. diff --git a/docs/3.api/1.composables/use-head-safe.md b/docs/3.api/1.composables/use-head-safe.md index 5f44f93a7f..62dc5c2f3e 100644 --- a/docs/3.api/1.composables/use-head-safe.md +++ b/docs/3.api/1.composables/use-head-safe.md @@ -24,7 +24,7 @@ useHeadSafe({ // ``` -Read more on [unhead documentation](https://unhead.harlanzw.com/guide/composables/use-head-safe). +Read more on [unhead documentation](https://unhead.unjs.io/usage/composables/use-head-safe). ## Type diff --git a/docs/3.api/1.composables/use-head.md b/docs/3.api/1.composables/use-head.md index 71475a6604..6a03e5ada0 100644 --- a/docs/3.api/1.composables/use-head.md +++ b/docs/3.api/1.composables/use-head.md @@ -4,7 +4,7 @@ description: useHead customizes the head properties of individual pages of your # useHead -The [`useHead`](/docs/api/composables/use-head) composable function allows you to manage your head tags in a programmatic and reactive way, powered by [Unhead](https://unhead.harlanzw.com/). If the data comes from a user or other untrusted source, we recommend you check out [`useHeadSafe`](/docs/api/composables/use-head-safe) +The [`useHead`](/docs/api/composables/use-head) composable function allows you to manage your head tags in a programmatic and reactive way, powered by [Unhead](https://unhead.unjs.io/). If the data comes from a user or other untrusted source, we recommend you check out [`useHeadSafe`](/docs/api/composables/use-head-safe) :ReadMore{link="/docs/getting-started/seo-meta"} diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index c2d5de5467..d9accd9039 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -58,9 +58,9 @@ "@nuxt/telemetry": "^2.4.1", "@nuxt/ui-templates": "^1.3.1", "@nuxt/vite-builder": "workspace:../vite", - "@unhead/dom": "^1.3.9", - "@unhead/ssr": "^1.3.9", - "@unhead/vue": "^1.3.9", + "@unhead/dom": "^1.5.2", + "@unhead/ssr": "^1.5.2", + "@unhead/vue": "^1.5.2", "@vue/shared": "^3.3.4", "acorn": "8.10.0", "c12": "^1.4.2", diff --git a/packages/nuxt/src/head/runtime/plugins/unhead.ts b/packages/nuxt/src/head/runtime/plugins/unhead.ts index 64394f402b..2b691be843 100644 --- a/packages/nuxt/src/head/runtime/plugins/unhead.ts +++ b/packages/nuxt/src/head/runtime/plugins/unhead.ts @@ -1,18 +1,25 @@ -import { createHead as createClientHead } from '@unhead/vue' +import { createHead as createClientHead, setHeadInjectionHandler } from '@unhead/vue' import { renderDOMHead } from '@unhead/dom' import { defineNuxtPlugin } from '#app/nuxt' +import { useNuxtApp } from '#app' // @ts-expect-error virtual file import unheadPlugins from '#build/unhead-plugins.mjs' export default defineNuxtPlugin({ name: 'nuxt:head', + enforce: 'pre', setup (nuxtApp) { const head = import.meta.server ? nuxtApp.ssrContext!.head : createClientHead({ plugins: unheadPlugins }) + // allow useHead to be used outside a Vue context but within a Nuxt context + setHeadInjectionHandler( + // need a fresh instance of the nuxt app to avoid parallel requests interfering with each other + () => useNuxtApp().vueApp._context.provides.usehead + ) // nuxt.config appHead is set server-side within the renderer nuxtApp.vueApp.use(head) diff --git a/packages/schema/package.json b/packages/schema/package.json index f8618b6a96..c3683d4d56 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -32,7 +32,7 @@ "@types/file-loader": "5.0.1", "@types/pug": "2.0.6", "@types/sass-loader": "8.0.5", - "@unhead/schema": "1.3.9", + "@unhead/schema": "1.5.2", "@vitejs/plugin-vue": "4.3.3", "@vitejs/plugin-vue-jsx": "3.0.2", "@vue/compiler-core": "3.3.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8fd2669033..5cc2e13fbb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -264,14 +264,14 @@ importers: specifier: ^14.18.0 || >=16.10.0 version: 18.17.11 '@unhead/dom': - specifier: ^1.3.9 - version: 1.3.9 + specifier: ^1.5.2 + version: 1.5.2 '@unhead/ssr': - specifier: ^1.3.9 - version: 1.3.9 + specifier: ^1.5.2 + version: 1.5.2 '@unhead/vue': - specifier: ^1.3.9 - version: 1.3.9(vue@3.3.4) + specifier: ^1.5.2 + version: 1.5.2(vue@3.3.4) '@vue/shared': specifier: ^3.3.4 version: 3.3.4 @@ -479,8 +479,8 @@ importers: specifier: 8.0.5 version: 8.0.5 '@unhead/schema': - specifier: 1.3.9 - version: 1.3.9 + specifier: 1.5.2 + version: 1.5.2 '@vitejs/plugin-vue': specifier: 4.3.3 version: 4.3.3(vite@4.4.9)(vue@3.3.4) @@ -2526,6 +2526,7 @@ packages: dependencies: is-glob: 4.0.3 micromatch: 4.0.5 + napi-wasm: 1.1.0 bundledDependencies: - napi-wasm @@ -3166,41 +3167,41 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@unhead/dom@1.3.9: - resolution: {integrity: sha512-bTbPFjXjmk8MC0cBC+7Bgf0Mcw62gsE2XqOhMH/qQo6NP4vR2XGxqy054Y7MGurznR1JVAqxUiU3cR/oxWFk3g==} + /@unhead/dom@1.5.2: + resolution: {integrity: sha512-lEDxqFSGb3Ye1TD7Kr3kRsMOSv5R2ldJ/uYh2mRFungYfv3TjOUfxvGgMs2vRjatPDpV4IUWr3E1BASayN8CnA==} dependencies: - '@unhead/schema': 1.3.9 - '@unhead/shared': 1.3.9 + '@unhead/schema': 1.5.2 + '@unhead/shared': 1.5.2 dev: false - /@unhead/schema@1.3.9: - resolution: {integrity: sha512-iIa0dczd2qTOxwYZbVR+iAKdlELnLTlKSFsN/YuJ/33sRi5VFa9D8TDBEPLec9gpcjB/bH0FhERfR4bb4UbRuA==} + /@unhead/schema@1.5.2: + resolution: {integrity: sha512-7nmcN332yuXzWPzzlqD/F/wOXTaIKn3cRaPxTkU+eJLNGmAsQ9i5p4P5x9AgduZD/NGbJG/h+wM+/cB0psMiKQ==} dependencies: hookable: 5.5.3 zhead: 2.0.10 - /@unhead/shared@1.3.9: - resolution: {integrity: sha512-lBXK1gzsg3XOnsOgYUVTT2RKOvM+AB0myDXkwQb0jsJB3Tc1qVOSz9JAOR+ZGrosSr7+Iv91+Fu/0E+knxaj2Q==} + /@unhead/shared@1.5.2: + resolution: {integrity: sha512-gHjquSnyJ9SOV20zxGffZP0t9mkBAHTGgFhUl9HB8FrL9tp4Jovjc01O0jn/NRNaBICsQBxDryj5lpuTHFIM9g==} dependencies: - '@unhead/schema': 1.3.9 + '@unhead/schema': 1.5.2 dev: false - /@unhead/ssr@1.3.9: - resolution: {integrity: sha512-FTt4IQOAxHiSfRM7IoJJiFnUEBH8CG5zkJOQ/LydG19QpYa9/AGOi4xvngeCr++1as51p2hWoRO6gPxSRhV8cA==} + /@unhead/ssr@1.5.2: + resolution: {integrity: sha512-wse2uOg2Fh+MM9unoM0T1Q/dYwmaNdUWzR4ovnMKvQ6K7HpzCJaETHLzbS5g/TXLRIFd7eA3mTQCnp0iPoaoYw==} dependencies: - '@unhead/schema': 1.3.9 - '@unhead/shared': 1.3.9 + '@unhead/schema': 1.5.2 + '@unhead/shared': 1.5.2 dev: false - /@unhead/vue@1.3.9(vue@3.3.4): - resolution: {integrity: sha512-rVAsRLBc+3Y//NRmr7vmRs5yhIf65jYSvcj0V5DtDfDwql7BbGgc3VIIEvY0+EjLQuNsS5kxwm78LSPCIl/3Xw==} + /@unhead/vue@1.5.2(vue@3.3.4): + resolution: {integrity: sha512-DkKJJfNmiwkq41PiNmPcONVdNN1wRp8KTHCCOnOBt1nAdhIAj83ykIdpkLGLseJTzy4C2efiR1lips/42ZsNTg==} peerDependencies: vue: '>=2.7 || >=3' dependencies: - '@unhead/schema': 1.3.9 - '@unhead/shared': 1.3.9 + '@unhead/schema': 1.5.2 + '@unhead/shared': 1.5.2 hookable: 5.5.3 - unhead: 1.3.9 + unhead: 1.5.2 vue: 3.3.4 dev: false @@ -7063,7 +7064,7 @@ packages: graceful-fs: 4.2.11 /jstransformer@1.0.0: - resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==} + resolution: {integrity: sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=} dependencies: is-promise: 2.2.2 promise: 7.3.1 @@ -7947,6 +7948,9 @@ packages: engines: {node: ^14 || ^16 || >=18} hasBin: true + /napi-wasm@1.1.0: + resolution: {integrity: sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg==} + /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} dev: true @@ -10206,7 +10210,7 @@ packages: engines: {node: '>=0.6'} /token-stream@1.0.0: - resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==} + resolution: {integrity: sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=} dev: false /totalist@1.1.0: @@ -10461,12 +10465,12 @@ packages: node-fetch-native: 1.4.0 pathe: 1.1.1 - /unhead@1.3.9: - resolution: {integrity: sha512-vzWZJW8l6dlNM5egJs3c7NMHWZ+iw2x7jCZtU2rrhwFINlKCaA3J42fvOeDxx6t5QR9dfZ96HF2AeNlCcPT+bQ==} + /unhead@1.5.2: + resolution: {integrity: sha512-KLsz9MCMEhVEeaI4YsoALnr4xk6k+xZ2JW9xjJxsae6AvHNTZQzRbavuPRQ3tIw2hIHoGetyPKiYjFteORNQMg==} dependencies: - '@unhead/dom': 1.3.9 - '@unhead/schema': 1.3.9 - '@unhead/shared': 1.3.9 + '@unhead/dom': 1.5.2 + '@unhead/schema': 1.5.2 + '@unhead/shared': 1.5.2 hookable: 5.5.3 dev: false diff --git a/test/bundle.test.ts b/test/bundle.test.ts index 9ea2358084..dd56092c01 100644 --- a/test/bundle.test.ts +++ b/test/bundle.test.ts @@ -19,7 +19,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM for (const outputDir of ['.output', '.output-inline']) { it('default client bundle size', async () => { const clientStats = await analyzeSizes('**/*.js', join(rootDir, outputDir, 'public')) - expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot('"95.5k"') + expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot('"95.9k"') expect(clientStats.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(` [ "_nuxt/entry.js", @@ -32,7 +32,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM const serverDir = join(rootDir, '.output/server') const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir) - expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"299k"') + expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"300k"') const modules = await analyzeSizes('node_modules/**/*', serverDir) expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"1822k"') @@ -71,10 +71,10 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM const serverDir = join(rootDir, '.output-inline/server') const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir) - expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"605k"') + expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"607k"') const modules = await analyzeSizes('node_modules/**/*', serverDir) - expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"70.6k"') + expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"71.0k"') const packages = modules.files .filter(m => m.endsWith('package.json'))