diff --git a/packages/nuxt/src/head/module.ts b/packages/nuxt/src/head/module.ts index a8dcccbdae..44a58b588c 100644 --- a/packages/nuxt/src/head/module.ts +++ b/packages/nuxt/src/head/module.ts @@ -1,17 +1,11 @@ import { resolve } from 'pathe' import { addPlugin, addTemplate, defineNuxtModule } from '@nuxt/kit' -import defu from 'defu' import { distDir } from '../dirs' -import type { MetaObject } from './runtime' export default defineNuxtModule({ meta: { name: 'meta' }, - defaults: { - charset: 'utf-8', - viewport: 'width=device-width, initial-scale=1' - }, setup (options, nuxt) { const runtimeDir = nuxt.options.alias['#head'] || resolve(distDir, 'head/runtime') @@ -21,17 +15,10 @@ export default defineNuxtModule({ // Add #head alias nuxt.options.alias['#head'] = runtimeDir - // Global meta -for Bridge, this is necessary to repeat here - // and in packages/schema/src/config/_app.ts - const globalMeta: MetaObject = defu(nuxt.options.app.head, { - charset: options.charset, - viewport: options.viewport - }) - // Add global meta configuration addTemplate({ filename: 'meta.config.mjs', - getContents: () => 'export default ' + JSON.stringify({ globalMeta }) + getContents: () => 'export default ' + JSON.stringify({ globalMeta: nuxt.options.app.head }) }) // Add generic plugin diff --git a/packages/schema/src/config/_app.ts b/packages/schema/src/config/_app.ts index ff3606c7b4..2887a0ab59 100644 --- a/packages/schema/src/config/_app.ts +++ b/packages/schema/src/config/_app.ts @@ -105,15 +105,23 @@ export default { */ head: { $resolve: (val, get) => { - return defu(val, get('meta'), { - charset: 'utf-8', - viewport: 'width=device-width, initial-scale=1', + const resolved = defu(val, get('meta'), { meta: [], link: [], style: [], script: [], noscript: [] }) + + resolved.charset = resolved.charset ?? resolved.meta.find(m => m.charset)?.charset ?? 'utf-8' + resolved.viewport = resolved.viewport ?? resolved.meta.find(m => m.name === 'viewport')?.content ?? 'width=device-width, initial-scale=1' + resolved.meta = resolved.meta.filter(m => m && m.name !== 'viewport' && !m.charset) + resolved.link = resolved.link.filter(Boolean) + resolved.style = resolved.style.filter(Boolean) + resolved.script = resolved.script.filter(Boolean) + resolved.noscript = resolved.noscript.filter(Boolean) + + return resolved } }, }, diff --git a/test/basic.test.ts b/test/basic.test.ts index f2e86d8f4a..a361730843 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -138,6 +138,9 @@ describe('head tags', () => { expect(headHtml).toContain('Using a dynamic component - Title Template Fn Change') expect(headHtml).not.toContain('') expect(headHtml).toContain('') + expect(headHtml.match('meta charset').length).toEqual(1) + expect(headHtml).toContain('') + expect(headHtml.match('meta name="viewport"').length).toEqual(1) expect(headHtml).not.toContain('') expect(headHtml).toContain('') expect(headHtml).toMatch(/]*class="html-attrs-test"/) diff --git a/test/fixtures/basic/nuxt.config.ts b/test/fixtures/basic/nuxt.config.ts index ed29626bc2..331e50799a 100644 --- a/test/fixtures/basic/nuxt.config.ts +++ b/test/fixtures/basic/nuxt.config.ts @@ -2,6 +2,13 @@ import { defineNuxtConfig } from 'nuxt' import { addComponent } from '@nuxt/kit' export default defineNuxtConfig({ + app: { + head: { + charset: 'utf-8', + link: [undefined], + meta: [{ name: 'viewport', content: 'width=1024, initial-scale=1' }, { charset: 'utf-8' }] + } + }, buildDir: process.env.NITRO_BUILD_DIR, builder: process.env.TEST_WITH_WEBPACK ? 'webpack' : 'vite', extends: [