From c54292b17f56609e81fecea29eafcbf01f303ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Guilloux?= Date: Wed, 24 Aug 2022 16:25:18 +0200 Subject: [PATCH 1/9] feat(app.config): improve merging strategy --- examples/advanced/config-extends/app.config.ts | 17 ++++++++++++++++- .../advanced/config-extends/base/app.config.ts | 16 +++++++++++++++- packages/nuxt/src/core/templates.ts | 12 ++++++++++-- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/examples/advanced/config-extends/app.config.ts b/examples/advanced/config-extends/app.config.ts index 909ae0dc97f..3c5a7dfa648 100644 --- a/examples/advanced/config-extends/app.config.ts +++ b/examples/advanced/config-extends/app.config.ts @@ -1,5 +1,20 @@ export default defineAppConfig({ foo: 'user', bar: 'user', - baz: 'base' + baz: 'base', + array: [ + 'user', + 'user', + 'user' + ], + arrayNested: { + nested: { + key: 'user', + array: [ + 'user', + 'user', + 'user' + ] + } + } }) diff --git a/examples/advanced/config-extends/base/app.config.ts b/examples/advanced/config-extends/base/app.config.ts index b94ce0b0b05..e69f21f4c66 100644 --- a/examples/advanced/config-extends/base/app.config.ts +++ b/examples/advanced/config-extends/base/app.config.ts @@ -1,4 +1,18 @@ export default defineAppConfig({ bar: 'base', - baz: 'base' + baz: 'base', + array: [ + 'base', + 'base', + 'base' + ], + arrayNested: { + nested: { + array: [ + 'base', + 'base', + 'base' + ] + } + } }) diff --git a/packages/nuxt/src/core/templates.ts b/packages/nuxt/src/core/templates.ts index cc5dc9055dc..f7ac96f6b06 100644 --- a/packages/nuxt/src/core/templates.ts +++ b/packages/nuxt/src/core/templates.ts @@ -207,12 +207,20 @@ export const appConfigTemplate: NuxtTemplate = { write: true, getContents: ({ app, nuxt }) => { return ` -import defu from 'defu' +import { createDefu } from 'defu' const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)} ${app.configs.map((id: string, index: number) => `import ${`cfg${index}`} from ${JSON.stringify(id)}`).join('\n')} -export default defu(${app.configs.map((_id: string, index: number) => `cfg${index}`).concat(['inlineConfig']).join(', ')}) + +const merge = createDefu((obj, key, value) => { + if (obj[key] && Array.isArray(obj[key])) { + obj[key] = value + return true + } +}) + +export default merge(${app.configs.map((_id: string, index: number) => `cfg${index}`).concat(['inlineConfig']).join(', ')}) ` } } From 00cf0e444660ce41bbda95ae094b8ad2019a3c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Guilloux?= Date: Wed, 24 Aug 2022 16:36:08 +0200 Subject: [PATCH 2/9] feat(app.config): cleanup nested keys on HMR --- packages/nuxt/src/app/config.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/nuxt/src/app/config.ts b/packages/nuxt/src/app/config.ts index b8d504a0728..aa414e6e295 100644 --- a/packages/nuxt/src/app/config.ts +++ b/packages/nuxt/src/app/config.ts @@ -21,10 +21,18 @@ if (process.dev) { const appConfig = useAppConfig() if (newConfig && appConfig) { deepAssign(appConfig, newConfig) - for (const key in appConfig) { - if (!(key in newConfig)) { - delete (appConfig as any)[key] - } + deepDelete(appConfig, newConfig) + } + } + + function deepDelete (obj: any, newObj: any) { + for (const key in obj) { + if (!(key in newObj)) { + delete (obj as any)[key] + } + + if (typeof obj[key] === 'object' && newObj[key]) { + deepDelete(obj[key], newObj[key]) } } } From bdd222a85341de5cccb18cd29002efe30629e33c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Guilloux?= Date: Wed, 24 Aug 2022 16:47:26 +0200 Subject: [PATCH 3/9] feat(app.config): support setAppConfig/updateAppConfig functions --- packages/nuxt/src/app/config.ts | 66 +++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/packages/nuxt/src/app/config.ts b/packages/nuxt/src/app/config.ts index aa414e6e295..32fcd3b8f2c 100644 --- a/packages/nuxt/src/app/config.ts +++ b/packages/nuxt/src/app/config.ts @@ -7,6 +7,28 @@ import __appConfig from '#build/app.config.mjs' // Workaround for vite HMR with virtual modules export const _getAppConfig = () => __appConfig as AppConfig +function deepDelete (obj: any, newObj: any) { + for (const key in obj) { + if (!(key in newObj)) { + delete (obj as any)[key] + } + + if (typeof obj[key] === 'object' && newObj[key]) { + deepDelete(obj[key], newObj[key]) + } + } +} +function deepAssign (obj: any, newObj: any) { + for (const key in newObj) { + const val = newObj[key] + if (val !== null && typeof val === 'object') { + deepAssign(obj[key], val) + } else { + obj[key] = val + } + } +} + export function useAppConfig (): AppConfig { const nuxtApp = useNuxtApp() if (!nuxtApp._appConfig) { @@ -15,6 +37,27 @@ export function useAppConfig (): AppConfig { return nuxtApp._appConfig } +/** + * Deep assign the current appConfig with the new one. + * + * Will preserve existing properties. + */ +export function updateAppConfig (appConfig: Partial) { + const nuxtApp = useNuxtApp() + if (!nuxtApp._appConfig) { + nuxtApp._appConfig = reactive(__appConfig) as AppConfig + } + deepAssign(nuxtApp._appConfig, appConfig) +} + +/** + * Overwrites the current app config with the new one. + */ +export function setAppConfig (appConfig: AppConfig) { + const nuxtApp = useNuxtApp() + nuxtApp._appConfig = appConfig +} + // HMR Support if (process.dev) { function applyHMR (newConfig: AppConfig) { @@ -25,29 +68,6 @@ if (process.dev) { } } - function deepDelete (obj: any, newObj: any) { - for (const key in obj) { - if (!(key in newObj)) { - delete (obj as any)[key] - } - - if (typeof obj[key] === 'object' && newObj[key]) { - deepDelete(obj[key], newObj[key]) - } - } - } - - function deepAssign (obj: any, newObj: any) { - for (const key in newObj) { - const val = newObj[key] - if (val !== null && typeof val === 'object') { - deepAssign(obj[key], val) - } else { - obj[key] = val - } - } - } - // Vite if (import.meta.hot) { import.meta.hot.accept((newModule) => { From 6317a1d35db08d530c58541031b3aa6d8f5fd1b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Guilloux?= Date: Wed, 24 Aug 2022 17:06:30 +0200 Subject: [PATCH 4/9] feat(app.config): add new helpers to unimport presets --- packages/nuxt/src/app/config.ts | 1 + packages/nuxt/src/imports/presets.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/nuxt/src/app/config.ts b/packages/nuxt/src/app/config.ts index 32fcd3b8f2c..2ba694e4ade 100644 --- a/packages/nuxt/src/app/config.ts +++ b/packages/nuxt/src/app/config.ts @@ -18,6 +18,7 @@ function deepDelete (obj: any, newObj: any) { } } } + function deepAssign (obj: any, newObj: any) { for (const key in newObj) { const val = newObj[key] diff --git a/packages/nuxt/src/imports/presets.ts b/packages/nuxt/src/imports/presets.ts index 5655717733f..f56451402a6 100644 --- a/packages/nuxt/src/imports/presets.ts +++ b/packages/nuxt/src/imports/presets.ts @@ -51,6 +51,8 @@ const appPreset = defineUnimportPreset({ 'createError', 'defineNuxtLink', 'useAppConfig', + 'setAppConfig', + 'updateAppConfig', 'defineAppConfig', 'preloadComponents', 'prefetchComponents' From 1b07424dce819355e2d479bf73639cb70e2e3289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Guilloux?= Date: Wed, 24 Aug 2022 17:18:12 +0200 Subject: [PATCH 5/9] feat(app.config): use arrayFn for merging --- examples/advanced/config-extends/base/app.config.ts | 2 +- packages/nuxt/src/core/templates.ts | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/examples/advanced/config-extends/base/app.config.ts b/examples/advanced/config-extends/base/app.config.ts index e69f21f4c66..e55c3765c32 100644 --- a/examples/advanced/config-extends/base/app.config.ts +++ b/examples/advanced/config-extends/base/app.config.ts @@ -1,7 +1,7 @@ export default defineAppConfig({ bar: 'base', baz: 'base', - array: [ + array: () => [ 'base', 'base', 'base' diff --git a/packages/nuxt/src/core/templates.ts b/packages/nuxt/src/core/templates.ts index f7ac96f6b06..ca3f5c27d55 100644 --- a/packages/nuxt/src/core/templates.ts +++ b/packages/nuxt/src/core/templates.ts @@ -207,20 +207,13 @@ export const appConfigTemplate: NuxtTemplate = { write: true, getContents: ({ app, nuxt }) => { return ` -import { createDefu } from 'defu' +import { defuArrayFn } from 'defu' const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)} ${app.configs.map((id: string, index: number) => `import ${`cfg${index}`} from ${JSON.stringify(id)}`).join('\n')} -const merge = createDefu((obj, key, value) => { - if (obj[key] && Array.isArray(obj[key])) { - obj[key] = value - return true - } -}) - -export default merge(${app.configs.map((_id: string, index: number) => `cfg${index}`).concat(['inlineConfig']).join(', ')}) +export default defuArrayFn(${app.configs.map((_id: string, index: number) => `cfg${index}`).concat(['inlineConfig']).join(', ')}) ` } } From 82e5a532ae9728c397f367b11ccfe3681d43d353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Guilloux?= Date: Wed, 24 Aug 2022 18:07:14 +0200 Subject: [PATCH 6/9] refactor(review): apply comments --- .../3.api/1.composables/update-app-config.md | 20 +++++++++++++++++++ .../advanced/config-extends/app.config.ts | 12 +---------- packages/nuxt/src/app/config.ts | 15 ++------------ packages/nuxt/src/core/templates.ts | 4 ++-- packages/nuxt/src/imports/presets.ts | 1 - 5 files changed, 25 insertions(+), 27 deletions(-) create mode 100644 docs/content/3.api/1.composables/update-app-config.md diff --git a/docs/content/3.api/1.composables/update-app-config.md b/docs/content/3.api/1.composables/update-app-config.md new file mode 100644 index 00000000000..e81309727a5 --- /dev/null +++ b/docs/content/3.api/1.composables/update-app-config.md @@ -0,0 +1,20 @@ +# `updateAppConfig` + +::StabilityEdge +:: + +Updates [app config](/guide/features/app-config): + +**Usage:** + +```js +const appConfig = useAppConfig() // { foo: 'bar' } + +const newAppConfig = { foo: 'baz' } + +updateAppConfig(newAppConfig) + +console.log(appConfig) // { foo: 'baz' } +``` + +::ReadMore{link="/guide/features/app-config"} diff --git a/examples/advanced/config-extends/app.config.ts b/examples/advanced/config-extends/app.config.ts index 3c5a7dfa648..6ffbebb636c 100644 --- a/examples/advanced/config-extends/app.config.ts +++ b/examples/advanced/config-extends/app.config.ts @@ -6,15 +6,5 @@ export default defineAppConfig({ 'user', 'user', 'user' - ], - arrayNested: { - nested: { - key: 'user', - array: [ - 'user', - 'user', - 'user' - ] - } - } + ] }) diff --git a/packages/nuxt/src/app/config.ts b/packages/nuxt/src/app/config.ts index 2ba694e4ade..dbf64604524 100644 --- a/packages/nuxt/src/app/config.ts +++ b/packages/nuxt/src/app/config.ts @@ -44,19 +44,8 @@ export function useAppConfig (): AppConfig { * Will preserve existing properties. */ export function updateAppConfig (appConfig: Partial) { - const nuxtApp = useNuxtApp() - if (!nuxtApp._appConfig) { - nuxtApp._appConfig = reactive(__appConfig) as AppConfig - } - deepAssign(nuxtApp._appConfig, appConfig) -} - -/** - * Overwrites the current app config with the new one. - */ -export function setAppConfig (appConfig: AppConfig) { - const nuxtApp = useNuxtApp() - nuxtApp._appConfig = appConfig + const _appConfig = useAppConfig() + deepAssign(_appConfig, appConfig) } // HMR Support diff --git a/packages/nuxt/src/core/templates.ts b/packages/nuxt/src/core/templates.ts index ca3f5c27d55..8d0e8334fd8 100644 --- a/packages/nuxt/src/core/templates.ts +++ b/packages/nuxt/src/core/templates.ts @@ -207,13 +207,13 @@ export const appConfigTemplate: NuxtTemplate = { write: true, getContents: ({ app, nuxt }) => { return ` -import { defuArrayFn } from 'defu' +import { defuFn } from 'defu' const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)} ${app.configs.map((id: string, index: number) => `import ${`cfg${index}`} from ${JSON.stringify(id)}`).join('\n')} -export default defuArrayFn(${app.configs.map((_id: string, index: number) => `cfg${index}`).concat(['inlineConfig']).join(', ')}) +export default defuFn(${app.configs.map((_id: string, index: number) => `cfg${index}`).concat(['inlineConfig']).join(', ')}) ` } } diff --git a/packages/nuxt/src/imports/presets.ts b/packages/nuxt/src/imports/presets.ts index f56451402a6..6985af5b27e 100644 --- a/packages/nuxt/src/imports/presets.ts +++ b/packages/nuxt/src/imports/presets.ts @@ -51,7 +51,6 @@ const appPreset = defineUnimportPreset({ 'createError', 'defineNuxtLink', 'useAppConfig', - 'setAppConfig', 'updateAppConfig', 'defineAppConfig', 'preloadComponents', From 5074bf24ecd0e1691787598ddd25f60d59d61600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Guilloux?= Date: Wed, 24 Aug 2022 18:17:49 +0200 Subject: [PATCH 7/9] refactor(review): apply review comments --- packages/nuxt/src/app/config.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/app/config.ts b/packages/nuxt/src/app/config.ts index dbf64604524..84f93a1627b 100644 --- a/packages/nuxt/src/app/config.ts +++ b/packages/nuxt/src/app/config.ts @@ -4,16 +4,19 @@ import { useNuxtApp } from './nuxt' // @ts-ignore import __appConfig from '#build/app.config.mjs' +type DeepPartial = T extends Function ? T : T extends Record ? { [P in keyof T]?: DeepPartial } : T + // Workaround for vite HMR with virtual modules export const _getAppConfig = () => __appConfig as AppConfig function deepDelete (obj: any, newObj: any) { for (const key in obj) { + const val = newObj[key] if (!(key in newObj)) { delete (obj as any)[key] } - if (typeof obj[key] === 'object' && newObj[key]) { + if (val !== null && typeof val === 'object') { deepDelete(obj[key], newObj[key]) } } @@ -43,7 +46,7 @@ export function useAppConfig (): AppConfig { * * Will preserve existing properties. */ -export function updateAppConfig (appConfig: Partial) { +export function updateAppConfig (appConfig: DeepPartial) { const _appConfig = useAppConfig() deepAssign(_appConfig, appConfig) } From 1a6dfb710bcde6d8447bceb51a611356ab7204af Mon Sep 17 00:00:00 2001 From: pooya parsa Date: Wed, 24 Aug 2022 18:22:04 +0200 Subject: [PATCH 8/9] Update docs/content/3.api/1.composables/update-app-config.md --- docs/content/3.api/1.composables/update-app-config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/3.api/1.composables/update-app-config.md b/docs/content/3.api/1.composables/update-app-config.md index e81309727a5..26b0752d946 100644 --- a/docs/content/3.api/1.composables/update-app-config.md +++ b/docs/content/3.api/1.composables/update-app-config.md @@ -3,7 +3,7 @@ ::StabilityEdge :: -Updates [app config](/guide/features/app-config): +Updates [app config](/guide/features/app-config) using deep assignment. Existing (nested) properties will be preserved. **Usage:** From c2bf3a712b75db4590d546aa9fd74872c28841bb Mon Sep 17 00:00:00 2001 From: pooya parsa Date: Wed, 24 Aug 2022 18:26:50 +0200 Subject: [PATCH 9/9] Update update-app-config.md --- docs/content/3.api/1.composables/update-app-config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/3.api/1.composables/update-app-config.md b/docs/content/3.api/1.composables/update-app-config.md index 26b0752d946..9d7eecb93ed 100644 --- a/docs/content/3.api/1.composables/update-app-config.md +++ b/docs/content/3.api/1.composables/update-app-config.md @@ -3,7 +3,7 @@ ::StabilityEdge :: -Updates [app config](/guide/features/app-config) using deep assignment. Existing (nested) properties will be preserved. +Updates [app config](/guide/features/app-config) using deep assignment. Existing (nested) properties will be preserved. **Usage:**