mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(kit): add useRuntimeConfig
and updateRuntimeConfig
utils (#27117)
This commit is contained in:
parent
76925a4477
commit
cebc89186e
27
docs/3.api/5.kit/10.runtime-config.md
Normal file
27
docs/3.api/5.kit/10.runtime-config.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
title: Runtime Config
|
||||||
|
description: Nuxt Kit provides a set of utilities to help you access and modify Nuxt runtime configuration.
|
||||||
|
links:
|
||||||
|
- label: Source
|
||||||
|
icon: i-simple-icons-github
|
||||||
|
to: https://github.com/nuxt/nuxt/blob/main/packages/kit/src/runtime-config.ts
|
||||||
|
size: xs
|
||||||
|
---
|
||||||
|
|
||||||
|
## `useRuntimeConfig`
|
||||||
|
|
||||||
|
At build-time, it is possible to access the resolved Nuxt [runtime config](/docs/guide/going-further/runtime-config).
|
||||||
|
|
||||||
|
### Type
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function useRuntimeConfig (): Record<string, unknown>
|
||||||
|
```
|
||||||
|
|
||||||
|
## `updateRuntimeConfig`
|
||||||
|
|
||||||
|
It is also possible to update runtime configuration. This will be merged with the existing runtime configuration, and if Nitro has already been initialized it will trigger an HMR event to reload the Nitro runtime config.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
function updateRuntimeConfig (config: Record<string, unknown>): void | Promise<void>
|
||||||
|
```
|
@ -30,10 +30,12 @@
|
|||||||
"c12": "^1.10.0",
|
"c12": "^1.10.0",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
|
"destr": "^2.0.3",
|
||||||
"globby": "^14.0.1",
|
"globby": "^14.0.1",
|
||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"jiti": "^1.21.0",
|
"jiti": "^1.21.0",
|
||||||
|
"klona": "^2.0.6",
|
||||||
"knitwork": "^1.1.0",
|
"knitwork": "^1.1.0",
|
||||||
"mlly": "^1.7.0",
|
"mlly": "^1.7.0",
|
||||||
"pathe": "^1.1.2",
|
"pathe": "^1.1.2",
|
||||||
|
@ -10,6 +10,7 @@ export * from './loader/nuxt'
|
|||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
export * from './imports'
|
export * from './imports'
|
||||||
|
export { updateRuntimeConfig, useRuntimeConfig } from './runtime-config'
|
||||||
export * from './build'
|
export * from './build'
|
||||||
export * from './compatibility'
|
export * from './compatibility'
|
||||||
export * from './components'
|
export * from './components'
|
||||||
|
103
packages/kit/src/runtime-config.ts
Normal file
103
packages/kit/src/runtime-config.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import process from 'node:process'
|
||||||
|
import destr from 'destr'
|
||||||
|
import { snakeCase } from 'scule'
|
||||||
|
import { klona } from 'klona'
|
||||||
|
|
||||||
|
import defu from 'defu'
|
||||||
|
import { useNuxt } from './context'
|
||||||
|
import { useNitro } from './nitro'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access 'resolved' Nuxt runtime configuration, with values updated from environment.
|
||||||
|
*
|
||||||
|
* This mirrors the runtime behavior of Nitro.
|
||||||
|
*/
|
||||||
|
export function useRuntimeConfig () {
|
||||||
|
const nuxt = useNuxt()
|
||||||
|
return applyEnv(klona(nuxt.options.nitro.runtimeConfig!), {
|
||||||
|
prefix: 'NITRO_',
|
||||||
|
altPrefix: 'NUXT_',
|
||||||
|
envExpansion: nuxt.options.nitro.experimental?.envExpansion ?? !!process.env.NITRO_ENV_EXPANSION,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Nuxt runtime configuration.
|
||||||
|
*/
|
||||||
|
export function updateRuntimeConfig (runtimeConfig: Record<string, unknown>) {
|
||||||
|
const nuxt = useNuxt()
|
||||||
|
Object.assign(nuxt.options.nitro.runtimeConfig as Record<string, unknown>, defu(runtimeConfig, nuxt.options.nitro.runtimeConfig))
|
||||||
|
|
||||||
|
try {
|
||||||
|
return useNitro().updateConfig({ runtimeConfig })
|
||||||
|
} catch {
|
||||||
|
// Nitro is not yet initialised - we can safely ignore this error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* https://github.com/unjs/nitro/blob/main/src/runtime/utils.env.ts.
|
||||||
|
*
|
||||||
|
* These utils will be replaced by util exposed from nitropack. See https://github.com/unjs/nitro/pull/2404
|
||||||
|
* for more context and future plans.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
type EnvOptions = {
|
||||||
|
prefix?: string
|
||||||
|
altPrefix?: string
|
||||||
|
envExpansion?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEnv (key: string, opts: EnvOptions, env = process.env) {
|
||||||
|
const envKey = snakeCase(key).toUpperCase()
|
||||||
|
return destr(
|
||||||
|
env[opts.prefix + envKey] ?? env[opts.altPrefix + envKey],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function _isObject (input: unknown) {
|
||||||
|
return typeof input === 'object' && !Array.isArray(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyEnv (
|
||||||
|
obj: Record<string, any>,
|
||||||
|
opts: EnvOptions,
|
||||||
|
parentKey = '',
|
||||||
|
) {
|
||||||
|
for (const key in obj) {
|
||||||
|
const subKey = parentKey ? `${parentKey}_${key}` : key
|
||||||
|
const envValue = getEnv(subKey, opts)
|
||||||
|
if (_isObject(obj[key])) {
|
||||||
|
// Same as before
|
||||||
|
if (_isObject(envValue)) {
|
||||||
|
obj[key] = { ...(obj[key] as any), ...(envValue as any) }
|
||||||
|
applyEnv(obj[key], opts, subKey)
|
||||||
|
} else if (envValue === undefined) {
|
||||||
|
// If envValue is undefined
|
||||||
|
// Then proceed to nested properties
|
||||||
|
applyEnv(obj[key], opts, subKey)
|
||||||
|
} else {
|
||||||
|
// If envValue is a primitive other than undefined
|
||||||
|
// Then set objValue and ignore the nested properties
|
||||||
|
obj[key] = envValue ?? obj[key]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obj[key] = envValue ?? obj[key]
|
||||||
|
}
|
||||||
|
// Experimental env expansion
|
||||||
|
if (opts.envExpansion && typeof obj[key] === 'string') {
|
||||||
|
obj[key] = _expandFromEnv(obj[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
const envExpandRx = /{{(.*?)}}/g
|
||||||
|
|
||||||
|
function _expandFromEnv (value: string, env: Record<string, any> = process.env) {
|
||||||
|
return value.replace(envExpandRx, (match, key) => {
|
||||||
|
return env[key] || match
|
||||||
|
})
|
||||||
|
}
|
@ -12,7 +12,7 @@ import { defu } from 'defu'
|
|||||||
import fsExtra from 'fs-extra'
|
import fsExtra from 'fs-extra'
|
||||||
import { dynamicEventHandler } from 'h3'
|
import { dynamicEventHandler } from 'h3'
|
||||||
import { isWindows } from 'std-env'
|
import { isWindows } from 'std-env'
|
||||||
import type { Nuxt, NuxtOptions, RuntimeConfig } from 'nuxt/schema'
|
import type { Nuxt, NuxtOptions } from 'nuxt/schema'
|
||||||
import { version as nuxtVersion } from '../../package.json'
|
import { version as nuxtVersion } from '../../package.json'
|
||||||
import { distDir } from '../dirs'
|
import { distDir } from '../dirs'
|
||||||
import { toArray } from '../utils'
|
import { toArray } from '../utils'
|
||||||
@ -27,8 +27,6 @@ const logLevelMapReverse = {
|
|||||||
|
|
||||||
export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||||
// Resolve config
|
// Resolve config
|
||||||
const _nitroConfig = ((nuxt.options as any).nitro || {}) as NitroConfig
|
|
||||||
|
|
||||||
const excludePaths = nuxt.options._layers
|
const excludePaths = nuxt.options._layers
|
||||||
.flatMap(l => [
|
.flatMap(l => [
|
||||||
l.cwd.match(/(?<=\/)node_modules\/(.+)$/)?.[1],
|
l.cwd.match(/(?<=\/)node_modules\/(.+)$/)?.[1],
|
||||||
@ -48,7 +46,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
.map(m => m.entryPath),
|
.map(m => m.entryPath),
|
||||||
)
|
)
|
||||||
|
|
||||||
const nitroConfig: NitroConfig = defu(_nitroConfig, {
|
const nitroConfig: NitroConfig = defu(nuxt.options.nitro, {
|
||||||
debug: nuxt.options.debug,
|
debug: nuxt.options.debug,
|
||||||
rootDir: nuxt.options.rootDir,
|
rootDir: nuxt.options.rootDir,
|
||||||
workspaceDir: nuxt.options.workspaceDir,
|
workspaceDir: nuxt.options.workspaceDir,
|
||||||
@ -57,7 +55,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
buildDir: nuxt.options.buildDir,
|
buildDir: nuxt.options.buildDir,
|
||||||
experimental: {
|
experimental: {
|
||||||
asyncContext: nuxt.options.experimental.asyncContext,
|
asyncContext: nuxt.options.experimental.asyncContext,
|
||||||
typescriptBundlerResolution: nuxt.options.future.typescriptBundlerResolution || nuxt.options.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' || _nitroConfig.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler',
|
typescriptBundlerResolution: nuxt.options.future.typescriptBundlerResolution || nuxt.options.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' || nuxt.options.nitro.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler',
|
||||||
},
|
},
|
||||||
framework: {
|
framework: {
|
||||||
name: 'nuxt',
|
name: 'nuxt',
|
||||||
@ -110,20 +108,6 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
routeRules: {
|
routeRules: {
|
||||||
'/__nuxt_error': { cache: false },
|
'/__nuxt_error': { cache: false },
|
||||||
},
|
},
|
||||||
runtimeConfig: {
|
|
||||||
...nuxt.options.runtimeConfig,
|
|
||||||
app: {
|
|
||||||
...nuxt.options.runtimeConfig.app,
|
|
||||||
baseURL: nuxt.options.runtimeConfig.app.baseURL.startsWith('./')
|
|
||||||
? nuxt.options.runtimeConfig.app.baseURL.slice(1)
|
|
||||||
: nuxt.options.runtimeConfig.app.baseURL,
|
|
||||||
},
|
|
||||||
nitro: {
|
|
||||||
envPrefix: 'NUXT_',
|
|
||||||
// TODO: address upstream issue with defu types...?
|
|
||||||
...nuxt.options.runtimeConfig.nitro satisfies RuntimeConfig['nitro'] as any,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
appConfig: nuxt.options.appConfig,
|
appConfig: nuxt.options.appConfig,
|
||||||
appConfigFiles: nuxt.options._layers.map(
|
appConfigFiles: nuxt.options._layers.map(
|
||||||
layer => resolve(layer.config.srcDir, 'app.config'),
|
layer => resolve(layer.config.srcDir, 'app.config'),
|
||||||
|
@ -4,7 +4,7 @@ import ignore from 'ignore'
|
|||||||
import type { LoadNuxtOptions } from '@nuxt/kit'
|
import type { LoadNuxtOptions } from '@nuxt/kit'
|
||||||
import { addBuildPlugin, addComponent, addPlugin, addRouteMiddleware, addServerPlugin, addVitePlugin, addWebpackPlugin, installModule, loadNuxtConfig, logger, nuxtCtx, resolveAlias, resolveFiles, resolveIgnorePatterns, resolvePath, tryResolveModule, useNitro } from '@nuxt/kit'
|
import { addBuildPlugin, addComponent, addPlugin, addRouteMiddleware, addServerPlugin, addVitePlugin, addWebpackPlugin, installModule, loadNuxtConfig, logger, nuxtCtx, resolveAlias, resolveFiles, resolveIgnorePatterns, resolvePath, tryResolveModule, useNitro } from '@nuxt/kit'
|
||||||
import { resolvePath as _resolvePath } from 'mlly'
|
import { resolvePath as _resolvePath } from 'mlly'
|
||||||
import type { Nuxt, NuxtHooks, NuxtOptions } from 'nuxt/schema'
|
import type { Nuxt, NuxtHooks, 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'
|
||||||
|
|
||||||
@ -600,6 +600,9 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
|
|||||||
options._modules.push('@nuxt/telemetry')
|
options._modules.push('@nuxt/telemetry')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure we share runtime config between Nuxt and Nitro
|
||||||
|
options.runtimeConfig = options.nitro.runtimeConfig as RuntimeConfig
|
||||||
|
|
||||||
const nuxt = createNuxt(options)
|
const nuxt = createNuxt(options)
|
||||||
|
|
||||||
// We register hooks layer-by-layer so any overrides need to be registered separately
|
// We register hooks layer-by-layer so any overrides need to be registered separately
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { defineUntypedSchema } from 'untyped'
|
import { defineUntypedSchema } from 'untyped'
|
||||||
|
import type { RuntimeConfig } from '../types/config'
|
||||||
|
|
||||||
export default defineUntypedSchema({
|
export default defineUntypedSchema({
|
||||||
/**
|
/**
|
||||||
@ -7,6 +8,24 @@ export default defineUntypedSchema({
|
|||||||
* @type {typeof import('nitropack')['NitroConfig']}
|
* @type {typeof import('nitropack')['NitroConfig']}
|
||||||
*/
|
*/
|
||||||
nitro: {
|
nitro: {
|
||||||
|
runtimeConfig: {
|
||||||
|
$resolve: async (val: Record<string, any> | undefined, get) => {
|
||||||
|
const runtimeConfig = await get('runtimeConfig') as RuntimeConfig
|
||||||
|
return {
|
||||||
|
...runtimeConfig,
|
||||||
|
app: {
|
||||||
|
...runtimeConfig.app,
|
||||||
|
baseURL: runtimeConfig.app.baseURL.startsWith('./')
|
||||||
|
? runtimeConfig.app.baseURL.slice(1)
|
||||||
|
: runtimeConfig.app.baseURL,
|
||||||
|
},
|
||||||
|
nitro: {
|
||||||
|
envPrefix: 'NUXT_',
|
||||||
|
...runtimeConfig.nitro,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
routeRules: {
|
routeRules: {
|
||||||
$resolve: async (val: Record<string, any> | undefined, get) => ({
|
$resolve: async (val: Record<string, any> | undefined, get) => ({
|
||||||
...await get('routeRules') as Record<string, any>,
|
...await get('routeRules') as Record<string, any>,
|
||||||
|
@ -167,6 +167,9 @@ importers:
|
|||||||
defu:
|
defu:
|
||||||
specifier: ^6.1.4
|
specifier: ^6.1.4
|
||||||
version: 6.1.4
|
version: 6.1.4
|
||||||
|
destr:
|
||||||
|
specifier: ^2.0.3
|
||||||
|
version: 2.0.3
|
||||||
globby:
|
globby:
|
||||||
specifier: ^14.0.1
|
specifier: ^14.0.1
|
||||||
version: 14.0.1
|
version: 14.0.1
|
||||||
@ -179,6 +182,9 @@ importers:
|
|||||||
jiti:
|
jiti:
|
||||||
specifier: ^1.21.0
|
specifier: ^1.21.0
|
||||||
version: 1.21.0
|
version: 1.21.0
|
||||||
|
klona:
|
||||||
|
specifier: ^2.0.6
|
||||||
|
version: 2.0.6
|
||||||
knitwork:
|
knitwork:
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
|
Loading…
Reference in New Issue
Block a user