Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

feat(nuxt): app.config with hmr and reactivity support #6333

Merged
merged 38 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5b8a04e
feat(nuxt): `app.config` with hmr support
pi0 Aug 3, 2022
eda4b99
Merge branch 'main' into feat/app-config
pi0 Aug 4, 2022
79ff3b1
webpack hmr support
pi0 Aug 4, 2022
c949684
update AppConfig schema
pi0 Aug 4, 2022
8316b5a
handle key removals
pi0 Aug 4, 2022
171d869
support inline config using `appConfig` in nuxt.config
pi0 Aug 4, 2022
22518d8
fix template when no appConfigs added
pi0 Aug 4, 2022
75e3be9
handle app.config add/removal
pi0 Aug 4, 2022
231e0ca
Merge branch 'main' into feat/app-config
pi0 Aug 4, 2022
efd22f0
auto generate types
pi0 Aug 4, 2022
3e0534c
add tests
pi0 Aug 4, 2022
8c2a012
Merge branch 'main' into feat/app-config
pi0 Aug 4, 2022
9cb0c74
fix test side effect
pi0 Aug 4, 2022
7d6c04a
Merge branch 'main' into feat/app-config
pi0 Aug 4, 2022
d3b9163
simplify reserved namespaces
pi0 Aug 4, 2022
9178cd8
fix: reserved are optional
pi0 Aug 4, 2022
bc269f3
Merge branch 'main' into feat/app-config
pi0 Aug 12, 2022
808bf9d
feat(nuxt): include type of resolved configs in AppConfig
danielroe Aug 16, 2022
d5011cf
refactor: write a single type declaration file
danielroe Aug 16, 2022
5d9c593
chore: upgrade defu
danielroe Aug 16, 2022
43b58f3
test: add type test
danielroe Aug 16, 2022
d152678
fix: update to use `Defu` type helper
danielroe Aug 16, 2022
59ed668
fix: use `ResolvedAppConfig` to for type inference and extract `defin…
danielroe Aug 17, 2022
c63fd89
Merge branch 'main' into feat/app-config
pi0 Aug 17, 2022
69c5b50
try removing subpath from package.json
pi0 Aug 17, 2022
15ed77c
refactor: move `defineAppConfig` to `nuxt.ts`
pi0 Aug 17, 2022
f36e0d0
Update packages/nuxt/src/app/config.ts
pi0 Aug 17, 2022
df2380d
chore: fix ts issue
pi0 Aug 17, 2022
b2c7f57
remove unused import
pi0 Aug 17, 2022
a08d987
add usage to examples
pi0 Aug 17, 2022
6a571f5
add docs
pi0 Aug 17, 2022
e54db5d
fix vite hmr
pi0 Aug 17, 2022
2cace40
update docs
pi0 Aug 17, 2022
840f245
update api guide
pi0 Aug 17, 2022
ed0b584
revert useRuntimeConfig back to nuxt.ts
pi0 Aug 17, 2022
12ec374
Merge branch 'main' into feat/app-config
pi0 Aug 17, 2022
5e7d9c6
i touched it!
pi0 Aug 17, 2022
15f5e3f
strict is not funny
pi0 Aug 17, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"semver": "^7.3.7",
"unctx": "^2.0.0",
"unimport": "^0.6.5",
"untyped": "^0.4.4"
"untyped": "^0.4.5"
},
"devDependencies": {
"@types/lodash.template": "^4",
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxi/src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export default defineNuxtCommand({
dLoad(true, `Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`)
}
} else if (isFileChange) {
if (file.match(/(app|error)\.(js|ts|mjs|jsx|tsx|vue)$/)) {
if (file.match(/(app|error|app\.config)\.(js|ts|mjs|jsx|tsx|vue)$/)) {
dLoad(true, `\`${relativePath}\` ${event === 'add' ? 'created' : 'removed'}`)
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"unenv": "^0.5.2",
"unimport": "^0.6.5",
"unplugin": "^0.8.1",
"untyped": "^0.4.4",
"untyped": "^0.4.5",
"vue": "^3.2.37",
"vue-bundle-renderer": "^0.3.9",
"vue-router": "^4.1.3"
Expand Down
57 changes: 57 additions & 0 deletions packages/nuxt/src/app/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { AppConfig, RuntimeConfig } from '@nuxt/schema'
import { reactive } from 'vue'
import { useNuxtApp } from './nuxt'
// @ts-ignore
import __appConfig from '#build/app.config.mjs'

// Workaround for vite HMR with virtual modules
export const _appConfig = __appConfig as AppConfig

export function useRuntimeConfig (): RuntimeConfig {
pi0 marked this conversation as resolved.
Show resolved Hide resolved
return useNuxtApp().$config
}

export function defineAppConfig (config: AppConfig): AppConfig {
return config
}

export function useAppConfig (): AppConfig {
const nuxtApp = useNuxtApp()
if (!nuxtApp._appConfig) {
nuxtApp._appConfig = reactive(_appConfig) as AppConfig
}
return nuxtApp._appConfig
}

// HMR Support
if (process.dev) {
function applyHMR (newConfig) {
const appConfig = useAppConfig()
if (newConfig && appConfig) {
for (const key in newConfig) {
appConfig[key] = newConfig[key]
}
for (const key in appConfig) {
if (!(key in newConfig)) {
delete appConfig[key]
}
}
}
}

// Vite
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
const newConfig = newModule?._appConfig
applyHMR(newConfig)
})
}

// Webpack
if (import.meta.webpackHot) {
console.log('Register webpackHot')
import.meta.webpackHot.accept('#build/app.config.mjs', () => {
applyHMR(__appConfig)
})
}
}
1 change: 1 addition & 0 deletions packages/nuxt/src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export * from './nuxt'
export * from './composables'
export * from './components'
export * from './config'

// eslint-disable-next-line import/no-restricted-paths
export type { PageMeta } from '../pages/runtime'
Expand Down
4 changes: 0 additions & 4 deletions packages/nuxt/src/app/nuxt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,6 @@ export function useNuxtApp () {
return nuxtAppInstance
}

export function useRuntimeConfig (): RuntimeConfig {
return useNuxtApp().$config
}

function defineGetter<K extends string | number | symbol, V> (obj: Record<K, V>, key: K, val: V) {
Object.defineProperty(obj, key, { get: () => val })
}
4 changes: 3 additions & 1 deletion packages/nuxt/src/auto-imports/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ export const appPreset = defineUnimportPreset({
'isNuxtError',
'useError',
'createError',
'defineNuxtLink'
'defineNuxtLink',
'defineAppConfig',
'useAppConfig'
]
})

Expand Down
9 changes: 9 additions & 0 deletions packages/nuxt/src/core/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
}
app.plugins = uniqueBy(app.plugins, 'src')

// Resolve app.config
app.configs = []
for (const config of nuxt.options._layers.map(layer => layer.config)) {
const appConfigPath = await findPath(resolve(config.srcDir, 'app.config'))
if (appConfigPath) {
app.configs.push(appConfigPath)
}
}

// Extend app
await nuxt.callHook('app:resolve', app)
}
24 changes: 24 additions & 0 deletions packages/nuxt/src/core/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ export const schemaTemplate = {
allowExtraKeys: false,
indentation: 2
}),
generateTypes(resolveSchema(Object.fromEntries(Object.entries(nuxt.options.appConfig))),
{
interfaceName: 'AppConfig',
addExport: false,
addDefaults: false,
allowExtraKeys: true,
indentation: 2,
partial: true
}),
generateTypes(resolveSchema(nuxt.options.runtimeConfig.public),
{
interfaceName: 'PublicRuntimeConfig',
Expand Down Expand Up @@ -176,6 +185,21 @@ export const useRuntimeConfig = () => window?.__NUXT__?.config || {}
`
}

export const appConfigTemplate: NuxtTemplate = {
filename: 'app.config.mjs',
write: true,
getContents: ({ app, nuxt }) => {
return `
import defu from 'defu'

const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)}

${app.configs.map((id, index) => `import ${`cfg${index}`} from ${JSON.stringify(id)}`).join('\n')}
pi0 marked this conversation as resolved.
Show resolved Hide resolved
export default defu(${['{}'].concat(app.configs.map((_id, index) => `cfg${index}`)).concat(['inlineConfig']).join(', ')})
`
}
}

export const publicPathTemplate: NuxtTemplate = {
filename: 'paths.mjs',
getContents ({ nuxt }) {
Expand Down
13 changes: 12 additions & 1 deletion packages/schema/src/config/_common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -747,5 +747,16 @@ export default {
* @version 3
* @deprecated Use `runtimeConfig` option with `public` key (`runtimeConfig.public.*`)
*/
publicRuntimeConfig: {}
publicRuntimeConfig: {},

/**
* Additional app configuration
*
* For programmatic usage and type support, you can directly provide app config with this option.
* It will be merged with all `app.config` files as default value.
*
* @type {typeof import('../src/types/config').AppConfig}
* @version 3
*/
appConfig: {},
}
30 changes: 24 additions & 6 deletions packages/schema/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ export interface NuxtOptions extends ConfigSchema {
_layers: ResolvedConfig<NuxtConfig>[]
}

export interface ViteConfig extends ViteUserConfig {
/**
* Options passed to @vitejs/plugin-vue
* @see https://github.com/vitejs/vite/tree/main/packages/plugin-vue
*/
vue?: VuePluginOptions
}


// -- Runtime Config --

type RuntimeConfigNamespace = Record<string, any>

export interface PublicRuntimeConfig extends RuntimeConfigNamespace { }
Expand All @@ -29,10 +40,17 @@ export interface RuntimeConfig extends PrivateRuntimeConfig, RuntimeConfigNamesp
public: PublicRuntimeConfig
}

export interface ViteConfig extends ViteUserConfig {
/**
* Options passed to @vitejs/plugin-vue
* @see https://github.com/vitejs/vite/tree/main/packages/plugin-vue
*/
vue?: VuePluginOptions
// -- App Config --

// Reserved namespaces to avoid breaking changes if Nuxt starts to use them
// type ReservedAppConfigKeys =
// 'baseURL' | 'buildAssetsDir' | 'cdnURL' |
// 'public' | 'private' | 'app'| 'config' | 'head' |
// 'nuxt' | 'nitro' | 'internal' | 'runtime'

type AppConfigNamespace = Record<string, any> // & Partial<Record<ReservedAppConfigKeys, never>>
pi0 marked this conversation as resolved.
Show resolved Hide resolved

export interface AppConfig extends AppConfigNamespace {
theme?: Record<string, any>
}

1 change: 1 addition & 0 deletions packages/schema/src/types/nuxt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export interface NuxtApp {
layouts: Record<string, NuxtLayout>
middleware: NuxtMiddleware[]
templates: NuxtTemplate[]
configs: string[]
}

type _TemplatePlugin = Omit<NuxtPlugin, 'src'> & NuxtTemplate
Expand Down
13 changes: 13 additions & 0 deletions playground/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// import { defineAppConfig } from '#imports'
pi0 marked this conversation as resolved.
Show resolved Hide resolved
import type { AppConfig } from '@nuxt/schema'

const defineAppConfig = (config: AppConfig) => config

export default defineAppConfig({
custom: '123',
nested: {
foo: {
bar: 'fdfdf'
}
}
})
6 changes: 5 additions & 1 deletion playground/app.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<script setup lang="ts">
const appConfig = useAppConfig()
watch(appConfig, () => {
console.log('App config updated:', appConfig)
})
</script>

<template>
<!-- Edit this file to play around with Nuxt but never commit changes! -->
<div>
Nuxt 3 Playground
Hello World {{ appConfig }}
</div>
</template>

Expand Down
4 changes: 4 additions & 0 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { defineNuxtConfig } from 'nuxt'

export default defineNuxtConfig({
appConfig: {
custom: '123',
nested: { foo: { bar: 'baz' } }
}
})
23 changes: 21 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,13 @@ __metadata:
languageName: node
linkType: hard

"@babel/standalone@npm:^7.18.11":
version: 7.18.11
resolution: "@babel/standalone@npm:7.18.11"
checksum: 8a1c8e527c41ba7e2b6c80f7eb4e84cf82fd8697c38416fac548cb5442a83bae9eaf3c2bbcdc398d4149df54d4f1020f31337d784ede634fa1f3de1a6b5fad7c
languageName: node
linkType: hard

"@babel/template@npm:^7.0.0, @babel/template@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/template@npm:7.18.6"
Expand Down Expand Up @@ -1737,7 +1744,7 @@ __metadata:
unbuild: latest
unctx: ^2.0.0
unimport: ^0.6.5
untyped: ^0.4.4
untyped: ^0.4.5
languageName: unknown
linkType: soft

Expand Down Expand Up @@ -9982,7 +9989,7 @@ __metadata:
unenv: ^0.5.2
unimport: ^0.6.5
unplugin: ^0.8.1
untyped: ^0.4.4
untyped: ^0.4.5
vue: ^3.2.37
vue-bundle-renderer: ^0.3.9
vue-meta: next
Expand Down Expand Up @@ -13222,6 +13229,18 @@ __metadata:
languageName: node
linkType: hard

"untyped@npm:^0.4.5":
version: 0.4.5
resolution: "untyped@npm:0.4.5"
dependencies:
"@babel/core": ^7.18.10
"@babel/standalone": ^7.18.11
"@babel/types": ^7.18.10
scule: ^0.3.2
checksum: fd09347048145a3f87dbbd03174a3053e5a01b0e174c49bca23e6acddb2dd234a024795033d2c0d72fe8dbded3f8c56fb54580fcee893703f380e15095ddd3e2
languageName: node
linkType: hard

"upath@npm:^2.0.1":
version: 2.0.1
resolution: "upath@npm:2.0.1"
Expand Down