fix(nuxt): deduplicate app.head arrays (#27480)

This commit is contained in:
Daniel Roe 2024-06-07 15:24:56 +01:00 committed by GitHub
parent 5785332626
commit 34ea5ae2f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 30 additions and 0 deletions

View File

@ -7,6 +7,7 @@ import { resolvePath as _resolvePath } from 'mlly'
import type { Nuxt, NuxtHooks, NuxtModule, NuxtOptions, RuntimeConfig } from 'nuxt/schema' import type { Nuxt, NuxtHooks, NuxtModule, NuxtOptions, RuntimeConfig } from 'nuxt/schema'
import type { PackageJson } from 'pkg-types' import type { PackageJson } from 'pkg-types'
import { readPackageJSON, resolvePackageJSON } from 'pkg-types' import { readPackageJSON, resolvePackageJSON } from 'pkg-types'
import { hash } from 'ohash'
import escapeRE from 'escape-string-regexp' import escapeRE from 'escape-string-regexp'
import fse from 'fs-extra' import fse from 'fs-extra'
@ -583,6 +584,11 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
options.appDir = options.alias['#app'] = resolve(distDir, 'app') options.appDir = options.alias['#app'] = resolve(distDir, 'app')
options._majorVersion = 3 options._majorVersion = 3
// De-duplicate key arrays
for (const key in options.app.head || {}) {
options.app.head[key as 'link'] = deduplicateArray(options.app.head[key as 'link'])
}
// Nuxt DevTools only works for Vite // Nuxt DevTools only works for Vite
if (options.builder === '@nuxt/vite-builder') { if (options.builder === '@nuxt/vite-builder') {
const isDevToolsEnabled = typeof options.devtools === 'boolean' const isDevToolsEnabled = typeof options.devtools === 'boolean'
@ -668,3 +674,18 @@ async function checkDependencyVersion (name: string, nuxtVersion: string): Promi
} }
const RESTART_RE = /^(?:app|error|app\.config)\.(?:js|ts|mjs|jsx|tsx|vue)$/i const RESTART_RE = /^(?:app|error|app\.config)\.(?:js|ts|mjs|jsx|tsx|vue)$/i
function deduplicateArray<T = unknown> (maybeArray: T): T {
if (!Array.isArray(maybeArray)) { return maybeArray }
const fresh = []
const hashes = new Set<string>()
for (const item of maybeArray) {
const _hash = hash(item)
if (!hashes.has(_hash)) {
hashes.add(_hash)
fresh.push(item)
}
}
return fresh as T
}

View File

@ -64,6 +64,7 @@ describe('route rules', () => {
expect(headHtml).toContain('<meta name="description" content="Nuxt Fixture">') expect(headHtml).toContain('<meta name="description" content="Nuxt Fixture">')
expect(headHtml).toContain('<meta charset="utf-8">') expect(headHtml).toContain('<meta charset="utf-8">')
expect(headHtml).toContain('<meta name="viewport" content="width=1024, initial-scale=1">') expect(headHtml).toContain('<meta name="viewport" content="width=1024, initial-scale=1">')
expect(headHtml.match(/<meta name="viewport" content="width=1024, initial-scale=1">/g)).toHaveLength(1)
const { script, attrs } = parseData(headHtml) const { script, attrs } = parseData(headHtml)
expect(script.serverRendered).toEqual(false) expect(script.serverRendered).toEqual(false)

View File

@ -1,3 +1,11 @@
export default defineNuxtConfig({ export default defineNuxtConfig({
modules: [undefined], modules: [undefined],
app: {
head: {
meta: [
{ name: 'viewport', content: 'width=1024, initial-scale=1' },
{ charset: 'utf-8' },
],
},
},
}) })