Skip to content

Commit 81210d0

Browse files
authored
feat: export H3Core (#1127)
1 parent 0cd52f5 commit 81210d0

File tree

5 files changed

+91
-37
lines changed

5 files changed

+91
-37
lines changed

src/h3.ts

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { H3Event } from "./event.ts";
33
import { toResponse, kNotFound } from "./response.ts";
44
import { callMiddleware, normalizeMiddleware } from "./middleware.ts";
55

6-
import type { RouterContext } from "rou3";
6+
import type { RouterContext, MatchedRoute } from "rou3";
77
import type {
88
FetchHandler,
99
H3Config,
@@ -22,15 +22,15 @@ import type {
2222
} from "./types/h3.ts";
2323
import type { ServerRequest } from "srvx";
2424

25-
export type H3 = H3Type;
26-
27-
export const H3 = /* @__PURE__ */ (() => {
25+
export const H3Core = /* @__PURE__ */ (() => {
2826
// prettier-ignore
2927
const HTTPMethods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT", "TRACE" ] as const;
3028

31-
class H3 implements Omit<H3Type, Lowercase<(typeof HTTPMethods)[number]>> {
29+
class H3Core
30+
implements Omit<H3Type, Lowercase<(typeof HTTPMethods)[number]>>
31+
{
3232
_middleware: Middleware[];
33-
_routes?: RouterContext<H3Route>;
33+
_routes: H3Route[] = [];
3434

3535
readonly config: H3Config;
3636

@@ -90,10 +90,14 @@ export const H3 = /* @__PURE__ */ (() => {
9090
return this as unknown as H3Type;
9191
}
9292

93+
_findRoute(_event: H3Event): MatchedRoute<H3Route> | void {}
94+
95+
_addRoute(_route: H3Route): void {
96+
this._routes.push(_route);
97+
}
98+
9399
handler(event: H3Event): unknown | Promise<unknown> {
94-
const route = this._routes
95-
? findRoute(this._routes, event.req.method, event.url.pathname)
96-
: undefined;
100+
const route = this._findRoute(event);
97101
if (route) {
98102
event.context.params = route.params;
99103
event.context.matchedRoute = route.data;
@@ -126,9 +130,6 @@ export const H3 = /* @__PURE__ */ (() => {
126130
handler: RouteHandler,
127131
opts?: RouteOptions,
128132
): H3Type {
129-
if (!this._routes) {
130-
this._routes = createRouter();
131-
}
132133
const _method = (method || "").toUpperCase();
133134
let _handler: EventHandler;
134135
let meta: H3RouteMeta | undefined = opts?.meta;
@@ -139,13 +140,13 @@ export const H3 = /* @__PURE__ */ (() => {
139140
meta = { ...(handler as EventHandler).meta, ...meta };
140141
}
141142
route = new URL(route, "h://_").pathname;
142-
addRoute(this._routes, _method, route, {
143+
this._addRoute({
143144
method: _method as HTTPMethod,
144145
route,
145146
handler: _handler,
146147
middleware: opts?.middleware,
147148
meta,
148-
} satisfies H3Route);
149+
});
149150
return this as unknown as H3Type;
150151
}
151152

@@ -162,14 +163,17 @@ export const H3 = /* @__PURE__ */ (() => {
162163
opts = arg2 as MiddlewareOptions;
163164
}
164165
this._middleware.push(
165-
normalizeMiddleware(fn, route ? { ...opts, route } : opts),
166+
normalizeMiddleware(
167+
fn as Middleware,
168+
route ? { ...opts, route } : opts,
169+
),
166170
);
167171
return this as unknown as H3Type;
168172
}
169173
}
170174

171175
for (const method of HTTPMethods) {
172-
(H3 as any).prototype[method.toLowerCase()] = function (
176+
(H3Core as any).prototype[method.toLowerCase()] = function (
173177
this: H3Type,
174178
route: string,
175179
handler: EventHandler | H3Type,
@@ -179,8 +183,29 @@ export const H3 = /* @__PURE__ */ (() => {
179183
};
180184
}
181185

182-
return H3;
183-
})() as unknown as typeof H3Type;
186+
return H3Core;
187+
})() as unknown as { new (config?: H3Config): H3Type };
188+
189+
export class H3 extends H3Core {
190+
/**
191+
* @internal
192+
*/
193+
_rou3: RouterContext<H3Route>;
194+
195+
constructor(config: H3Config = {}) {
196+
super(config);
197+
this._rou3 = createRouter();
198+
}
199+
200+
override _findRoute(_event: H3Event): MatchedRoute<H3Route> | void {
201+
return findRoute(this._rou3, _event.req.method, _event.url.pathname);
202+
}
203+
204+
override _addRoute(_route: H3Route): void {
205+
addRoute(this._rou3, _route.method, _route.route!, _route);
206+
super._addRoute(_route);
207+
}
208+
}
184209

185210
export function toRequest(
186211
_request: ServerRequest | URL | string,

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export type {
1515

1616
export { definePlugin } from "./types/h3.ts";
1717

18-
export { H3 } from "./h3.ts";
18+
export { H3Core, H3 } from "./h3.ts";
1919

2020
// Event
2121

src/types/h3.ts

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { EventHandler, Middleware } from "./handler.ts";
33
import type { HTTPError } from "../error.ts";
44
import type { MaybePromise } from "./_utils.ts";
55
import type { ServerRequest } from "srvx";
6-
import type { RouterContext } from "rou3";
6+
import type { MatchedRoute } from "rou3";
77
import type { H3Event } from "../event.ts";
88

99
// --- Misc ---
@@ -71,7 +71,7 @@ export declare class H3 {
7171
/**
7272
* @internal
7373
*/
74-
_routes?: RouterContext<H3Route>;
74+
_routes?: H3Route[];
7575

7676
/**
7777
* H3 instance config.
@@ -102,10 +102,20 @@ export declare class H3 {
102102
context?: H3EventContext,
103103
): Response | Promise<Response>;
104104

105+
/**
106+
* @internal
107+
*/
108+
_findRoute(_event: H3Event): MatchedRoute<H3Route> | void;
109+
110+
/**
111+
* @internal
112+
*/
113+
_addRoute(_route: H3Route): void;
114+
105115
/**
106116
* Immediately register an H3 plugin.
107117
*/
108-
register(plugin: H3Plugin): H3;
118+
register(plugin: H3Plugin): this;
109119

110120
/**
111121
* An h3 compatible event handler useful to compose multiple h3 app instances.
@@ -115,13 +125,13 @@ export declare class H3 {
115125
/**
116126
* Mount a `.fetch` compatible server (like Hono or Elysia) to the H3 app.
117127
*/
118-
mount(base: string, input: FetchHandler | { fetch: FetchHandler }): H3;
128+
mount(base: string, input: FetchHandler | { fetch: FetchHandler }): this;
119129

120130
/**
121131
* Register a global middleware.
122132
*/
123-
use(route: string, handler: Middleware | H3, opts?: MiddlewareOptions): H3;
124-
use(handler: Middleware | H3, opts?: MiddlewareOptions): H3;
133+
use(route: string, handler: Middleware | H3, opts?: MiddlewareOptions): this;
134+
use(handler: Middleware | H3, opts?: MiddlewareOptions): this;
125135

126136
/**
127137
* Register a route handler for the specified HTTP method and route.
@@ -131,20 +141,20 @@ export declare class H3 {
131141
route: string,
132142
handler: RouteHandler,
133143
opts?: RouteOptions,
134-
): H3;
144+
): this;
135145

136146
/**
137147
* Register a route handler for all HTTP methods.
138148
*/
139-
all(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
140-
141-
get(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
142-
post(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
143-
put(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
144-
delete(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
145-
patch(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
146-
head(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
147-
options(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
148-
connect(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
149-
trace(route: string, handler: RouteHandler, opts?: RouteOptions): H3;
149+
all(route: string, handler: RouteHandler, opts?: RouteOptions): this;
150+
151+
get(route: string, handler: RouteHandler, opts?: RouteOptions): this;
152+
post(route: string, handler: RouteHandler, opts?: RouteOptions): this;
153+
put(route: string, handler: RouteHandler, opts?: RouteOptions): this;
154+
delete(route: string, handler: RouteHandler, opts?: RouteOptions): this;
155+
patch(route: string, handler: RouteHandler, opts?: RouteOptions): this;
156+
head(route: string, handler: RouteHandler, opts?: RouteOptions): this;
157+
options(route: string, handler: RouteHandler, opts?: RouteOptions): this;
158+
connect(route: string, handler: RouteHandler, opts?: RouteOptions): this;
159+
trace(route: string, handler: RouteHandler, opts?: RouteOptions): this;
150160
}

test/bench/bundle.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,24 @@ describe("benchmark", () => {
2424
expect(bundle.gzipSize).toBeLessThanOrEqual(4000); // <4kb
2525
});
2626

27+
it("bundle size (H3Core)", async () => {
28+
const code = /* js */ `
29+
import { H3Core } from "../../src/index.ts";
30+
const app = new H3Core();
31+
`;
32+
const bundle = await getBundleSize(code);
33+
if (inspect) {
34+
return;
35+
}
36+
if (process.env.DEBUG) {
37+
console.log(
38+
`Bundle size (H3Core): ${bundle.bytes} (gzip: ${bundle.gzipSize})`,
39+
);
40+
}
41+
expect(bundle.bytes).toBeLessThanOrEqual(8000); // <8kb
42+
expect(bundle.gzipSize).toBeLessThanOrEqual(3500); // <3.5kb
43+
});
44+
2745
it("bundle size (defineHandler)", async () => {
2846
const code = /* js */ `
2947
import { defineHandler } from "h3";

test/unit/package.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ describe("h3 package", () => {
88
expect(exportNames).toMatchInlineSnapshot(`
99
[
1010
"H3",
11+
"H3Core",
1112
"H3Error",
1213
"H3Event",
1314
"HTTPError",

0 commit comments

Comments
 (0)