0
0
mirror of https://github.com/honojs/hono.git synced 2024-11-21 10:08:58 +01:00

refactor: use # for private methods to reduce the minified file size (#3596)

* refactor: use `#` for private methods to reduce the bundle size

* use `#` for routers

* defined `#newResponse` with a method style

* Swap c.#newResponse and c.newResponse

* make `#newResponse` as `#method() {}` style
This commit is contained in:
Yusuke Wada 2024-11-03 08:31:59 +09:00 committed by GitHub
parent e43f203a2a
commit ae6165b994
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 71 additions and 67 deletions

View File

@ -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, {
@ -689,6 +689,8 @@ export class Context<
})
}
newResponse: NewResponse = (...args) => this.#newResponse(...(args as Parameters<NewResponse>))
/**
* `.body()` can return the HTTP response.
* You can set headers with `.header()` and set HTTP status code with `.status`.
@ -716,8 +718,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)
}
/**
@ -749,8 +751,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)
}
/**
@ -778,7 +780,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
}
@ -793,14 +795,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)
}
/**

View File

@ -130,11 +130,11 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
if (typeof args1 === 'string') {
this.#path = args1
} else {
this.addRoute(method, this.#path, args1)
this.#addRoute(method, this.#path, args1)
}
args.forEach((handler) => {
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<E extends Env = Env, S extends Schema = {}, BasePath extends string =
this.#path = p
for (const m of [method].flat()) {
handlers.map((handler) => {
this.addRoute(m.toUpperCase(), this.#path, handler)
this.#addRoute(m.toUpperCase(), this.#path, handler)
})
}
}
@ -163,7 +163,7 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
handlers.unshift(arg1)
}
handlers.forEach((handler) => {
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<E extends Env = Env, S extends Schema = {}, BasePath extends string =
this.getPath = strict ? options.getPath ?? getPath : getPathNoStrict
}
private clone(): Hono<E, S, BasePath> {
#clone(): Hono<E, S, BasePath> {
const clone = new Hono<E, S, BasePath>({
router: this.router,
getPath: this.getPath,
@ -183,8 +183,8 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
return clone
}
private notFoundHandler: NotFoundHandler = notFoundHandler
private errorHandler: ErrorHandler = errorHandler
#notFoundHandler: NotFoundHandler = notFoundHandler
#errorHandler: ErrorHandler = errorHandler
/**
* `.route()` allows grouping other Hono instance in routes.
@ -216,15 +216,15 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
const subApp = this.basePath(path)
app.routes.map((r) => {
let handler
if (app.errorHandler === errorHandler) {
if (app.#errorHandler === errorHandler) {
handler = r.handler
} else {
handler = async (c: Context, next: Next) =>
(await compose<Context>([], app.errorHandler)(c, () => r.handler(c, next))).res
(await compose<Context>([], 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<E extends Env = Env, S extends Schema = {}, BasePath extends string =
* ```
*/
basePath<SubPath extends string>(path: SubPath): Hono<E, S, MergePath<BasePath, SubPath>> {
const subApp = this.clone()
const subApp = this.#clone()
subApp._basePath = mergePath(this._basePath, path)
return subApp
}
@ -265,7 +265,7 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
* ```
*/
onError = (handler: ErrorHandler<E>): Hono<E, S, BasePath> => {
this.errorHandler = handler
this.#errorHandler = handler
return this
}
@ -285,7 +285,7 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
* ```
*/
notFound = (handler: NotFoundHandler<E>): Hono<E, S, BasePath> => {
this.notFoundHandler = handler
this.#notFoundHandler = handler
return this
}
@ -370,11 +370,11 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
await next()
}
this.addRoute(METHOD_NAME_ALL, mergePath(path, '*'), handler)
this.#addRoute(METHOD_NAME_ALL, mergePath(path, '*'), handler)
return this
}
private addRoute(method: string, path: string, handler: H) {
#addRoute(method: string, path: string, handler: H) {
method = method.toUpperCase()
path = mergePath(this._basePath, path)
const r: RouterRoute = { path: path, method: method, handler: handler }
@ -382,14 +382,14 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
this.routes.push(r)
}
private handleError(err: unknown, c: Context<E>) {
#handleError(err: unknown, c: Context<E>) {
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<E extends Env = Env, S extends Schema = {}, BasePath extends string =
// Handle HEAD method
if (method === 'HEAD') {
return (async () =>
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<E extends Env = Env, S extends Schema = {}, BasePath extends string =
matchResult,
env,
executionCtx,
notFoundHandler: this.notFoundHandler,
notFoundHandler: this.#notFoundHandler,
})
// Do not `compose` if it has only one handler
@ -417,23 +417,23 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
let res: ReturnType<H>
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<Context>(matchResult[0], this.errorHandler, this.notFoundHandler)
const composed = compose<Context>(matchResult[0], this.#errorHandler, this.#notFoundHandler)
return (async () => {
try {
@ -446,7 +446,7 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
return context.res
} catch (err) {
return this.handleError(err, c)
return this.#handleError(err, c)
}
})()
}
@ -467,7 +467,7 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
Env?: E['Bindings'] | {},
executionCtx?: ExecutionContext
) => Response | Promise<Response> = (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<E extends Env = Env, S extends Schema = {}, BasePath extends string =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
addEventListener('fetch', (event: FetchEventLike): void => {
event.respondWith(this.dispatch(event.request, event, undefined, event.request.method))
event.respondWith(this.#dispatch(event.request, event, undefined, event.request.method))
})
}
}

View File

@ -91,21 +91,21 @@ export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
param(key: string): string | undefined
param<P2 extends string = P>(): Simplify<UnionToIntersection<ParamKeyToRecord<ParamKeys<P2>>>>
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<string, string> {
#getAllDecodedParams(): Record<string, string> {
const decoded: Record<string, string> = {}
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<P extends string = '/', I extends Input['out'] = {}> {
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<P extends string = '/', I extends Input['out'] = {}> {
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<P extends string = '/', I extends Input['out'] = {}> {
* ```
*/
json<T = any>(): Promise<T> {
return this.cachedBody('json')
return this.#cachedBody('json')
}
/**
@ -258,7 +258,7 @@ export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
* ```
*/
text(): Promise<string> {
return this.cachedBody('text')
return this.#cachedBody('text')
}
/**
@ -274,7 +274,7 @@ export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
* ```
*/
arrayBuffer(): Promise<ArrayBuffer> {
return this.cachedBody('arrayBuffer')
return this.#cachedBody('arrayBuffer')
}
/**
@ -288,7 +288,7 @@ export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
* @see https://hono.dev/docs/api/request#blob
*/
blob(): Promise<Blob> {
return this.cachedBody('blob')
return this.#cachedBody('blob')
}
/**
@ -302,7 +302,7 @@ export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
* @see https://hono.dev/docs/api/request#formdata
*/
formData(): Promise<FormData> {
return this.cachedBody('formData')
return this.#cachedBody('formData')
}
/**

View File

@ -5,7 +5,7 @@ type Route<T> = [RegExp, string, T] // [pattern, method, handler, path]
export class PatternRouter<T> implements Router<T> {
name: string = 'PatternRouter'
private routes: Route<T>[] = []
#routes: Route<T>[] = []
add(method: string, path: string, handler: T) {
const endsWithWildcard = path[path.length - 1] === '*'
@ -34,14 +34,14 @@ export class PatternRouter<T> implements Router<T> {
} catch {
throw new UnsupportedPathError()
}
this.routes.push([re, method, handler])
this.#routes.push([re, method, handler])
}
match(method: string, path: string): Result<T> {
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)

View File

@ -207,7 +207,7 @@ export class RegExpRouter<T> implements Router<T> {
match(method: string, path: string): Result<T> {
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<T>
@ -229,13 +229,13 @@ export class RegExpRouter<T> implements Router<T> {
return this.match(method, path)
}
private buildAllMatchers(): Record<string, Matcher<T> | null> {
#buildAllMatchers(): Record<string, Matcher<T> | null> {
const matchers: Record<string, Matcher<T> | 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<T> implements Router<T> {
return matchers
}
private buildMatcher(method: string): Matcher<T> | null {
#buildMatcher(method: string): Matcher<T> | null {
const routes: [string, HandlerWithMetadata<T>[]][] = []
let hasOwnRoute = method === METHOD_NAME_ALL

View File

@ -82,7 +82,7 @@ export class Node<T> {
}
// getHandlerSets
private gHSets(
#gHSets(
node: Node<T>,
method: string,
nodeParams: Record<string, string>,
@ -133,10 +133,10 @@ export class Node<T> {
// '/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<T> {
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<T> {
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<T> {
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