From ae808766004e68bf1f39eec75de7ca1ab487a1a5 Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Sun, 10 Dec 2023 22:11:20 +0100 Subject: [PATCH 01/11] feat: add `setRuntimeConfig` module utility --- build.config.ts | 4 ++- module-utils.d.ts | 1 + package.json | 2 ++ pnpm-lock.yaml | 7 +++++ src/core/server.ts | 9 ++++-- src/module-utils/index.mjs | 1 + src/module-utils/runtime-config.ts | 47 ++++++++++++++++++++++++++++++ 7 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 module-utils.d.ts create mode 100644 src/module-utils/index.mjs create mode 100644 src/module-utils/runtime-config.ts diff --git a/build.config.ts b/build.config.ts index 73e15ac4f..e9269e9d8 100644 --- a/build.config.ts +++ b/build.config.ts @@ -9,6 +9,7 @@ export default defineBuildConfig({ 'src/experimental', 'src/config', 'src/module.ts', + isStub ? { input: 'src/module-utils/', outDir: 'dist/module-utils', format: 'esm' } : 'src/module-utils/index.mjs', 'src/vitest-environment', isStub ? { input: 'src/runtime-utils/', outDir: 'dist/runtime-utils', format: 'esm' } : 'src/runtime-utils/index.mjs', { input: 'src/runtime/', outDir: 'dist/runtime', format: 'esm' } @@ -17,5 +18,6 @@ export default defineBuildConfig({ "#app/entry", "#build/root-component.mjs", "#imports", - ] + ], + failOnWarn: false, }) diff --git a/module-utils.d.ts b/module-utils.d.ts new file mode 100644 index 000000000..ace1f7c13 --- /dev/null +++ b/module-utils.d.ts @@ -0,0 +1 @@ +export * from './dist/module-utils/index.mjs' diff --git a/package.json b/package.json index 02cd6296d..bb820f5f0 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "./e2e": "./dist/e2e.mjs", "./experimental": "./dist/experimental.mjs", "./module": "./dist/module.mjs", + "./module-utils": "./dist/module-utils/index.mjs", "./runtime": "./dist/runtime-utils/index.mjs", "./vitest-environment": "./dist/vitest-environment.mjs" }, @@ -81,6 +82,7 @@ "nuxt": "3.8.2", "playwright-core": "1.40.1", "rollup": "4.7.0", + "scule": "^1.1.1", "semver": "7.5.4", "unbuild": "latest", "unimport": "3.6.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b99cd33d4..c9582d679 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,6 +146,9 @@ importers: rollup: specifier: 4.7.0 version: 4.7.0 + scule: + specifier: ^1.1.1 + version: 1.1.1 semver: specifier: 7.5.4 version: 7.5.4 @@ -2509,6 +2512,7 @@ packages: dependencies: is-glob: 4.0.3 micromatch: 4.0.5 + napi-wasm: 1.1.0 bundledDependencies: - napi-wasm @@ -8270,6 +8274,9 @@ packages: engines: {node: ^14 || ^16 || >=18} hasBin: true + /napi-wasm@1.1.0: + resolution: {integrity: sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg==} + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} diff --git a/src/core/server.ts b/src/core/server.ts index 1305f7b5e..2332749d2 100644 --- a/src/core/server.ts +++ b/src/core/server.ts @@ -6,11 +6,12 @@ import * as _kit from '@nuxt/kit' import { resolve } from 'pathe' import { useTestContext } from './context' + // @ts-expect-error type cast // eslint-disable-next-line const kit: typeof _kit = _kit.default || _kit -export async function startServer () { +export async function startServer (env: Record = {}) { const ctx = useTestContext() await stopServer() const host = '127.0.0.1' @@ -26,7 +27,8 @@ export async function startServer () { _PORT: String(port), // Used by internal _dev command PORT: String(port), HOST: host, - NODE_ENV: 'development' + NODE_ENV: 'development', + ...env } }) await waitForPort(port, { retries: 32, host }).catch(() => {}) @@ -53,7 +55,8 @@ export async function startServer () { ...process.env, PORT: String(port), HOST: host, - NODE_ENV: 'test' + NODE_ENV: 'test', + ...env } }) await waitForPort(port, { retries: 20, host }) diff --git a/src/module-utils/index.mjs b/src/module-utils/index.mjs new file mode 100644 index 000000000..4e7377450 --- /dev/null +++ b/src/module-utils/index.mjs @@ -0,0 +1 @@ +export { setRuntimeConfig } from './runtime-config' \ No newline at end of file diff --git a/src/module-utils/runtime-config.ts b/src/module-utils/runtime-config.ts new file mode 100644 index 000000000..fba1c8227 --- /dev/null +++ b/src/module-utils/runtime-config.ts @@ -0,0 +1,47 @@ +import { snakeCase } from "scule" +import { startServer } from "../e2e"; + +const NUXT_ENV_PREFIX = 'NUXT_' + +export function flattenObject(obj: Record = {}) { + const flattened: Record = {} + + for (const key in obj) { + if (!(key in obj)) continue + + const entry = obj[key] + if (typeof entry !== 'object' || entry == null) { + flattened[key] = obj[key] + continue + } + const flatObject = flattenObject(entry as Record) + + for (const x in flatObject) { + if (!(x in flatObject)) continue + + flattened[key + '_' + x] = flatObject[x] + } + } + + return flattened +} + +export function convertObjectToConfig(obj: Record) { + const makeEnvKey = (str: string) => `${NUXT_ENV_PREFIX}${snakeCase(str).toUpperCase()}` + + const env: Record = {} + const flattened = flattenObject(obj) + for (const key in flattened) { + env[makeEnvKey(key)] = flattened[key] + } + + return env +} + +export async function setRuntimeConfig(env: Record) { + const converted = convertObjectToConfig(env) + await startServer(converted) + + // restore + return async () => startServer() +} From b7355dc436478ddc37f3fabb58c73e641a384f7b Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Sun, 10 Dec 2023 22:11:39 +0100 Subject: [PATCH 02/11] test: confirm `setRuntimeConfig` works --- examples/module/test/basic.test.ts | 15 ++++++++++++++- examples/module/test/fixtures/basic/app.vue | 3 ++- .../module/test/fixtures/basic/nuxt.config.ts | 5 +++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/examples/module/test/basic.test.ts b/examples/module/test/basic.test.ts index 2e3df6728..fbb5cd102 100644 --- a/examples/module/test/basic.test.ts +++ b/examples/module/test/basic.test.ts @@ -1,6 +1,7 @@ import { fileURLToPath } from 'node:url' import { describe, expect, it } from 'vitest' import { $fetch, setup } from '@nuxt/test-utils/e2e' +import { setRuntimeConfig } from '@nuxt/test-utils/module-utils' describe('ssr', async () => { await setup({ @@ -10,6 +11,18 @@ describe('ssr', async () => { it('renders the index page', async () => { // Get response to a server-rendered page with `$fetch`. const html = await $fetch('/') - expect(html).toContain('
basic
') + expect(html).toContain('
basic original value
') + }) + + + it('changes runtime config and restarts', async () => { + const restoreConfig = await setRuntimeConfig({ public: { myValue: 'overwritten by test!' } }) + + const html = await $fetch('/') + expect(html).toContain('
basic overwritten by test!
') + + await restoreConfig() + const htmlRestored = await $fetch('/') + expect(htmlRestored).toContain('
basic original value
') }) }) diff --git a/examples/module/test/fixtures/basic/app.vue b/examples/module/test/fixtures/basic/app.vue index 29a9c81fa..0e4c395fe 100644 --- a/examples/module/test/fixtures/basic/app.vue +++ b/examples/module/test/fixtures/basic/app.vue @@ -1,6 +1,7 @@ diff --git a/examples/module/test/fixtures/basic/nuxt.config.ts b/examples/module/test/fixtures/basic/nuxt.config.ts index 1bc2f7ccd..5b1ef6ef3 100644 --- a/examples/module/test/fixtures/basic/nuxt.config.ts +++ b/examples/module/test/fixtures/basic/nuxt.config.ts @@ -1,6 +1,11 @@ import MyModule from '../../../src/module' export default defineNuxtConfig({ + runtimeConfig: { + public: { + myValue: 'original value', + }, + }, modules: [ MyModule ] From fe1c8d3ee80053e6607188c55ad26dd857efe459 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 11 Dec 2023 17:48:18 +0000 Subject: [PATCH 03/11] refactor: move to e2e utils --- build.config.ts | 4 +--- examples/module/test/basic.test.ts | 5 ++--- module-utils.d.ts | 1 - package.json | 1 - src/{module-utils => core}/runtime-config.ts | 4 ++-- src/core/server.ts | 11 +++++++---- src/e2e.ts | 1 + src/module-utils/index.mjs | 1 - 8 files changed, 13 insertions(+), 15 deletions(-) delete mode 100644 module-utils.d.ts rename src/{module-utils => core}/runtime-config.ts (93%) delete mode 100644 src/module-utils/index.mjs diff --git a/build.config.ts b/build.config.ts index e9269e9d8..73e15ac4f 100644 --- a/build.config.ts +++ b/build.config.ts @@ -9,7 +9,6 @@ export default defineBuildConfig({ 'src/experimental', 'src/config', 'src/module.ts', - isStub ? { input: 'src/module-utils/', outDir: 'dist/module-utils', format: 'esm' } : 'src/module-utils/index.mjs', 'src/vitest-environment', isStub ? { input: 'src/runtime-utils/', outDir: 'dist/runtime-utils', format: 'esm' } : 'src/runtime-utils/index.mjs', { input: 'src/runtime/', outDir: 'dist/runtime', format: 'esm' } @@ -18,6 +17,5 @@ export default defineBuildConfig({ "#app/entry", "#build/root-component.mjs", "#imports", - ], - failOnWarn: false, + ] }) diff --git a/examples/module/test/basic.test.ts b/examples/module/test/basic.test.ts index fbb5cd102..fbe39c3c0 100644 --- a/examples/module/test/basic.test.ts +++ b/examples/module/test/basic.test.ts @@ -1,7 +1,6 @@ import { fileURLToPath } from 'node:url' import { describe, expect, it } from 'vitest' -import { $fetch, setup } from '@nuxt/test-utils/e2e' -import { setRuntimeConfig } from '@nuxt/test-utils/module-utils' +import { $fetch, setRuntimeConfig, setup } from '@nuxt/test-utils/e2e' describe('ssr', async () => { await setup({ @@ -17,7 +16,7 @@ describe('ssr', async () => { it('changes runtime config and restarts', async () => { const restoreConfig = await setRuntimeConfig({ public: { myValue: 'overwritten by test!' } }) - + const html = await $fetch('/') expect(html).toContain('
basic overwritten by test!
') diff --git a/module-utils.d.ts b/module-utils.d.ts deleted file mode 100644 index ace1f7c13..000000000 --- a/module-utils.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './dist/module-utils/index.mjs' diff --git a/package.json b/package.json index 2f1715c09..5ac9f3de2 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "./e2e": "./dist/e2e.mjs", "./experimental": "./dist/experimental.mjs", "./module": "./dist/module.mjs", - "./module-utils": "./dist/module-utils/index.mjs", "./runtime": "./dist/runtime-utils/index.mjs", "./vitest-environment": "./dist/vitest-environment.mjs" }, diff --git a/src/module-utils/runtime-config.ts b/src/core/runtime-config.ts similarity index 93% rename from src/module-utils/runtime-config.ts rename to src/core/runtime-config.ts index fba1c8227..cb5c2dba1 100644 --- a/src/module-utils/runtime-config.ts +++ b/src/core/runtime-config.ts @@ -1,5 +1,5 @@ -import { snakeCase } from "scule" -import { startServer } from "../e2e"; +import { snakeCase } from 'scule' +import { startServer } from './server' const NUXT_ENV_PREFIX = 'NUXT_' diff --git a/src/core/server.ts b/src/core/server.ts index 2332749d2..cbd267b36 100644 --- a/src/core/server.ts +++ b/src/core/server.ts @@ -6,12 +6,15 @@ import * as _kit from '@nuxt/kit' import { resolve } from 'pathe' import { useTestContext } from './context' - // @ts-expect-error type cast // eslint-disable-next-line const kit: typeof _kit = _kit.default || _kit -export async function startServer (env: Record = {}) { +export interface StartServerOptions { + env?: Record +} + +export async function startServer (options: StartServerOptions = {}) { const ctx = useTestContext() await stopServer() const host = '127.0.0.1' @@ -28,7 +31,7 @@ export async function startServer (env: Record = {}) { PORT: String(port), HOST: host, NODE_ENV: 'development', - ...env + ...options.env } }) await waitForPort(port, { retries: 32, host }).catch(() => {}) @@ -56,7 +59,7 @@ export async function startServer (env: Record = {}) { PORT: String(port), HOST: host, NODE_ENV: 'test', - ...env + ...options.env } }) await waitForPort(port, { retries: 20, host }) diff --git a/src/e2e.ts b/src/e2e.ts index f8604f58d..0fef3e7e8 100644 --- a/src/e2e.ts +++ b/src/e2e.ts @@ -5,4 +5,5 @@ export * from './core/nuxt' export * from './core/server' export * from './core/setup/index' export * from './core/run' +export * from './core/runtime-config' export * from './core/types' diff --git a/src/module-utils/index.mjs b/src/module-utils/index.mjs deleted file mode 100644 index 4e7377450..000000000 --- a/src/module-utils/index.mjs +++ /dev/null @@ -1 +0,0 @@ -export { setRuntimeConfig } from './runtime-config' \ No newline at end of file From cc5305d6707b58662ae93cb6d72b98980f1aeab4 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 11 Dec 2023 17:49:04 +0000 Subject: [PATCH 04/11] chore: remove space --- examples/module/test/basic.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/module/test/basic.test.ts b/examples/module/test/basic.test.ts index fbe39c3c0..2e6602354 100644 --- a/examples/module/test/basic.test.ts +++ b/examples/module/test/basic.test.ts @@ -13,7 +13,6 @@ describe('ssr', async () => { expect(html).toContain('
basic original value
') }) - it('changes runtime config and restarts', async () => { const restoreConfig = await setRuntimeConfig({ public: { myValue: 'overwritten by test!' } }) From ca54fc32827150cd950df71b374a2ebaed8ce7fa Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 11 Dec 2023 17:57:24 +0000 Subject: [PATCH 05/11] refactor: avoid exposing other utils --- src/e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2e.ts b/src/e2e.ts index 0fef3e7e8..7ed2bb1d2 100644 --- a/src/e2e.ts +++ b/src/e2e.ts @@ -5,5 +5,5 @@ export * from './core/nuxt' export * from './core/server' export * from './core/setup/index' export * from './core/run' -export * from './core/runtime-config' +export { setRuntimeConfig } from './core/runtime-config' export * from './core/types' From 0e60b7002d98b53595944cdfdbe76a8bf7a5f5a5 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 11 Dec 2023 18:43:11 +0000 Subject: [PATCH 06/11] fix: move `scule` to dependency --- package.json | 2 +- pnpm-lock.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 5ac9f3de2..e50d35672 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "pathe": "^1.1.1", "perfect-debounce": "^1.0.0", "radix3": "^1.1.0", + "scule": "^1.1.1", "std-env": "^3.6.0", "ufo": "^1.3.2", "unenv": "^1.8.0", @@ -81,7 +82,6 @@ "nuxt": "3.8.2", "playwright-core": "1.40.1", "rollup": "4.8.0", - "scule": "^1.1.1", "semver": "7.5.4", "unbuild": "latest", "unimport": "3.6.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d6a27a12e..547084fb0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -64,6 +64,9 @@ importers: radix3: specifier: ^1.1.0 version: 1.1.0 + scule: + specifier: ^1.1.1 + version: 1.1.1 std-env: specifier: ^3.6.0 version: 3.6.0 @@ -146,9 +149,6 @@ importers: rollup: specifier: 4.8.0 version: 4.8.0 - scule: - specifier: ^1.1.1 - version: 1.1.1 semver: specifier: 7.5.4 version: 7.5.4 From 46df8505b8562bf9d932796ab45edac218c9d285 Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Mon, 11 Dec 2023 22:51:55 +0100 Subject: [PATCH 07/11] fix: `setRuntimeConfig` not passing env in options object --- src/core/runtime-config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/runtime-config.ts b/src/core/runtime-config.ts index cb5c2dba1..33e17d269 100644 --- a/src/core/runtime-config.ts +++ b/src/core/runtime-config.ts @@ -38,9 +38,9 @@ export function convertObjectToConfig(obj: Record) { return env } -export async function setRuntimeConfig(env: Record) { - const converted = convertObjectToConfig(env) - await startServer(converted) +export async function setRuntimeConfig(config: Record) { + const env = convertObjectToConfig(config) + await startServer({ env }) // restore return async () => startServer() From 8bf8cc71c5a1504ae87b0ab41e9e1749f270ec12 Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Mon, 11 Dec 2023 23:27:42 +0100 Subject: [PATCH 08/11] feat: add optional `envPrefix` argument to `setRuntimeConfig` --- src/core/runtime-config.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/core/runtime-config.ts b/src/core/runtime-config.ts index 33e17d269..ba4a9ccdd 100644 --- a/src/core/runtime-config.ts +++ b/src/core/runtime-config.ts @@ -1,8 +1,6 @@ import { snakeCase } from 'scule' import { startServer } from './server' -const NUXT_ENV_PREFIX = 'NUXT_' - export function flattenObject(obj: Record = {}) { const flattened: Record = {} @@ -26,8 +24,8 @@ export function flattenObject(obj: Record = {}) { return flattened } -export function convertObjectToConfig(obj: Record) { - const makeEnvKey = (str: string) => `${NUXT_ENV_PREFIX}${snakeCase(str).toUpperCase()}` +export function convertObjectToConfig(obj: Record, envPrefix: string) { + const makeEnvKey = (str: string) => `${envPrefix}${snakeCase(str).toUpperCase()}` const env: Record = {} const flattened = flattenObject(obj) @@ -38,8 +36,8 @@ export function convertObjectToConfig(obj: Record) { return env } -export async function setRuntimeConfig(config: Record) { - const env = convertObjectToConfig(config) +export async function setRuntimeConfig(config: Record, envPrefix = 'NUXT_') { + const env = convertObjectToConfig(config, envPrefix) await startServer({ env }) // restore From 235755b35ac82fa5ae16a23c3085199ede6264bd Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Thu, 21 Dec 2023 18:16:54 +0100 Subject: [PATCH 09/11] fix: `process.send` is `undefined` --- src/core/server.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/core/server.ts b/src/core/server.ts index cbd267b36..dd7997f19 100644 --- a/src/core/server.ts +++ b/src/core/server.ts @@ -50,17 +50,15 @@ export async function startServer (options: StartServerOptions = {}) { ctx.serverProcess.kill() throw lastError || new Error('Timeout waiting for dev server!') } else { - ctx.serverProcess = execa('node', [ - resolve(ctx.nuxt!.options.nitro.output!.dir!, 'server/index.mjs') - ], { + ctx.serverProcess = execaNode(resolve(ctx.nuxt!.options.nitro.output!.dir!, 'server/index.mjs'), { stdio: 'inherit', env: { ...process.env, PORT: String(port), HOST: host, NODE_ENV: 'test', - ...options.env - } + ...options.env, + }, }) await waitForPort(port, { retries: 20, host }) } From 49383f1806c907e303c9c8fe016163c9289b5a10 Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Thu, 21 Dec 2023 18:18:03 +0100 Subject: [PATCH 10/11] feat: change runtime config using ipc signal --- examples/module/test/basic.test.ts | 40 ++++++++++++++----- examples/module/test/fixtures/basic/app.vue | 6 ++- .../fixtures/basic/plugins/ipc-listener.ts | 30 ++++++++++++++ .../test/fixtures/basic/server/api/config.ts | 4 ++ src/core/runtime-config.ts | 28 ++++++++++--- src/core/server.ts | 2 +- 6 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 examples/module/test/fixtures/basic/plugins/ipc-listener.ts create mode 100644 examples/module/test/fixtures/basic/server/api/config.ts diff --git a/examples/module/test/basic.test.ts b/examples/module/test/basic.test.ts index 2e6602354..a1ffd5ba6 100644 --- a/examples/module/test/basic.test.ts +++ b/examples/module/test/basic.test.ts @@ -1,26 +1,48 @@ import { fileURLToPath } from 'node:url' import { describe, expect, it } from 'vitest' -import { $fetch, setRuntimeConfig, setup } from '@nuxt/test-utils/e2e' +import { $fetch, getBrowser, setRuntimeConfig, setup, url } from '@nuxt/test-utils/e2e' describe('ssr', async () => { await setup({ rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)), + browser: true, }) it('renders the index page', async () => { // Get response to a server-rendered page with `$fetch`. const html = await $fetch('/') - expect(html).toContain('
basic original value
') + expect(html).toContain('original value') }) - it('changes runtime config and restarts', async () => { - const restoreConfig = await setRuntimeConfig({ public: { myValue: 'overwritten by test!' } }) + it('changes runtime config client-side', async () => { + const browser = await getBrowser() + const page = await browser.newPage() + await page.goto(url('/')) - const html = await $fetch('/') - expect(html).toContain('
basic overwritten by test!
') + const el = page.locator('#runtime') + expect(await el.innerText()).to.equal('original value') + + await page.evaluate(() => { + window.__NUXT_TEST_RUNTIME_CONFIG_SETTER__({ public: { myValue: 'overwritten by test!' } }) + }) + + expect(await el.innerText()).to.equal('overwritten by test!') + }) + + it('changes runtime config in server route', async () => { + const originalConfig = await $fetch('/api/config') + expect(originalConfig.public.myValue).to.equal('original value') - await restoreConfig() - const htmlRestored = await $fetch('/') - expect(htmlRestored).toContain('
basic original value
') + await setRuntimeConfig({ public: { myValue: 'overwritten by test!' } }) + + const newConfig = await $fetch('/api/config') + expect(newConfig.public.myValue).to.equal('overwritten by test!') + }) + + it('changes runtime config', async () => { + await setRuntimeConfig({ public: { myValue: 'overwritten by test!' } }) + + const html = await $fetch('/') + expect(html).toContain('overwritten by test!') }) }) diff --git a/examples/module/test/fixtures/basic/app.vue b/examples/module/test/fixtures/basic/app.vue index 0e4c395fe..22f0dbf4a 100644 --- a/examples/module/test/fixtures/basic/app.vue +++ b/examples/module/test/fixtures/basic/app.vue @@ -1,7 +1,9 @@ diff --git a/examples/module/test/fixtures/basic/plugins/ipc-listener.ts b/examples/module/test/fixtures/basic/plugins/ipc-listener.ts new file mode 100644 index 000000000..b1bcd800b --- /dev/null +++ b/examples/module/test/fixtures/basic/plugins/ipc-listener.ts @@ -0,0 +1,30 @@ +import defu from 'defu' +import { defineNuxtPlugin } from 'nuxt/app' + +declare global { + interface Window { + __NUXT_TEST_RUNTIME_CONFIG_SETTER__: (env: { public: Record }) => void + } +} + +export default defineNuxtPlugin(() => { + const config = useRuntimeConfig() + + if (process.client) { + window.__NUXT_TEST_RUNTIME_CONFIG_SETTER__ ??= (env: { public: Record }) => { + config.public = defu(env.public, config.public) + } + } + + if (process.server) { + process.on('message', (msg: { type: string; value: Record }) => { + if (msg.type === 'update:runtime-config') { + for (const [key, value] of Object.entries(msg.value)) { + process.env[key] = value + } + + process!.send!({ type: 'confirm:runtime-config' }) + } + }) + } +}) diff --git a/examples/module/test/fixtures/basic/server/api/config.ts b/examples/module/test/fixtures/basic/server/api/config.ts new file mode 100644 index 000000000..f07457e24 --- /dev/null +++ b/examples/module/test/fixtures/basic/server/api/config.ts @@ -0,0 +1,4 @@ +export default defineEventHandler(async (event) => { + const config = useRuntimeConfig(event) + return config +}) diff --git a/src/core/runtime-config.ts b/src/core/runtime-config.ts index ba4a9ccdd..a95a90c07 100644 --- a/src/core/runtime-config.ts +++ b/src/core/runtime-config.ts @@ -1,5 +1,5 @@ import { snakeCase } from 'scule' -import { startServer } from './server' +import { useTestContext } from './context' export function flattenObject(obj: Record = {}) { const flattened: Record = {} @@ -26,20 +26,36 @@ export function flattenObject(obj: Record = {}) { export function convertObjectToConfig(obj: Record, envPrefix: string) { const makeEnvKey = (str: string) => `${envPrefix}${snakeCase(str).toUpperCase()}` - + const env: Record = {} const flattened = flattenObject(obj) for (const key in flattened) { env[makeEnvKey(key)] = flattened[key] } - + return env } export async function setRuntimeConfig(config: Record, envPrefix = 'NUXT_') { const env = convertObjectToConfig(config, envPrefix) - await startServer({ env }) + const ctx = useTestContext() + + let updatedConfig = false + ctx.serverProcess?.once('message', (msg: { type: string }) => { + if (msg.type === 'confirm:runtime-config') { + updatedConfig = true + } + }) - // restore - return async () => startServer() + ctx.serverProcess?.send({ type: 'update:runtime-config', value: env }) + + // Wait for confirmation to ensure + for (let i = 0; i < 10; i++) { + if (updatedConfig) break + await new Promise((resolve) => setTimeout(resolve, 1000)) + } + + if (!updatedConfig) { + throw new Error('Missing confirmation of runtime config update!') + } } diff --git a/src/core/server.ts b/src/core/server.ts index dd7997f19..e0080d619 100644 --- a/src/core/server.ts +++ b/src/core/server.ts @@ -1,4 +1,4 @@ -import { execa } from 'execa' +import { execa, execaNode } from 'execa' import { getRandomPort, waitForPort } from 'get-port-please' import type { FetchOptions } from 'ofetch' import { $fetch as _$fetch, fetch as _fetch } from 'ofetch' From 5aafee4a3b19b481347ff2c070c3aaa043ff47e9 Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Thu, 21 Dec 2023 20:20:13 +0100 Subject: [PATCH 11/11] fix: use `restart` for server config update --- examples/module/test/basic.test.ts | 7 ++++--- src/core/runtime-config.ts | 10 ++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/examples/module/test/basic.test.ts b/examples/module/test/basic.test.ts index a1ffd5ba6..c9d9413e9 100644 --- a/examples/module/test/basic.test.ts +++ b/examples/module/test/basic.test.ts @@ -40,9 +40,10 @@ describe('ssr', async () => { }) it('changes runtime config', async () => { - await setRuntimeConfig({ public: { myValue: 'overwritten by test!' } }) + expect(await $fetch('/')).toContain('original value') - const html = await $fetch('/') - expect(html).toContain('overwritten by test!') + await setRuntimeConfig({ public: { myValue: 'overwritten by test!' } }, { restart: true }) + + expect(await $fetch('/')).toContain('overwritten by test!') }) }) diff --git a/src/core/runtime-config.ts b/src/core/runtime-config.ts index a95a90c07..b4edcbf17 100644 --- a/src/core/runtime-config.ts +++ b/src/core/runtime-config.ts @@ -1,5 +1,6 @@ import { snakeCase } from 'scule' import { useTestContext } from './context' +import { startServer } from './server' export function flattenObject(obj: Record = {}) { const flattened: Record = {} @@ -36,10 +37,15 @@ export function convertObjectToConfig(obj: Record, envPrefix: s return env } -export async function setRuntimeConfig(config: Record, envPrefix = 'NUXT_') { - const env = convertObjectToConfig(config, envPrefix) +type SetRuntimeConfigOptions = { envPrefix?: string; restart?: boolean } +export async function setRuntimeConfig(config: Record, options: SetRuntimeConfigOptions = {}) { + const env = convertObjectToConfig(config, options.envPrefix ?? 'NUXT_') const ctx = useTestContext() + if (options.restart) { + return await startServer({ env }) + } + let updatedConfig = false ctx.serverProcess?.once('message', (msg: { type: string }) => { if (msg.type === 'confirm:runtime-config') {