Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: experimental composition api via useEvent() ans async context support #1546

Merged
merged 8 commits into from Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -111,6 +111,7 @@
"std-env": "^3.3.3",
"ufo": "^1.2.0",
"uncrypto": "^0.1.3",
"unctx": "^2.3.1",
"unenv": "^1.6.1",
"unimport": "^3.1.3",
"unstorage": "^1.8.0"
Expand Down
18 changes: 18 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/imports.ts
Expand Up @@ -16,6 +16,7 @@ export const nitroImports: Preset[] = [
"defineRenderHandler",
"getRouteRules",
"useAppConfig",
"useEvent",
],
},
];
2 changes: 2 additions & 0 deletions src/rollup/config.ts
Expand Up @@ -184,6 +184,8 @@ export const getRollupConfig = (nitro: Nitro): RollupConfig => {
// @ts-expect-error
"versions.nitro": version,
"versions?.nitro": version,
// Internal
_asyncContext: nitro.options.experimental.asyncContext,
};

// Universal import.meta
Expand Down
10 changes: 10 additions & 0 deletions src/runtime/app.ts
Expand Up @@ -23,6 +23,7 @@ import { useRuntimeConfig } from "./config";
import { cachedEventHandler } from "./cache";
import { normalizeFetchResponse } from "./utils";
import { createRouteRulesHandler, getRouteRulesForPath } from "./route-rules";
import { NitroAsyncContext, nitroAsyncContext } from "./context";
import type { $Fetch, NitroFetchRequest } from "nitropack";
import { plugins } from "#internal/nitro/virtual/plugins";
import errorHandler from "#internal/nitro/virtual/error-handler";
Expand Down Expand Up @@ -172,6 +173,15 @@ function createNitroApp(): NitroApp {

h3App.use(config.app.baseURL as string, router.handler);

// Experimental async context support
if (import.meta._asyncContext) {
const _handler = h3App.handler;
h3App.handler = (event) => {
const ctx: NitroAsyncContext = { event };
return nitroAsyncContext.callAsync(ctx, () => _handler(event));
};
}

const app: NitroApp = {
hooks,
h3App,
Expand Down
32 changes: 32 additions & 0 deletions src/runtime/context.ts
@@ -0,0 +1,32 @@
import { AsyncLocalStorage } from "node:async_hooks";
import { H3Event, createError } from "h3";
import { getContext } from "unctx";

export interface NitroAsyncContext {
event: H3Event;
}

export const nitroAsyncContext = getContext<NitroAsyncContext>("nitro-app", {
asyncContext: import.meta._asyncContext,
AsyncLocalStorage: import.meta._asyncContext ? AsyncLocalStorage : undefined,
});

/**
*
* Access to the current Nitro request event.
*
* @experimental Requires `experimental.asyncContext: true` config to work.
*
*/
export function useEvent(): H3Event {
try {
return nitroAsyncContext.use().event;
} catch {
const hint = import.meta._asyncContext
? "Please report this issue!"
: "Enable the experimental async context support using `experimental.asyncContext: true`";
throw createError({
message: `Nitro request context is not available. ${hint}`,
});
}
}
1 change: 1 addition & 0 deletions src/runtime/index.ts
Expand Up @@ -5,3 +5,4 @@ export * from "./plugin";
export * from "./renderer";
export { getRouteRules } from "./route-rules";
export { useStorage } from "./storage";
export { useEvent } from "./context";
1 change: 1 addition & 0 deletions src/types/global.ts
@@ -1,6 +1,7 @@
import type { NitroOptions } from "./nitro";

export interface NitroStaticBuildFlags {
_asyncContext?: boolean;
dev?: boolean;
client?: boolean;
nitro?: boolean;
Expand Down
4 changes: 4 additions & 0 deletions src/types/nitro.ts
Expand Up @@ -227,6 +227,10 @@ export interface NitroOptions extends PresetOptions {
* See https://github.com/microsoft/TypeScript/pull/51669
*/
typescriptBundlerResolution?: boolean;
/**
* Enable native async context support for useEvent()
*/
asyncContext?: boolean;
};
future: {
nativeSWR: boolean;
Expand Down
1 change: 1 addition & 0 deletions test/fixture/nitro.config.ts
Expand Up @@ -82,5 +82,6 @@ export default defineNitroConfig({
},
experimental: {
openAPI: true,
asyncContext: true,
},
});
12 changes: 12 additions & 0 deletions test/fixture/routes/context.ts
@@ -0,0 +1,12 @@
export default defineEventHandler(async () => {
await Promise.resolve(setTimeout(() => {}, 10));
return await useTest();
});

function useTest() {
return {
context: {
path: useEvent().path,
},
};
}