feat(nuxt3,bridge): add automatic schema augmentation declaration (#3096)

Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
Daniel Roe 2022-02-08 19:09:44 +00:00 committed by GitHub
parent ba522b2034
commit 7825e2aa12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 79 additions and 19 deletions

View File

@ -34,6 +34,7 @@
"defu": "^5.0.1", "defu": "^5.0.1",
"destr": "^1.1.0", "destr": "^1.1.0",
"enhanced-resolve": "^5.9.0", "enhanced-resolve": "^5.9.0",
"escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.1", "estree-walker": "^3.0.1",
"externality": "^0.1.6", "externality": "^0.1.6",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",

View File

@ -1,6 +1,8 @@
import { useNuxt, resolveModule, addTemplate } from '@nuxt/kit' import { useNuxt, resolveModule, addTemplate, resolveAlias } from '@nuxt/kit'
import { NuxtModule } from '@nuxt/schema'
import { resolve } from 'pathe' import { resolve } from 'pathe'
import { componentsTypeTemplate } from '../../nuxt3/src/components/templates' import { componentsTypeTemplate } from '../../nuxt3/src/components/templates'
import { schemaTemplate } from '../../nuxt3/src/core/templates'
import { distDir } from './dirs' import { distDir } from './dirs'
export function setupAppBridge (_options: any) { export function setupAppBridge (_options: any) {
@ -38,6 +40,15 @@ export function setupAppBridge (_options: any) {
references.push({ path: resolve(nuxt.options.buildDir, 'types/components.d.ts') }) references.push({ path: resolve(nuxt.options.buildDir, 'types/components.d.ts') })
}) })
// Augment schema with module types
nuxt.hook('modules:done', async (container: any) => {
nuxt.options._installedModules = await Promise.all(Object.values(container.requiredModules).map(async (m: { src: string, handler: NuxtModule }) => ({
meta: await m.handler.getMeta?.(),
entryPath: resolveAlias(m.src, nuxt.options.alias)
})))
addTemplate(schemaTemplate)
})
// Alias vue to have identical vue3 exports // Alias vue to have identical vue3 exports
nuxt.options.alias['vue2-bridge'] = resolve(distDir, 'runtime/vue2-bridge.mjs') nuxt.options.alias['vue2-bridge'] = resolve(distDir, 'runtime/vue2-bridge.mjs')
for (const alias of [ for (const alias of [

View File

@ -32,7 +32,7 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
} else { } else {
src = moduleOpts src = moduleOpts
} }
await installModule(src, inlineOptions, nuxt) await installModule(src, inlineOptions)
} }
nuxt[MODULE_CONTAINER_KEY] = <ModuleContainer>{ nuxt[MODULE_CONTAINER_KEY] = <ModuleContainer>{

View File

@ -1,18 +1,34 @@
import type { NuxtModule, Nuxt } from '@nuxt/schema' import type { Nuxt, NuxtModule } from '@nuxt/schema'
import { useNuxt } from '../context' import { useNuxt } from '../context'
import { resolveModule, requireModule, importModule } from '../internal/cjs' import { resolveModule, requireModule, importModule } from '../internal/cjs'
import { resolveAlias } from '../resolve' import { resolveAlias } from '../resolve'
import { useModuleContainer } from './container' import { useModuleContainer } from './container'
/** Installs a module on a Nuxt instance. */ /** Installs a module on a Nuxt instance. */
export async function installModule (nuxtModule: string | NuxtModule, inlineOptions?: any, nuxt: Nuxt = useNuxt()) { export async function installModule (moduleToInstall: string | NuxtModule, _inlineOptions?: any, _nuxt?: Nuxt) {
const nuxt = useNuxt()
const { nuxtModule, inlineOptions } = await normalizeModule(moduleToInstall, _inlineOptions)
// Call module
await nuxtModule.call(useModuleContainer(), inlineOptions, nuxt)
nuxt.options._installedModules = nuxt.options._installedModules || []
nuxt.options._installedModules.push({
meta: await nuxtModule.getMeta?.(),
entryPath: typeof moduleToInstall === 'string' ? resolveAlias(moduleToInstall) : undefined
})
}
// --- Internal ---
async function normalizeModule (nuxtModule: string | NuxtModule, inlineOptions?: any) {
const nuxt = useNuxt()
// Detect if `installModule` used with older signuture (nuxt, nuxtModule) // Detect if `installModule` used with older signuture (nuxt, nuxtModule)
// TODO: Remove in RC // TODO: Remove in RC
// @ts-ignore // @ts-ignore
if (nuxtModule?._version || nuxtModule?.version || nuxtModule?.constructor?.version || '') { if (nuxtModule?._version || nuxtModule?.version || nuxtModule?.constructor?.version || '') {
// @ts-ignore [nuxtModule, inlineOptions] = [inlineOptions, {}]
[nuxt, nuxtModule] = [nuxtModule, inlineOptions]
inlineOptions = {}
console.warn(new Error('`installModule` is being called with old signature!')) console.warn(new Error('`installModule` is being called with old signature!'))
} }
@ -29,6 +45,5 @@ export async function installModule (nuxtModule: string | NuxtModule, inlineOpti
throw new TypeError('Nuxt module should be a function: ' + nuxtModule) throw new TypeError('Nuxt module should be a function: ' + nuxtModule)
} }
// Call module return { nuxtModule, inlineOptions } as { nuxtModule: NuxtModule<any>, inlineOptions: undefined | Record<string, any> }
await nuxtModule.call(useModuleContainer(), inlineOptions, nuxt)
} }

View File

@ -49,6 +49,8 @@ async function initNuxt (nuxt: Nuxt) {
if (nuxt.options.typescript.shim) { if (nuxt.options.typescript.shim) {
opts.references.push({ path: resolve(nuxt.options.buildDir, 'types/vue-shim.d.ts') }) opts.references.push({ path: resolve(nuxt.options.buildDir, 'types/vue-shim.d.ts') })
} }
// Add module augmentations directly to NuxtConfig
opts.references.push({ path: resolve(nuxt.options.buildDir, 'types/schema.d.ts') })
}) })
// Add import protection // Add import protection
@ -82,9 +84,9 @@ async function initNuxt (nuxt: Nuxt) {
for (const m of modulesToInstall) { for (const m of modulesToInstall) {
if (Array.isArray(m)) { if (Array.isArray(m)) {
await installModule(m[0], m[1], nuxt) await installModule(m[0], m[1])
} else { } else {
await installModule(m, {}, nuxt) await installModule(m, {})
} }
} }

View File

@ -1,13 +1,13 @@
import { templateUtils } from '@nuxt/kit' import { templateUtils } from '@nuxt/kit'
import type { Nuxt, NuxtApp } from '@nuxt/schema' import type { Nuxt, NuxtApp } from '@nuxt/schema'
import { genArrayFromRaw, genDynamicImport, genExport, genImport } from 'knitwork' import { genArrayFromRaw, genDynamicImport, genExport, genImport, genString } from 'knitwork'
import { isAbsolute, join, relative } from 'pathe' import { isAbsolute, join, relative } from 'pathe'
import escapeRE from 'escape-string-regexp' import escapeRE from 'escape-string-regexp'
type TemplateContext = { export interface TemplateContext {
nuxt: Nuxt; nuxt: Nuxt
app: NuxtApp; app: NuxtApp
} }
export const vueShim = { export const vueShim = {
@ -110,3 +110,25 @@ export { }
` `
} }
} }
const adHocModules = ['router', 'pages', 'auto-imports', 'meta', 'components']
export const schemaTemplate = {
filename: 'types/schema.d.ts',
getContents: ({ nuxt }: TemplateContext) => {
const moduleInfo = nuxt.options._installedModules.map(m => ({
...m.meta || {},
importName: m.entryPath || m.meta?.name
})).filter(m => m.configKey && m.name && !adHocModules.includes(m.name))
return [
"import { NuxtModule } from '@nuxt/schema'",
"declare module '@nuxt/schema' {",
' interface NuxtConfig {',
...moduleInfo.filter(Boolean).map(meta =>
` [${genString(meta.configKey)}]?: typeof ${genDynamicImport(meta.importName, { wrapper: false })}.default extends NuxtModule<infer O> ? Partial<O> : Record<string, any>`
),
' }',
'}'
].join('\n')
}
}

View File

@ -288,6 +288,14 @@ export default {
*/ */
_modules: [], _modules: [],
/**
* Installed module metadata
*
* @version 3
* @private
*/
_installedModules: [],
/** /**
* Allows customizing the global ID used in the main HTML template as well as the main * Allows customizing the global ID used in the main HTML template as well as the main
* Vue instance name and other options. * Vue instance name and other options.

View File

@ -2576,6 +2576,7 @@ __metadata:
defu: ^5.0.1 defu: ^5.0.1
destr: ^1.1.0 destr: ^1.1.0
enhanced-resolve: ^5.9.0 enhanced-resolve: ^5.9.0
escape-string-regexp: ^5.0.0
estree-walker: ^3.0.1 estree-walker: ^3.0.1
externality: ^0.1.6 externality: ^0.1.6
fs-extra: ^10.0.0 fs-extra: ^10.0.0