feat(nuxt): check schema/kit versions when loading nuxt (#27224)

This commit is contained in:
Julien Huang 2024-05-21 10:18:36 +02:00 committed by GitHub
parent 9a33892cec
commit b4002f37d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 90 additions and 1 deletions

View File

@ -15,6 +15,10 @@ Discover all Nuxt Kit utilities.
You can install the latest Nuxt Kit by adding it to the `dependencies` section of your `package.json`. However, please consider always explicitly installing the `@nuxt/kit` package even if it is already installed by Nuxt.
::note
`@nuxt/kit` and `@nuxt/schema` are key dependencies for Nuxt. If you are installing it separately, make sure that the versions of `@nuxt/kit` and `@nuxt/schema` are equal to or greater than your `nuxt` version to avoid any unexpected behavior.
::
```json [package.json]
{
"dependencies": {

View File

@ -99,6 +99,7 @@
"pkg-types": "^1.1.1",
"radix3": "^1.1.2",
"scule": "^1.3.0",
"semver": "^7.6.2",
"std-env": "^3.7.0",
"strip-literal": "^2.1.0",
"ufo": "^1.5.3",

View File

@ -13,6 +13,7 @@ import fse from 'fs-extra'
import { withTrailingSlash, withoutLeadingSlash } from 'ufo'
import defu from 'defu'
import { gte } from 'semver'
import pagesModule from '../pages/module'
import metaModule from '../head/module'
import componentsModule from '../components/module'
@ -63,6 +64,11 @@ const nightlies = {
'@nuxt/kit': '@nuxt/kit-nightly',
}
const keyDependencies = [
'@nuxt/kit',
'@nuxt/schema',
]
async function initNuxt (nuxt: Nuxt) {
// Register user hooks
for (const config of nuxt.options._layers.map(layer => layer.config).reverse()) {
@ -616,6 +622,8 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
const nuxt = createNuxt(options)
await Promise.all(keyDependencies.map(dependency => checkDependencyVersion(dependency, nuxt._version)))
// We register hooks layer-by-layer so any overrides need to be registered separately
if (opts.overrides?.hooks) {
nuxt.hooks.addHooks(opts.overrides.hooks)
@ -632,4 +640,15 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
return nuxt
}
async function checkDependencyVersion (name: string, nuxtVersion: string): Promise<void> {
const path = await resolvePath(name).catch(() => null)
if (!path) { return }
const { version } = await readPackageJSON(path)
if (version && gte(nuxtVersion, version)) {
console.warn(`[nuxt] Expected \`${name}\` to be at least \`${nuxtVersion}\` but got \`${version}\`. This might lead to unexpected behavior. Check your package.json or refresh your lockfile.`)
}
}
const RESTART_RE = /^(?:app|error|app\.config)\.(?:js|ts|mjs|jsx|tsx|vue)$/i

View File

@ -1,11 +1,32 @@
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { normalize } from 'pathe'
import { withoutTrailingSlash } from 'ufo'
import { readPackageJSON } from 'pkg-types'
import { inc } from 'semver'
import { loadNuxt } from '../src'
import { version } from '../package.json'
const repoRoot = withoutTrailingSlash(normalize(fileURLToPath(new URL('../../../', import.meta.url))))
vi.stubGlobal('console', {
...console,
error: vi.fn(console.error),
warn: vi.fn(console.warn),
})
vi.mock('pkg-types', async (og) => {
const originalPkgTypes = (await og<typeof import('pkg-types')>())
return {
...originalPkgTypes,
readPackageJSON: vi.fn(originalPkgTypes.readPackageJSON),
}
})
afterEach(() => {
vi.clearAllMocks()
})
describe('loadNuxt', () => {
it('respects hook overrides', async () => {
let hookRan = false
@ -24,3 +45,44 @@ describe('loadNuxt', () => {
expect(hookRan).toBe(true)
})
})
describe('dependency mismatch', () => {
it('expect mismatched dependency to log a warning', async () => {
vi.mocked(readPackageJSON).mockReturnValue(Promise.resolve({
version: '3.0.0',
}))
const nuxt = await loadNuxt({
cwd: repoRoot,
})
expect(console.warn).toHaveBeenCalledWith(`[nuxt] Expected \`@nuxt/kit\` to be at least \`${version}\` but got \`3.0.0\`. This might lead to unexpected behavior. Check your package.json or refresh your lockfile.`)
expect(console.warn).toHaveBeenCalledWith(`[nuxt] Expected \`@nuxt/schema\` to be at least \`${version}\` but got \`3.0.0\`. This might lead to unexpected behavior. Check your package.json or refresh your lockfile.`)
vi.mocked(readPackageJSON).mockRestore()
await nuxt.close()
})
it.each([
{
name: 'nuxt version is lower',
depVersion: inc(version, 'minor'),
},
{
name: 'version matches',
depVersion: version,
},
])('expect no warning when $name.', async ({ depVersion }) => {
vi.mocked(readPackageJSON).mockReturnValue(Promise.resolve({
depVersion,
}))
const nuxt = await loadNuxt({
cwd: repoRoot,
})
expect(console.warn).not.toHaveBeenCalled()
await nuxt.close()
vi.mocked(readPackageJSON).mockRestore()
})
})

View File

@ -369,6 +369,9 @@ importers:
scule:
specifier: ^1.3.0
version: 1.3.0
semver:
specifier: ^7.6.2
version: 7.6.2
std-env:
specifier: ^3.7.0
version: 3.7.0