mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(nuxt3,bridge): add automatic schema augmentation declaration (#3096)
Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
parent
ba522b2034
commit
7825e2aa12
@ -34,6 +34,7 @@
|
||||
"defu": "^5.0.1",
|
||||
"destr": "^1.1.0",
|
||||
"enhanced-resolve": "^5.9.0",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"estree-walker": "^3.0.1",
|
||||
"externality": "^0.1.6",
|
||||
"fs-extra": "^10.0.0",
|
||||
|
@ -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 { componentsTypeTemplate } from '../../nuxt3/src/components/templates'
|
||||
import { schemaTemplate } from '../../nuxt3/src/core/templates'
|
||||
import { distDir } from './dirs'
|
||||
|
||||
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') })
|
||||
})
|
||||
|
||||
// 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
|
||||
nuxt.options.alias['vue2-bridge'] = resolve(distDir, 'runtime/vue2-bridge.mjs')
|
||||
for (const alias of [
|
||||
|
@ -32,7 +32,7 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
|
||||
} else {
|
||||
src = moduleOpts
|
||||
}
|
||||
await installModule(src, inlineOptions, nuxt)
|
||||
await installModule(src, inlineOptions)
|
||||
}
|
||||
|
||||
nuxt[MODULE_CONTAINER_KEY] = <ModuleContainer>{
|
||||
|
@ -1,18 +1,34 @@
|
||||
import type { NuxtModule, Nuxt } from '@nuxt/schema'
|
||||
import type { Nuxt, NuxtModule } from '@nuxt/schema'
|
||||
import { useNuxt } from '../context'
|
||||
import { resolveModule, requireModule, importModule } from '../internal/cjs'
|
||||
import { resolveAlias } from '../resolve'
|
||||
import { useModuleContainer } from './container'
|
||||
|
||||
/** 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)
|
||||
// TODO: Remove in RC
|
||||
// @ts-ignore
|
||||
if (nuxtModule?._version || nuxtModule?.version || nuxtModule?.constructor?.version || '') {
|
||||
// @ts-ignore
|
||||
[nuxt, nuxtModule] = [nuxtModule, inlineOptions]
|
||||
inlineOptions = {}
|
||||
[nuxtModule, inlineOptions] = [inlineOptions, {}]
|
||||
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)
|
||||
}
|
||||
|
||||
// Call module
|
||||
await nuxtModule.call(useModuleContainer(), inlineOptions, nuxt)
|
||||
return { nuxtModule, inlineOptions } as { nuxtModule: NuxtModule<any>, inlineOptions: undefined | Record<string, any> }
|
||||
}
|
||||
|
@ -49,6 +49,8 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
if (nuxt.options.typescript.shim) {
|
||||
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
|
||||
@ -82,9 +84,9 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
|
||||
for (const m of modulesToInstall) {
|
||||
if (Array.isArray(m)) {
|
||||
await installModule(m[0], m[1], nuxt)
|
||||
await installModule(m[0], m[1])
|
||||
} else {
|
||||
await installModule(m, {}, nuxt)
|
||||
await installModule(m, {})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { templateUtils } from '@nuxt/kit'
|
||||
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 escapeRE from 'escape-string-regexp'
|
||||
|
||||
type TemplateContext = {
|
||||
nuxt: Nuxt;
|
||||
app: NuxtApp;
|
||||
export interface TemplateContext {
|
||||
nuxt: Nuxt
|
||||
app: NuxtApp
|
||||
}
|
||||
|
||||
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')
|
||||
}
|
||||
}
|
||||
|
@ -288,6 +288,14 @@ export default {
|
||||
*/
|
||||
_modules: [],
|
||||
|
||||
/**
|
||||
* Installed module metadata
|
||||
*
|
||||
* @version 3
|
||||
* @private
|
||||
*/
|
||||
_installedModules: [],
|
||||
|
||||
/**
|
||||
* Allows customizing the global ID used in the main HTML template as well as the main
|
||||
* Vue instance name and other options.
|
||||
@ -678,13 +686,13 @@ export default {
|
||||
|
||||
/**
|
||||
* Runtime config allows passing dynamic config and environment variables to the Nuxt app context.
|
||||
*
|
||||
*
|
||||
* The value of this object is accessible from server only using `$config` or `useRuntimeConfig`.
|
||||
* It will override `publicRuntimeConfig` on the server-side.
|
||||
*
|
||||
* It should hold _private_ environment variables (that should not be exposed on the frontend).
|
||||
* This could include a reference to your API secret tokens.
|
||||
*
|
||||
*
|
||||
* Values are automatically replaced by matching env variables at runtime, e.g. setting an environment
|
||||
* variable `API_SECRET=my-api-key` would overwrite the value in the example below.
|
||||
* Note that the env variable has to be named exactly the same as the config key.
|
||||
@ -705,9 +713,9 @@ export default {
|
||||
|
||||
/**
|
||||
* Runtime config allows passing dynamic config and environment variables to the Nuxt app context.
|
||||
*
|
||||
*
|
||||
* The value of this object is accessible from both client and server using `$config` or `useRuntimeConfig`.
|
||||
*
|
||||
*
|
||||
* It should hold env variables that are _public_ as they will be accessible on the frontend. This could include a
|
||||
* reference to your public URL.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user