mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 07:05:11 +00:00
feat(kit, bridge): version constraint utils and checks (#442)
Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
parent
eb0332126e
commit
9503d62607
@ -1,5 +1,5 @@
|
|||||||
import { createRequire } from 'module'
|
import { createRequire } from 'module'
|
||||||
import { defineNuxtModule, installModule } from '@nuxt/kit'
|
import { defineNuxtModule, installModule, checkNuxtCompatibilityIssues } from '@nuxt/kit'
|
||||||
import { setupNitroBridge } from './nitro'
|
import { setupNitroBridge } from './nitro'
|
||||||
import { setupAppBridge } from './app'
|
import { setupAppBridge } from './app'
|
||||||
import { setupCAPIBridge } from './capi'
|
import { setupCAPIBridge } from './capi'
|
||||||
@ -15,6 +15,7 @@ export default defineNuxtModule({
|
|||||||
app: {},
|
app: {},
|
||||||
capi: {},
|
capi: {},
|
||||||
globalImports: true,
|
globalImports: true,
|
||||||
|
constraints: true,
|
||||||
// TODO: Remove from 2.16
|
// TODO: Remove from 2.16
|
||||||
postcss8: true,
|
postcss8: true,
|
||||||
swc: true,
|
swc: true,
|
||||||
@ -50,5 +51,18 @@ export default defineNuxtModule({
|
|||||||
if (opts.resolve) {
|
if (opts.resolve) {
|
||||||
setupBetterResolve()
|
setupBetterResolve()
|
||||||
}
|
}
|
||||||
|
if (opts.constraints) {
|
||||||
|
nuxt.hook('modules:done', (moduleContainer: any) => {
|
||||||
|
for (const [name, m] of Object.entries(moduleContainer.requiredModules || {})) {
|
||||||
|
const requires = (m as any)?.handler?.meta?.requires
|
||||||
|
if (requires) {
|
||||||
|
const issues = checkNuxtCompatibilityIssues(requires, nuxt)
|
||||||
|
if (issues.length) {
|
||||||
|
console.warn(`[bridge] Detected module incompatibility issues for \`${name}\`:\n` + issues.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash.template": "^4",
|
"@types/lodash.template": "^4",
|
||||||
|
"@types/semver": "^7",
|
||||||
"unbuild": "latest"
|
"unbuild": "latest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -30,6 +31,7 @@
|
|||||||
"pathe": "^0.2.0",
|
"pathe": "^0.2.0",
|
||||||
"rc9": "^1.2.0",
|
"rc9": "^1.2.0",
|
||||||
"scule": "^0.2.1",
|
"scule": "^0.2.1",
|
||||||
|
"semver": "^7.3.5",
|
||||||
"std-env": "^2.3.1",
|
"std-env": "^2.3.1",
|
||||||
"ufo": "^0.7.9",
|
"ufo": "^0.7.9",
|
||||||
"unctx": "^1.0.2",
|
"unctx": "^1.0.2",
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { promises as fsp } from 'fs'
|
import { promises as fsp } from 'fs'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
import { applyDefaults } from 'untyped'
|
import { applyDefaults } from 'untyped'
|
||||||
|
import consola from 'consola'
|
||||||
import { useNuxt, nuxtCtx } from '../nuxt'
|
import { useNuxt, nuxtCtx } from '../nuxt'
|
||||||
import type { Nuxt, NuxtTemplate } from '../types/nuxt'
|
import type { Nuxt, NuxtTemplate } from '../types/nuxt'
|
||||||
import type { NuxtModule, LegacyNuxtModule, ModuleOptions } from '../types/module'
|
import type { NuxtModule, LegacyNuxtModule, ModuleOptions } from '../types/module'
|
||||||
import { compileTemplate, isNuxt2, templateUtils } from './utils'
|
import { checkNuxtCompatibilityIssues, compileTemplate, isNuxt2, templateUtils } from './utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a Nuxt module, automatically merging defaults with user provided options, installing
|
* Define a Nuxt module, automatically merging defaults with user provided options, installing
|
||||||
@ -34,6 +35,15 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (input: NuxtMod
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check nuxt version range
|
||||||
|
if (mod.requires) {
|
||||||
|
const issues = checkNuxtCompatibilityIssues(mod.requires, nuxt)
|
||||||
|
if (issues.length) {
|
||||||
|
consola.warn(`Module \`${mod.name}\` is disabled due to incompatibility issues:\n${issues.toString()}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve options
|
// Resolve options
|
||||||
const configKey = mod.configKey || mod.name
|
const configKey = mod.configKey || mod.name
|
||||||
const userOptions = defu(inlineOptions, nuxt.options[configKey]) as OptionsT
|
const userOptions = defu(inlineOptions, nuxt.options[configKey]) as OptionsT
|
||||||
|
@ -5,6 +5,9 @@ import hash from 'hash-sum'
|
|||||||
import type { WebpackPluginInstance, Configuration as WebpackConfig } from 'webpack'
|
import type { WebpackPluginInstance, Configuration as WebpackConfig } from 'webpack'
|
||||||
import type { Plugin as VitePlugin, UserConfig as ViteConfig } from 'vite'
|
import type { Plugin as VitePlugin, UserConfig as ViteConfig } from 'vite'
|
||||||
import { camelCase } from 'scule'
|
import { camelCase } from 'scule'
|
||||||
|
import semver from 'semver'
|
||||||
|
import { NuxtCompatibilityConstraints, NuxtCompatibilityIssues } from '../types/module'
|
||||||
|
import { Nuxt } from '../types/nuxt'
|
||||||
import { useNuxt } from '../nuxt'
|
import { useNuxt } from '../nuxt'
|
||||||
import type { NuxtTemplate, NuxtPlugin, NuxtPluginTemplate } from '../types/nuxt'
|
import type { NuxtTemplate, NuxtPlugin, NuxtPluginTemplate } from '../types/nuxt'
|
||||||
|
|
||||||
@ -255,15 +258,6 @@ export function addVitePlugin (plugin: VitePlugin, options?: ExtendViteConfigOpt
|
|||||||
}, options)
|
}, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if current nuxt instance is version 2 legacy
|
|
||||||
*/
|
|
||||||
export function isNuxt2 (nuxt?: any) {
|
|
||||||
nuxt = nuxt || useNuxt()
|
|
||||||
const version = (nuxt?.version || nuxt?.constructor?.version || '').replace(/^v|-.*$/g, '')
|
|
||||||
return version.startsWith('2.')
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function compileTemplate (template: NuxtTemplate, ctx: any) {
|
export async function compileTemplate (template: NuxtTemplate, ctx: any) {
|
||||||
const data = { ...ctx, ...template.options }
|
const data = { ...ctx, ...template.options }
|
||||||
if (template.src) {
|
if (template.src) {
|
||||||
@ -302,3 +296,64 @@ export const templateUtils = {
|
|||||||
importName,
|
importName,
|
||||||
importSources
|
importSources
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if current nuxt instance is version 2 legacy
|
||||||
|
*/
|
||||||
|
export function isNuxt2 (nuxt: Nuxt = useNuxt()) {
|
||||||
|
return getNuxtVersion(nuxt).startsWith('2.')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if current nuxt instance is version 2 legacy
|
||||||
|
*/
|
||||||
|
export function isNuxt3 (nuxt: Nuxt = useNuxt()) {
|
||||||
|
return getNuxtVersion(nuxt).startsWith('3.')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get nuxt version
|
||||||
|
*/
|
||||||
|
export function getNuxtVersion (nuxt: Nuxt | any = useNuxt() /* TODO: LegacyNuxt */) {
|
||||||
|
const version = (nuxt?._version || nuxt?.version || nuxt?.constructor?.version || '').replace(/^v/g, '')
|
||||||
|
if (!version) {
|
||||||
|
throw new Error('Cannot determine nuxt version! Is currect instance passed?')
|
||||||
|
}
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check version constraints and return incompatibility issues as an array
|
||||||
|
*/
|
||||||
|
export function checkNuxtCompatibilityIssues (constraints: NuxtCompatibilityConstraints, nuxt: Nuxt = useNuxt()): NuxtCompatibilityIssues {
|
||||||
|
const issues: NuxtCompatibilityIssues = []
|
||||||
|
if (constraints.nuxt) {
|
||||||
|
const nuxtVersion = getNuxtVersion(nuxt)
|
||||||
|
if (!semver.satisfies(nuxtVersion, constraints.nuxt)) {
|
||||||
|
issues.push({
|
||||||
|
name: 'nuxt',
|
||||||
|
message: `Nuxt version \`${constraints.nuxt}\` is required but currently using \`${nuxtVersion}\``
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
issues.toString = () => issues.map(issue => ` - [${issue.name}] ${issue.message}`).join('\n')
|
||||||
|
return issues
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check version constraints and throw a detailed error if has any, otherwise returns true
|
||||||
|
*/
|
||||||
|
export function ensureNuxtCompatibility (constraints: NuxtCompatibilityConstraints, nuxt: Nuxt = useNuxt()): true {
|
||||||
|
const issues = checkNuxtCompatibilityIssues(constraints, nuxt)
|
||||||
|
if (issues.length) {
|
||||||
|
throw new Error('Nuxt compatibility issues found:\n' + issues.toString())
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check version constraints and return true if passed, otherwise returns false
|
||||||
|
*/
|
||||||
|
export function hasNuxtCompatibility (constraints: NuxtCompatibilityConstraints, nuxt: Nuxt = useNuxt()) {
|
||||||
|
return !checkNuxtCompatibilityIssues(constraints, nuxt).length
|
||||||
|
}
|
||||||
|
@ -2,14 +2,43 @@ import type { ModuleContainer } from '../module/container'
|
|||||||
import { Nuxt } from './nuxt'
|
import { Nuxt } from './nuxt'
|
||||||
import { NuxtHooks } from './hooks'
|
import { NuxtHooks } from './hooks'
|
||||||
|
|
||||||
|
export interface NuxtCompatibilityConstraints {
|
||||||
|
/**
|
||||||
|
* Required nuxt version. for example, `^2.14.0` or `>=3.0.0-27219851.6e49637`.
|
||||||
|
*/
|
||||||
|
nuxt?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NuxtCompatibilityIssue {
|
||||||
|
name: string
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NuxtCompatibilityIssues extends Array<NuxtCompatibilityIssue> {
|
||||||
|
/**
|
||||||
|
* Return formatted error message
|
||||||
|
*/
|
||||||
|
toString(): string
|
||||||
|
}
|
||||||
|
|
||||||
export interface ModuleMeta {
|
export interface ModuleMeta {
|
||||||
/** The module name. */
|
/** Module name */
|
||||||
name?: string
|
name?: string
|
||||||
|
|
||||||
|
/** Module version */
|
||||||
|
version?: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The configuration key used within `nuxt.config` for this module's options.
|
* The configuration key used within `nuxt.config` for this module's options.
|
||||||
* For example, `@nuxtjs/axios` uses `axios`.
|
* For example, `@nuxtjs/axios` uses `axios`.
|
||||||
*/
|
*/
|
||||||
configKey?: string
|
configKey?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semver constraints for the versions of Nuxt or features this module are supported.
|
||||||
|
*/
|
||||||
|
requires?: NuxtCompatibilityConstraints
|
||||||
|
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,11 @@ import type { NuxtHooks } from './hooks'
|
|||||||
import type { NuxtOptions } from './config'
|
import type { NuxtOptions } from './config'
|
||||||
|
|
||||||
export interface Nuxt {
|
export interface Nuxt {
|
||||||
|
// Private fields
|
||||||
|
_version: string
|
||||||
|
|
||||||
/** The resolved Nuxt configuration. */
|
/** The resolved Nuxt configuration. */
|
||||||
options: NuxtOptions
|
options: NuxtOptions
|
||||||
|
|
||||||
hooks: Hookable<NuxtHooks>
|
hooks: Hookable<NuxtHooks>
|
||||||
hook: Nuxt['hooks']['hook']
|
hook: Nuxt['hooks']['hook']
|
||||||
callHook: Nuxt['hooks']['callHook']
|
callHook: Nuxt['hooks']['callHook']
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nuxt3",
|
"name": "nuxt3",
|
||||||
"version": "0.10.0",
|
"version": "3.0.0",
|
||||||
"repository": "nuxt/framework",
|
"repository": "nuxt/framework",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
@ -6,12 +6,14 @@ import metaModule from '../meta/module'
|
|||||||
import componentsModule from '../components/module'
|
import componentsModule from '../components/module'
|
||||||
import globalImportsModule from '../global-imports/module'
|
import globalImportsModule from '../global-imports/module'
|
||||||
import { distDir, pkgDir } from '../dirs'
|
import { distDir, pkgDir } from '../dirs'
|
||||||
|
import { version } from '../../package.json'
|
||||||
import { initNitro } from './nitro'
|
import { initNitro } from './nitro'
|
||||||
|
|
||||||
export function createNuxt (options: NuxtOptions): Nuxt {
|
export function createNuxt (options: NuxtOptions): Nuxt {
|
||||||
const hooks = createHooks<NuxtHooks>()
|
const hooks = createHooks<NuxtHooks>()
|
||||||
|
|
||||||
const nuxt: Nuxt = {
|
const nuxt: Nuxt = {
|
||||||
|
_version: version,
|
||||||
options,
|
options,
|
||||||
hooks,
|
hooks,
|
||||||
callHook: hooks.callHook,
|
callHook: hooks.callHook,
|
||||||
|
@ -1494,6 +1494,7 @@ __metadata:
|
|||||||
resolution: "@nuxt/kit@workspace:packages/kit"
|
resolution: "@nuxt/kit@workspace:packages/kit"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/lodash.template": ^4
|
"@types/lodash.template": ^4
|
||||||
|
"@types/semver": ^7
|
||||||
consola: ^2.15.3
|
consola: ^2.15.3
|
||||||
create-require: ^1.1.1
|
create-require: ^1.1.1
|
||||||
defu: ^5.0.0
|
defu: ^5.0.0
|
||||||
@ -1506,6 +1507,7 @@ __metadata:
|
|||||||
pathe: ^0.2.0
|
pathe: ^0.2.0
|
||||||
rc9: ^1.2.0
|
rc9: ^1.2.0
|
||||||
scule: ^0.2.1
|
scule: ^0.2.1
|
||||||
|
semver: ^7.3.5
|
||||||
std-env: ^2.3.1
|
std-env: ^2.3.1
|
||||||
ufo: ^0.7.9
|
ufo: ^0.7.9
|
||||||
unbuild: latest
|
unbuild: latest
|
||||||
@ -2408,6 +2410,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/semver@npm:^7":
|
||||||
|
version: 7.3.8
|
||||||
|
resolution: "@types/semver@npm:7.3.8"
|
||||||
|
checksum: bc90f5a9d5430e36f766c08c898e3c28af88830ebc7736baef8ffc74783bad2efb32f29c40d450e85fc341847ee74e2dd97b76cfc7da407e4232ba9ecae4ff9c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/serve-static@npm:^1.13.10":
|
"@types/serve-static@npm:^1.13.10":
|
||||||
version: 1.13.10
|
version: 1.13.10
|
||||||
resolution: "@types/serve-static@npm:1.13.10"
|
resolution: "@types/serve-static@npm:1.13.10"
|
||||||
|
Loading…
Reference in New Issue
Block a user