Skip to content

Commit

Permalink
fix(hooks): enabled use of useAppConfig() and useRuntimeConfig() with…
Browse files Browse the repository at this point in the history
…in request hooks

If the nitro context isn't already initialized, it will be initialized, rather than error.
  • Loading branch information
boenrobot committed Jun 4, 2024
1 parent 40a0007 commit 009620c
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 8 deletions.
2 changes: 1 addition & 1 deletion docs/1.guide/97.configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default defineNuxtConfig({
```
::

You can now access the runtime config using `useRuntimeConfig(event)`. Use `useRuntimeConfig(event)` within event handlers and utilities and **avoid** calling it in ambient global contexts. This could lead to unexpected behavior such sharing the same runtime config across different requests.
You can now access the runtime config using `useRuntimeConfig(event)`. Use `useRuntimeConfig(event)` within event handlers, hooks and utilities and **avoid** calling it in ambient global contexts. This could lead to unexpected behavior such as sharing the same runtime config across different requests.

::code-group
```ts [api/example.get.ts (nitro)]
Expand Down
8 changes: 4 additions & 4 deletions src/runtime/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ export function useRuntimeConfig<
return _sharedRuntimeConfig as T;
}
// Reuse cached runtime config from event context
if (event.context.nitro.runtimeConfig) {
if (event.context.nitro?.runtimeConfig) {
return event.context.nitro.runtimeConfig;
}
// Prepare runtime config for event context
const runtimeConfig = klona(_inlineRuntimeConfig) as T;
applyEnv(runtimeConfig, envOptions);
event.context.nitro.runtimeConfig = runtimeConfig;
(event.context.nitro ??= {}).runtimeConfig = runtimeConfig;
return runtimeConfig;
}

Expand All @@ -46,12 +46,12 @@ export function useAppConfig(event?: H3Event) {
return _sharedAppConfig;
}
// Reuse cached app config from event context
if (event.context.nitro.appConfig) {
if (event.context.nitro?.appConfig) {
return event.context.nitro.appConfig;
}
// Prepare app config for event context
const appConfig = klona(_inlineAppConfig);
event.context.nitro.appConfig = appConfig;
(event.context.nitro ??= {}).appConfig = appConfig;
return appConfig;
}

Expand Down
2 changes: 1 addition & 1 deletion src/types/h3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ declare module "h3" {
captureError: CaptureError;
}
interface H3Context {
nitro: {
nitro?: {
_waitUntilPromises?: Promise<unknown>[];
/** @experimental */
errors: { error?: Error; context: CapturedErrorContext }[];
Expand Down
6 changes: 4 additions & 2 deletions test/fixture/middleware/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
process.env.NITRO_DYNAMIC = "from-env";

export default eventHandler((event) => {
const appConfig = useAppConfig(event);
appConfig.dynamic = "from-middleware";
if (event.path.startsWith("/config")) {
const appConfig = useAppConfig(event);
appConfig.dynamic = "from-middleware";
}
});
17 changes: 17 additions & 0 deletions test/fixture/plugins/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export default defineNitroPlugin((app) => {
app.hooks.hook("request", (event) => {
if (event.path.startsWith("/hooks")) {
const qs = getQuery(event);
switch (qs.change) {
case "useAppConfig": {
useAppConfig(event).dynamic = "from-hook";
break;
}
case "useRuntimeConfig": {
useRuntimeConfig(event).dynamic = "from-hook";
break;
}
}
}
});
});
14 changes: 14 additions & 0 deletions test/fixture/routes/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const sharedAppConfig = useAppConfig();
const sharedRuntimeConfig = useRuntimeConfig();

export default eventHandler((event) => {
const appConfig = useAppConfig(event);
const runtimeConfig = useRuntimeConfig(event);

return {
sharedAppConfig,
appConfig,
runtimeConfig,
sharedRuntimeConfig,
};
});
122 changes: 122 additions & 0 deletions test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,128 @@ export function testNitro(
});
});

describe("hooks", () => {
it("no modifications", async () => {
const { data } = await callHandler({
url: "/hooks",
});
expect(data).toMatchObject({
appConfig: {
dynamic: "initial",
"app-config": true,
"nitro-config": true,
"server-config": true,
},
runtimeConfig: {
dynamic: "from-env",
url: "https://test.com",
app: {
baseURL: "/",
},
},
sharedAppConfig: {
dynamic: "initial",
"app-config": true,
"nitro-config": true,
"server-config": true,
},
sharedRuntimeConfig: {
dynamic:
// TODO
ctx.preset.includes("cloudflare") ||
ctx.preset === "vercel-edge" ||
ctx.preset === "nitro-dev"
? "initial"
: "from-env",
// url: "https://test.com",
app: {
baseURL: "/",
},
},
});
});

it("modify appConfig", async () => {
const { data } = await callHandler({
url: "/hooks?change=useAppConfig",
});
expect(data).toMatchObject({
appConfig: {
dynamic: "from-hook",
"app-config": true,
"nitro-config": true,
"server-config": true,
},
runtimeConfig: {
dynamic: "from-env",
url: "https://test.com",
app: {
baseURL: "/",
},
},
sharedAppConfig: {
dynamic: "initial",
"app-config": true,
"nitro-config": true,
"server-config": true,
},
sharedRuntimeConfig: {
dynamic:
// TODO
ctx.preset.includes("cloudflare") ||
ctx.preset === "vercel-edge" ||
ctx.preset === "nitro-dev"
? "initial"
: "from-env",
// url: "https://test.com",
app: {
baseURL: "/",
},
},
});
});

it("modify runtimeConfig", async () => {
const { data } = await callHandler({
url: "/hooks?change=useRuntimeConfig",
});
expect(data).toMatchObject({
appConfig: {
dynamic: "initial",
"app-config": true,
"nitro-config": true,
"server-config": true,
},
runtimeConfig: {
dynamic: "from-hook",
url: "https://test.com",
app: {
baseURL: "/",
},
},
sharedAppConfig: {
dynamic: "initial",
"app-config": true,
"nitro-config": true,
"server-config": true,
},
sharedRuntimeConfig: {
dynamic:
// TODO
ctx.preset.includes("cloudflare") ||
ctx.preset === "vercel-edge" ||
ctx.preset === "nitro-dev"
? "initial"
: "from-env",
// url: "https://test.com",
app: {
baseURL: "/",
},
},
});
});
});

if (ctx.nitro!.options.timing) {
it("set server timing header", async () => {
const { status, headers } = await callHandler({
Expand Down

0 comments on commit 009620c

Please sign in to comment.