From 311b078442489e4b9bf2b16a564a146c3f8744e1 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Thu, 31 Oct 2024 16:29:09 +0900 Subject: [PATCH 1/5] refactor: use `#` for private methods to reduce the bundle size --- src/context.ts | 22 +++++++++--------- src/hono-base.ts | 58 ++++++++++++++++++++++++------------------------ src/request.ts | 24 ++++++++++---------- 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/context.ts b/src/context.ts index a23942e02..b7e876572 100644 --- a/src/context.ts +++ b/src/context.ts @@ -690,6 +690,8 @@ export class Context< }) } + #newResponse = this.newResponse + /** * `.body()` can return the HTTP response. * You can set headers with `.header()` and set HTTP status code with `.status`. @@ -717,8 +719,8 @@ export class Context< headers?: HeaderRecord ): Response => { return typeof arg === 'number' - ? this.newResponse(data, arg, headers) - : this.newResponse(data, arg) + ? this.#newResponse(data, arg, headers) + : this.#newResponse(data, arg) } /** @@ -750,8 +752,8 @@ export class Context< this.#preparedHeaders['content-type'] = TEXT_PLAIN // @ts-expect-error `Response` due to missing some types-only keys return typeof arg === 'number' - ? this.newResponse(text, arg, headers) - : this.newResponse(text, arg) + ? this.#newResponse(text, arg, headers) + : this.#newResponse(text, arg) } /** @@ -779,7 +781,7 @@ export class Context< this.#preparedHeaders['content-type'] = 'application/json; charset=UTF-8' /* eslint-disable @typescript-eslint/no-explicit-any */ return ( - typeof arg === 'number' ? this.newResponse(body, arg, headers) : this.newResponse(body, arg) + typeof arg === 'number' ? this.#newResponse(body, arg, headers) : this.#newResponse(body, arg) ) as any } @@ -794,14 +796,14 @@ export class Context< if (typeof html === 'object') { return resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then((html) => { return typeof arg === 'number' - ? this.newResponse(html, arg, headers) - : this.newResponse(html, arg) + ? this.#newResponse(html, arg, headers) + : this.#newResponse(html, arg) }) } return typeof arg === 'number' - ? this.newResponse(html as string, arg, headers) - : this.newResponse(html as string, arg) + ? this.#newResponse(html as string, arg, headers) + : this.#newResponse(html as string, arg) } /** @@ -825,7 +827,7 @@ export class Context< ): Response & TypedResponse => { this.#headers ??= new Headers() this.#headers.set('Location', location) - return this.newResponse(null, status ?? 302) as any + return this.#newResponse(null, status ?? 302) as any } /** diff --git a/src/hono-base.ts b/src/hono-base.ts index ea23ec260..88a5ec7ce 100644 --- a/src/hono-base.ts +++ b/src/hono-base.ts @@ -130,11 +130,11 @@ class Hono { if (typeof handler !== 'string') { - this.addRoute(method, this.#path, handler) + this.#addRoute(method, this.#path, handler) } }) return this as any @@ -147,7 +147,7 @@ class Hono { - this.addRoute(m.toUpperCase(), this.#path, handler) + this.#addRoute(m.toUpperCase(), this.#path, handler) }) } } @@ -163,7 +163,7 @@ class Hono { - this.addRoute(METHOD_NAME_ALL, this.#path, handler) + this.#addRoute(METHOD_NAME_ALL, this.#path, handler) }) return this as any } @@ -174,7 +174,7 @@ class Hono { + #clone(): Hono { const clone = new Hono({ router: this.router, getPath: this.getPath, @@ -183,8 +183,8 @@ class Hono { let handler - if (app.errorHandler === errorHandler) { + if (app.#errorHandler === errorHandler) { handler = r.handler } else { handler = async (c: Context, next: Next) => - (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res + (await compose([], app.#errorHandler)(c, () => r.handler(c, next))).res ;(handler as any)[COMPOSED_HANDLER] = r.handler } - subApp.addRoute(r.method, r.path, handler) + subApp.#addRoute(r.method, r.path, handler) }) return this } @@ -243,7 +243,7 @@ class Hono(path: SubPath): Hono> { - const subApp = this.clone() + const subApp = this.#clone() subApp._basePath = mergePath(this._basePath, path) return subApp } @@ -265,7 +265,7 @@ class Hono): Hono => { - this.errorHandler = handler + this.#errorHandler = handler return this } @@ -285,7 +285,7 @@ class Hono): Hono => { - this.notFoundHandler = handler + this.#notFoundHandler = handler return this } @@ -370,11 +370,11 @@ class Hono) { + #handleError(err: unknown, c: Context) { if (err instanceof Error) { - return this.errorHandler(err, c) + return this.#errorHandler(err, c) } throw err } - private dispatch( + #dispatch( request: Request, executionCtx: ExecutionContext | FetchEventLike | undefined, env: E['Bindings'], @@ -398,7 +398,7 @@ class Hono - new Response(null, await this.dispatch(request, executionCtx, env, 'GET')))() + new Response(null, await this.#dispatch(request, executionCtx, env, 'GET')))() } const path = this.getPath(request, { env }) @@ -409,7 +409,7 @@ class Hono try { res = matchResult[0][0][0][0](c, async () => { - c.res = await this.notFoundHandler(c) + c.res = await this.#notFoundHandler(c) }) } catch (err) { - return this.handleError(err, c) + return this.#handleError(err, c) } return res instanceof Promise ? res .then( (resolved: Response | undefined) => - resolved || (c.finalized ? c.res : this.notFoundHandler(c)) + resolved || (c.finalized ? c.res : this.#notFoundHandler(c)) ) - .catch((err: Error) => this.handleError(err, c)) - : res ?? this.notFoundHandler(c) + .catch((err: Error) => this.#handleError(err, c)) + : res ?? this.#notFoundHandler(c) } - const composed = compose(matchResult[0], this.errorHandler, this.notFoundHandler) + const composed = compose(matchResult[0], this.#errorHandler, this.#notFoundHandler) return (async () => { try { @@ -446,7 +446,7 @@ class Hono Response | Promise = (request, ...rest) => { - return this.dispatch(request, rest[1], rest[0], request.method) + return this.#dispatch(request, rest[1], rest[0], request.method) } /** @@ -511,7 +511,7 @@ class Hono { - event.respondWith(this.dispatch(event.request, event, undefined, event.request.method)) + event.respondWith(this.#dispatch(event.request, event, undefined, event.request.method)) }) } } diff --git a/src/request.ts b/src/request.ts index a3f68f9d2..68c710c35 100644 --- a/src/request.ts +++ b/src/request.ts @@ -91,21 +91,21 @@ export class HonoRequest

{ param(key: string): string | undefined param(): Simplify>>> param(key?: string): unknown { - return key ? this.getDecodedParam(key) : this.getAllDecodedParams() + return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams() } - private getDecodedParam(key: string): string | undefined { + #getDecodedParam(key: string): string | undefined { const paramKey = this.#matchResult[0][this.routeIndex][1][key] - const param = this.getParamValue(paramKey) + const param = this.#getParamValue(paramKey) return param ? (/\%/.test(param) ? tryDecodeURIComponent(param) : param) : undefined } - private getAllDecodedParams(): Record { + #getAllDecodedParams(): Record { const decoded: Record = {} const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]) for (const key of keys) { - const value = this.getParamValue(this.#matchResult[0][this.routeIndex][1][key]) + const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]) if (value && typeof value === 'string') { decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value } @@ -114,7 +114,7 @@ export class HonoRequest

{ return decoded } - private getParamValue(paramKey: any): string | undefined { + #getParamValue(paramKey: any): string | undefined { return this.#matchResult[1] ? this.#matchResult[1][paramKey as any] : paramKey } @@ -208,7 +208,7 @@ export class HonoRequest

{ return (this.bodyCache.parsedBody ??= await parseBody(this, options)) } - private cachedBody = (key: keyof Body) => { + #cachedBody = (key: keyof Body) => { const { bodyCache, raw } = this const cachedBody = bodyCache[key] @@ -242,7 +242,7 @@ export class HonoRequest

{ * ``` */ json(): Promise { - return this.cachedBody('json') + return this.#cachedBody('json') } /** @@ -258,7 +258,7 @@ export class HonoRequest

{ * ``` */ text(): Promise { - return this.cachedBody('text') + return this.#cachedBody('text') } /** @@ -274,7 +274,7 @@ export class HonoRequest

{ * ``` */ arrayBuffer(): Promise { - return this.cachedBody('arrayBuffer') + return this.#cachedBody('arrayBuffer') } /** @@ -288,7 +288,7 @@ export class HonoRequest

{ * @see https://hono.dev/docs/api/request#blob */ blob(): Promise { - return this.cachedBody('blob') + return this.#cachedBody('blob') } /** @@ -302,7 +302,7 @@ export class HonoRequest

{ * @see https://hono.dev/docs/api/request#formdata */ formData(): Promise { - return this.cachedBody('formData') + return this.#cachedBody('formData') } /** From 24d4fb157bdbdce0d38717e9ef4d55446f54dcea Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Thu, 31 Oct 2024 17:08:47 +0900 Subject: [PATCH 2/5] use `#` for routers --- src/router/pattern-router/router.ts | 8 ++++---- src/router/reg-exp-router/router.ts | 8 ++++---- src/router/trie-router/node.ts | 16 +++++++++------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/router/pattern-router/router.ts b/src/router/pattern-router/router.ts index db90bee79..fb819b217 100644 --- a/src/router/pattern-router/router.ts +++ b/src/router/pattern-router/router.ts @@ -5,7 +5,7 @@ type Route = [RegExp, string, T] // [pattern, method, handler, path] export class PatternRouter implements Router { name: string = 'PatternRouter' - private routes: Route[] = [] + #routes: Route[] = [] add(method: string, path: string, handler: T) { const endsWithWildcard = path[path.length - 1] === '*' @@ -34,14 +34,14 @@ export class PatternRouter implements Router { } catch { throw new UnsupportedPathError() } - this.routes.push([re, method, handler]) + this.#routes.push([re, method, handler]) } match(method: string, path: string): Result { const handlers: [T, Params][] = [] - for (let i = 0, len = this.routes.length; i < len; i++) { - const [pattern, routeMethod, handler] = this.routes[i] + for (let i = 0, len = this.#routes.length; i < len; i++) { + const [pattern, routeMethod, handler] = this.#routes[i] if (routeMethod === method || routeMethod === METHOD_NAME_ALL) { const match = pattern.exec(path) diff --git a/src/router/reg-exp-router/router.ts b/src/router/reg-exp-router/router.ts index 95f840e74..c33588857 100644 --- a/src/router/reg-exp-router/router.ts +++ b/src/router/reg-exp-router/router.ts @@ -207,7 +207,7 @@ export class RegExpRouter implements Router { match(method: string, path: string): Result { clearWildcardRegExpCache() // no longer used. - const matchers = this.buildAllMatchers() + const matchers = this.#buildAllMatchers() this.match = (method, path) => { const matcher = (matchers[method] || matchers[METHOD_NAME_ALL]) as Matcher @@ -229,13 +229,13 @@ export class RegExpRouter implements Router { return this.match(method, path) } - private buildAllMatchers(): Record | null> { + #buildAllMatchers(): Record | null> { const matchers: Record | null> = Object.create(null) Object.keys(this.routes!) .concat(Object.keys(this.middleware!)) .forEach((method) => { - matchers[method] ||= this.buildMatcher(method) + matchers[method] ||= this.#buildMatcher(method) }) // Release cache @@ -244,7 +244,7 @@ export class RegExpRouter implements Router { return matchers } - private buildMatcher(method: string): Matcher | null { + #buildMatcher(method: string): Matcher | null { const routes: [string, HandlerWithMetadata[]][] = [] let hasOwnRoute = method === METHOD_NAME_ALL diff --git a/src/router/trie-router/node.ts b/src/router/trie-router/node.ts index 61e6ba45f..3130433bc 100644 --- a/src/router/trie-router/node.ts +++ b/src/router/trie-router/node.ts @@ -82,7 +82,7 @@ export class Node { } // getHandlerSets - private gHSets( + #gHSets( node: Node, method: string, nodeParams: Record, @@ -133,10 +133,10 @@ export class Node { // '/hello/*' => match '/hello' if (nextNode.children['*']) { handlerSets.push( - ...this.gHSets(nextNode.children['*'], method, node.params, Object.create(null)) + ...this.#gHSets(nextNode.children['*'], method, node.params, Object.create(null)) ) } - handlerSets.push(...this.gHSets(nextNode, method, node.params, Object.create(null))) + handlerSets.push(...this.#gHSets(nextNode, method, node.params, Object.create(null))) } else { tempNodes.push(nextNode) } @@ -152,7 +152,7 @@ export class Node { if (pattern === '*') { const astNode = node.children['*'] if (astNode) { - handlerSets.push(...this.gHSets(astNode, method, node.params, Object.create(null))) + handlerSets.push(...this.#gHSets(astNode, method, node.params, Object.create(null))) tempNodes.push(astNode) } continue @@ -170,7 +170,7 @@ export class Node { const restPathString = parts.slice(i).join('/') if (matcher instanceof RegExp && matcher.test(restPathString)) { params[name] = restPathString - handlerSets.push(...this.gHSets(child, method, node.params, params)) + handlerSets.push(...this.#gHSets(child, method, node.params, params)) continue } @@ -178,9 +178,11 @@ export class Node { if (typeof key === 'string') { params[name] = part if (isLast) { - handlerSets.push(...this.gHSets(child, method, params, node.params)) + handlerSets.push(...this.#gHSets(child, method, params, node.params)) if (child.children['*']) { - handlerSets.push(...this.gHSets(child.children['*'], method, params, node.params)) + handlerSets.push( + ...this.#gHSets(child.children['*'], method, params, node.params) + ) } } else { child.params = params From 7f05f7d66535728abb6a1aaf07ab0c95f17933fa Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Fri, 1 Nov 2024 17:37:59 +0900 Subject: [PATCH 3/5] defined `#newResponse` with a method style --- src/context.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/context.ts b/src/context.ts index b7e876572..a591db72a 100644 --- a/src/context.ts +++ b/src/context.ts @@ -690,7 +690,10 @@ export class Context< }) } - #newResponse = this.newResponse + #newResponse(...args: unknown[]) { + // @ts-expect-error Type mismatch for args in newResponse call + return this.newResponse(...args) + } /** * `.body()` can return the HTTP response. From 3ac8d6216642303f6d62fc30221f8cdcbbdbc895 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Sat, 2 Nov 2024 11:04:20 +0900 Subject: [PATCH 4/5] Swap c.#newResponse and c.newResponse --- src/context.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/context.ts b/src/context.ts index 7a53f86ff..3bb9ceda1 100644 --- a/src/context.ts +++ b/src/context.ts @@ -623,7 +623,7 @@ export class Context< return Object.fromEntries(this.#var) } - newResponse: NewResponse = ( + #newResponse: NewResponse = ( data: Data | null, arg?: StatusCode | ResponseInit, headers?: HeaderRecord @@ -689,10 +689,7 @@ export class Context< }) } - #newResponse(...args: unknown[]) { - // @ts-expect-error Type mismatch for args in newResponse call - return this.newResponse(...args) - } + newResponse: NewResponse = (...args) => this.#newResponse(...(args as Parameters)) /** * `.body()` can return the HTTP response. From 96006d733a3bfe27f5215f7304a85da5859ec0d9 Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Sun, 3 Nov 2024 07:44:39 +0900 Subject: [PATCH 5/5] make `#newResponse` as `#method() {}` style --- src/context.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context.ts b/src/context.ts index 3bb9ceda1..86124e008 100644 --- a/src/context.ts +++ b/src/context.ts @@ -623,11 +623,11 @@ export class Context< return Object.fromEntries(this.#var) } - #newResponse: NewResponse = ( + #newResponse( data: Data | null, arg?: StatusCode | ResponseInit, headers?: HeaderRecord - ): Response => { + ): Response { // Optimized if (this.#isFresh && !headers && !arg && this.#status === 200) { return new Response(data, {