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

WIP refactor: make constructors as functions to reduce bundle size #3666

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
refactor: make constructors as functions to reduce bundle size
yusukebe committed Nov 15, 2024
commit 40ac8ce5418e9e24d66f5ef199be6f3429e08010
24 changes: 13 additions & 11 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import type {
RouterRoute,
TypedResponse,
} from './types'
import { newHeaders, newResponse } from './utils/constructors'
import type { ResponseHeader } from './utils/headers'
import { HtmlEscapedCallbackPhase, resolveCallback } from './utils/html'
import type { RedirectStatusCode, StatusCode } from './utils/http-status'
@@ -386,7 +387,7 @@ export class Context<
*/
get res(): Response {
this.#isFresh = false
return (this.#res ||= new Response('404 Not Found', { status: 404 }))
return (this.#res ||= newResponse('404 Not Found', { status: 404 }))
}

/**
@@ -415,7 +416,7 @@ export class Context<
} catch (e) {
if (e instanceof TypeError && e.message.includes('immutable')) {
// `_res` is immutable (probably a response from a fetch API), so retry with a new response.
this.res = new Response(_res.body, {
this.res = newResponse(_res.body, {
headers: _res.headers,
status: _res.status,
})
@@ -525,7 +526,7 @@ export class Context<
if (options?.append) {
if (!this.#headers) {
this.#isFresh = false
this.#headers = new Headers(this.#preparedHeaders)
this.#headers = newHeaders(this.#preparedHeaders)
this.#preparedHeaders = {}
}
this.#headers.append(name, value)
@@ -630,13 +631,13 @@ export class Context<
): Response {
// Optimized
if (this.#isFresh && !headers && !arg && this.#status === 200) {
return new Response(data, {
return newResponse(data, {
headers: this.#preparedHeaders,
})
}

if (arg && typeof arg !== 'number') {
const header = new Headers(arg.headers)
const header = newHeaders(arg.headers)
if (this.#headers) {
// If the header is set by c.header() and arg.headers, c.header() will be prioritized.
this.#headers.forEach((v, k) => {
@@ -648,7 +649,7 @@ export class Context<
})
}
const headers = setHeaders(header, this.#preparedHeaders)
return new Response(data, {
return newResponse(data, {
headers,
status: arg.status ?? this.#status,
})
@@ -657,7 +658,7 @@ export class Context<
const status = typeof arg === 'number' ? arg : this.#status
this.#preparedHeaders ??= {}

this.#headers ??= new Headers()
this.#headers ??= newHeaders()
setHeaders(this.#headers, this.#preparedHeaders)

if (this.#res) {
@@ -683,7 +684,7 @@ export class Context<
}
}

return new Response(data, {
return newResponse(data, {
status,
headers: this.#headers,
})
@@ -744,11 +745,12 @@ export class Context<
if (!this.#preparedHeaders) {
if (this.#isFresh && !headers && !arg) {
// @ts-expect-error `Response` due to missing some types-only keys
return new Response(text)
return newResponse(text)
}
this.#preparedHeaders = {}
}
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)
@@ -824,7 +826,7 @@ export class Context<
location: string | URL,
status?: T
): Response & TypedResponse<undefined, T, 'redirect'> => {
this.#headers ??= new Headers()
this.#headers ??= newHeaders()
this.#headers.set('Location', String(location))
return this.newResponse(null, status ?? 302) as any
}
@@ -842,7 +844,7 @@ export class Context<
* ```
*/
notFound = (): Response | Promise<Response> => {
this.#notFoundHandler ??= () => new Response()
this.#notFoundHandler ??= () => newResponse()
return this.#notFoundHandler(this)
}
}
9 changes: 5 additions & 4 deletions src/hono-base.ts
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ import type {
RouterRoute,
Schema,
} from './types'
import { newResponse, newRequest } from './utils/constructors'
import { getPath, getPathNoStrict, mergePath } from './utils/url'

/**
@@ -355,7 +356,7 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
return (request) => {
const url = new URL(request.url)
url.pathname = url.pathname.slice(pathPrefixLength) || '/'
return new Request(url, request)
return newRequest(url, request)
}
})()

@@ -396,7 +397,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')))()
newResponse(null, await this.#dispatch(request, executionCtx, env, 'GET')))()
}

const path = this.getPath(request, { env })
@@ -487,11 +488,11 @@ class Hono<E extends Env = Env, S extends Schema = {}, BasePath extends string =
executionCtx?: ExecutionContext
): Response | Promise<Response> => {
if (input instanceof Request) {
return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx)
return this.fetch(requestInit ? newRequest(input, requestInit) : input, Env, executionCtx)
}
input = input.toString()
return this.fetch(
new Request(
newRequest(
/^https?:\/\//.test(input) ? input : `http://localhost${mergePath('/', input)}`,
requestInit
),
3 changes: 2 additions & 1 deletion src/request.ts
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ import type {
} from './types'
import { parseBody } from './utils/body'
import type { BodyData, ParseBodyOptions } from './utils/body'
import { newResponse } from './utils/constructors'
import type { CustomHeader, RequestHeader } from './utils/headers'
import type { Simplify, UnionToIntersection } from './utils/types'
import { decodeURIComponent_, getQueryParam, getQueryParams, tryDecode } from './utils/url'
@@ -222,7 +223,7 @@ export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
if (anyCachedKey === 'json') {
body = JSON.stringify(body)
}
return new Response(body)[key]()
return newResponse(body)[key]()
})
}

11 changes: 11 additions & 0 deletions src/utils/constructors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const newRequest = (input: RequestInfo | URL, init?: RequestInit): Request => {
return new Request(input, init)
}

export const newResponse = (body?: BodyInit | null, init?: ResponseInit): Response => {
return new Response(body, init)
}

export const newHeaders = (init?: HeadersInit): Headers => {
return new Headers(init)
}

Unchanged files with check annotations Beta

protected getCookies(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
event: Exclude<LambdaEvent, APIGatewayProxyEventV2>,

Check failure on line 336 in src/adapter/aws-lambda/handler.ts

GitHub Actions / Main

'event' is declared but its value is never read.

Check failure on line 336 in src/adapter/aws-lambda/handler.ts

GitHub Actions / Node.js v18.18.2

'event' is declared but its value is never read.

Check failure on line 336 in src/adapter/aws-lambda/handler.ts

GitHub Actions / Node.js v20.x

'event' is declared but its value is never read.

Check failure on line 336 in src/adapter/aws-lambda/handler.ts

GitHub Actions / Node.js v22.x

'event' is declared but its value is never read.

Check failure on line 336 in src/adapter/aws-lambda/handler.ts

GitHub Actions / workerd

'event' is declared but its value is never read.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
headers: Headers

Check failure on line 338 in src/adapter/aws-lambda/handler.ts

GitHub Actions / Main

'headers' is declared but its value is never read.

Check failure on line 338 in src/adapter/aws-lambda/handler.ts

GitHub Actions / Node.js v18.18.2

'headers' is declared but its value is never read.

Check failure on line 338 in src/adapter/aws-lambda/handler.ts

GitHub Actions / Node.js v20.x

'headers' is declared but its value is never read.

Check failure on line 338 in src/adapter/aws-lambda/handler.ts

GitHub Actions / Node.js v22.x

'headers' is declared but its value is never read.

Check failure on line 338 in src/adapter/aws-lambda/handler.ts

GitHub Actions / workerd

'headers' is declared but its value is never read.
): void {
// nop
}
}
type ReactNode = ReactElement | string | number | boolean | null | undefined
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type ComponentClass<P = {}, S = {}> = unknown

Check failure on line 26 in src/jsx/types.ts

GitHub Actions / Main

All type parameters are unused.

Check failure on line 26 in src/jsx/types.ts

GitHub Actions / Node.js v18.18.2

All type parameters are unused.

Check failure on line 26 in src/jsx/types.ts

GitHub Actions / Node.js v20.x

All type parameters are unused.

Check failure on line 26 in src/jsx/types.ts

GitHub Actions / Node.js v22.x

All type parameters are unused.

Check failure on line 26 in src/jsx/types.ts

GitHub Actions / workerd

All type parameters are unused.
export type { ReactElement, ReactNode, ComponentClass }