From 13a8e2b163684f2b2517c534e4da447c4bc16e5b Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Wed, 10 Nov 2021 12:40:02 +0000 Subject: [PATCH] fix(nitro, nuxi): add runtimeConfig types (for `#config` and `useRuntimeConfig()`) (#1783) Co-authored-by: Tobias Diez Co-authored-by: Pooya Parsa --- .../3.docs/1.usage/5.runtime-config.md | 108 ++++++++++++++++++ packages/bridge/src/nitro.ts | 5 - packages/bridge/src/runtime/composables.ts | 3 +- packages/kit/src/index.ts | 1 + packages/kit/src/types/runtime-config.ts | 5 + packages/nitro/types/shims.d.ts | 8 ++ packages/nuxi/src/utils/prepare.ts | 1 + packages/nuxt3/src/app/nuxt.ts | 3 +- 8 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 docs/content/3.docs/1.usage/5.runtime-config.md create mode 100644 packages/kit/src/types/runtime-config.ts diff --git a/docs/content/3.docs/1.usage/5.runtime-config.md b/docs/content/3.docs/1.usage/5.runtime-config.md new file mode 100644 index 0000000000..78aba9ff16 --- /dev/null +++ b/docs/content/3.docs/1.usage/5.runtime-config.md @@ -0,0 +1,108 @@ +# Runtime Config + +Nuxt provides a runtime config API to share within App and API routes. + +## Exposing runtime config + +To expose config and environment variables to the rest of your app, you will need to define runtime configuration in your `nuxt.config` file, using either the [`publicRuntimeConfig` or `privateRuntimeConfig` options](/docs/directory-structure/nuxt.config#privateruntimeconfig). Based on whether you want it to be accessible on the client-side part of your app or not. + +**Example:** + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + publicRuntimeConfig: { + API_BASE: '/api' + }, + privateRunimeConfig: { + API_SECRET: '123' + } +}) +``` + +When adding `API_BASE` to the `publicRuntimeConfig`, Nuxt adds it to the pages payload. This way we can universally access `API_BASE` in both server and browser. + +### Environment Variables + +The most common way to provide configuration, is using [Environment Variables](https://medium.com/chingu/an-introduction-to-environment-variables-and-how-to-use-them-f602f66d15fa). +Nuxt CLI has built-in [dotenv](https://github.com/motdotla/dotenv) support. + +In addition to any process environment variables, if you have a `.env` file in your project root directory, it will be automatically loaded into `process.env` and accessible within your `nuxt.config` file and Modules. + +**Example:** + +```sh [.env] +BASE_URL=https://nuxtjs.org +API_SECRET=api_secret_token +``` + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + publicRuntimeConfig: { + BASE_URL: process.env.BASE_URL + }, + privateRuntimeConfig: { + API_SECRET: process.env.API_SECRET + } +}) +``` + +**💡 Tip:** While it is not necessary, by using identical runtime config names as env variables, you can easily override them in production using platform environment variables. + +## Accessing runtime config + +### Vue app + +Within the Vue part of your Nuxt app, you will need to call `useRuntimeConfig()` to access the runtime config. + +**Note:** Behavior is different between client side and server side: + +- On Client-Side, only `publicRuntimeConfig` is available and object is writable + reactive +- On Server-Side, both `publicRuntimeConfig` and `privateRuntimeConfig` are merged and object is readonly to avoid context sharing + +```vue + + + +``` + +**🛑 Security note:** Never use example above if `API_AUTH_TOKEN` is a private config. Even if you use `privateRuntimeConfig`, you have to be still careful you do not expose such config to either payload or html! + +### API routes + +Within the API routes, you can access runtime config by directly importing from virtual `#config`. + +```ts +import config from '#config' + +export default async () => { + const result = await $fetch('https://my.api.com/test', { + headers: { + Authorization: `Bearer ${config.API_AUTH_TOKEN}` + } + }) + return result +} +``` + +### Typing runtime config + +Currently it is possible to manually type your runtime config. + +```ts [index.d.ts] +declare module '@nuxt/kit' { + interface PublicRuntimeConfig { + testConfig: string + } + interface PrivateRuntimeConfig { + token: string + } +} +// It is always important to ensure you import/export something when augmenting a type +export {} +``` diff --git a/packages/bridge/src/nitro.ts b/packages/bridge/src/nitro.ts index ddbb26df20..f8d1e16e2d 100644 --- a/packages/bridge/src/nitro.ts +++ b/packages/bridge/src/nitro.ts @@ -129,11 +129,6 @@ export function setupNitroBridge () { // Add typed route responses nuxt.hook('prepare:types', (opts) => { opts.references.push({ path: resolve(nuxt.options.buildDir, 'nitro.d.ts') }) - - for (const stub of ['#storage', '#assets']) { - // The `@nuxt/nitro` types will be overwritten by packages/nitro/types/shims.d.ts - opts.tsConfig.compilerOptions.paths[stub] = ['@nuxt/nitro'] - } }) // nuxt build/dev diff --git a/packages/bridge/src/runtime/composables.ts b/packages/bridge/src/runtime/composables.ts index aa758901a4..d3fb9cb875 100644 --- a/packages/bridge/src/runtime/composables.ts +++ b/packages/bridge/src/runtime/composables.ts @@ -3,6 +3,7 @@ import type { CombinedVueInstance } from 'vue/types/vue' import type { MetaInfo } from 'vue-meta' import type VueRouter from 'vue-router' import type { Route } from 'vue-router' +import type { RuntimeConfig } from '@nuxt/kit' import { useNuxtApp } from './app' export * from '@vue/composition-api' @@ -18,7 +19,7 @@ export const useRuntimeConfig = () => { if (!nuxtApp.$config) { nuxtApp.$config = reactive(nuxtApp.nuxt2Context.app.$config) } - return nuxtApp.$config + return nuxtApp.$config as RuntimeConfig } // Auto-import equivalents for `vue-router` diff --git a/packages/kit/src/index.ts b/packages/kit/src/index.ts index c2678e8cef..a7532a50f2 100644 --- a/packages/kit/src/index.ts +++ b/packages/kit/src/index.ts @@ -25,3 +25,4 @@ export * from './types/module' export * from './types/nuxt' export * from './types/components' export * from './types/imports' +export * from './types/runtime-config' diff --git a/packages/kit/src/types/runtime-config.ts b/packages/kit/src/types/runtime-config.ts new file mode 100644 index 0000000000..91b70d14fe --- /dev/null +++ b/packages/kit/src/types/runtime-config.ts @@ -0,0 +1,5 @@ +export interface PublicRuntimeConfig extends Record { } +export interface PrivateRuntimeConfig extends PublicRuntimeConfig { } + +type _RuntimeConfig = PublicRuntimeConfig & Partial +export interface RuntimeConfig extends _RuntimeConfig { } diff --git a/packages/nitro/types/shims.d.ts b/packages/nitro/types/shims.d.ts index 335b973e11..b6fce00665 100644 --- a/packages/nitro/types/shims.d.ts +++ b/packages/nitro/types/shims.d.ts @@ -9,3 +9,11 @@ declare module '#assets' { export function statAsset (id: string): Promise export function getKeys() : Promise } + +declare module '#config' { + import type { PublicRuntimeConfig, PrivateRuntimeConfig } from '@nuxt/kit' + export const privateConfig: PrivateRuntimeConfig + export const publicConfig: PublicRuntimeConfig + const runtimeConfig: PrivateRuntimeConfig & PublicRuntimeConfig + export default runtimeConfig +} diff --git a/packages/nuxi/src/utils/prepare.ts b/packages/nuxi/src/utils/prepare.ts index f2a5010ab5..7b00901bb1 100644 --- a/packages/nuxi/src/utils/prepare.ts +++ b/packages/nuxi/src/utils/prepare.ts @@ -31,6 +31,7 @@ export const writeTypes = async (nuxt: Nuxt) => { ...nuxt.options.alias, '#build': nuxt.options.buildDir, // The `@nuxt/nitro` types will be overwritten by packages/nitro/types/shims.d.ts + '#config': '@nuxt/nitro', '#storage': '@nuxt/nitro', '#assets': '@nuxt/nitro' } diff --git a/packages/nuxt3/src/app/nuxt.ts b/packages/nuxt3/src/app/nuxt.ts index f91dad518f..10ac1fab8b 100644 --- a/packages/nuxt3/src/app/nuxt.ts +++ b/packages/nuxt3/src/app/nuxt.ts @@ -2,6 +2,7 @@ import { getCurrentInstance, reactive } from 'vue' import type { App, VNode } from 'vue' import { createHooks, Hookable } from 'hookable' +import type { RuntimeConfig } from '@nuxt/kit' import { legacyPlugin, LegacyContext } from './legacy' type NuxtMeta = { @@ -192,7 +193,7 @@ export function useNuxtApp (): NuxtApp { return vm.appContext.app.$nuxt } -export function useRuntimeConfig (): Record { +export function useRuntimeConfig (): RuntimeConfig { return useNuxtApp().$config }