Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit 201f14d

Browse files
author
Je
committed
feat: add gzip encoding for server
1 parent 496ba40 commit 201f14d

File tree

3 files changed

+52
-39
lines changed

3 files changed

+52
-39
lines changed

api.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { gzipEncode } from 'https://deno.land/x/[email protected]/mod.ts'
12
import log from './log.ts'
23
import type { ServerRequest } from './std.ts'
34
import type { APIRequest, APIRequestURL, APIResponse, RouterURL } from './types.ts'
@@ -58,11 +59,16 @@ export class AlephAPIResponse implements APIResponse {
5859

5960
constructor(req: ServerRequest) {
6061
this.#req = req
61-
this.#headers = new Headers()
62+
this.#headers = new Headers({
63+
'Status': '200',
64+
'Server': 'Aleph.js',
65+
'Date': (new Date).toUTCString(),
66+
})
6267
this.#status = 200
6368
}
6469

6570
status(code: number): this {
71+
this.#headers.set('status', code.toString())
6672
this.#status = code
6773
return this
6874
}
@@ -82,12 +88,31 @@ export class AlephAPIResponse implements APIResponse {
8288
return this
8389
}
8490

85-
async send(data: string | Uint8Array | ArrayBuffer) {
86-
let body: string | Uint8Array
87-
if (data instanceof ArrayBuffer) {
91+
async end(status: number) {
92+
return this.#req.respond({
93+
status,
94+
headers: this.#headers,
95+
}).catch(err => log.warn('ServerRequest.respond:', err.message))
96+
}
97+
98+
async send(data: string | Uint8Array | ArrayBuffer, contentType?: string, gzip = false) {
99+
let body: Uint8Array
100+
if (typeof data === 'string') {
101+
body = new TextEncoder().encode(data)
102+
} else if (data instanceof ArrayBuffer) {
88103
body = new Uint8Array(data)
89-
} else {
104+
} else if (data instanceof Uint8Array) {
90105
body = data
106+
} else {
107+
return
108+
}
109+
if (contentType) {
110+
this.#headers.set('Content-Type', contentType)
111+
}
112+
if (gzip && this.#req.headers.get('accept-encoding')?.includes('gzip') && body.length > 1024) {
113+
this.#headers.set('Vary', 'Origin')
114+
this.#headers.set('Content-Encoding', 'gzip')
115+
body = gzipEncode(body)
91116
}
92117
return this.#req.respond({
93118
status: this.#status,

publish.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ const versions = [
1010
]
1111

1212
async function ask(question: string = ':', stdin = Deno.stdin, stdout = Deno.stdout) {
13-
const buf = new Uint8Array(1024)
1413
await stdout.write(new TextEncoder().encode(question + ' '))
14+
const buf = new Uint8Array(1024)
1515
const n = <number>await stdin.read(buf)
1616
const answer = new TextDecoder().decode(buf.subarray(0, n))
1717
return answer.trim()

server.ts

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { AlephAPIResponse } from './api.ts'
12
import { createHtml } from './html.ts'
23
import log from './log.ts'
34
import { getContentType } from './mime.ts'
@@ -16,6 +17,7 @@ export async function start(appDir: string, port: number, isDev = false, reload
1617
for await (const req of s) {
1718
const url = new URL('http://localhost/' + req.url)
1819
const pathname = util.cleanPath(url.pathname)
20+
const resp = new AlephAPIResponse(req)
1921

2022
try {
2123
// serve hmr ws
@@ -72,11 +74,7 @@ export async function start(appDir: string, port: number, isDev = false, reload
7274
const filePath = path.join(project.buildDir, util.trimPrefix(pathname, '/_aleph/'))
7375
if (existsFileSync(filePath)) {
7476
const body = await Deno.readFile(filePath)
75-
req.respond({
76-
status: 200,
77-
headers: new Headers({ 'Content-Type': 'text/css; charset=utf-8' }),
78-
body
79-
}).catch(err => log.warn('ServerRequest.respond:', err.message))
77+
resp.send(body, 'text/css; charset=utf-8', true)
8078
continue
8179
}
8280
} else {
@@ -85,7 +83,7 @@ export async function start(appDir: string, port: number, isDev = false, reload
8583
if (mod) {
8684
const etag = req.headers.get('If-None-Match')
8785
if (etag && etag === mod.hash) {
88-
req.respond({ status: 304 })
86+
resp.end(304)
8987
continue
9088
}
9189

@@ -111,14 +109,8 @@ export async function start(appDir: string, port: number, isDev = false, reload
111109
body = injectHmr({ ...mod, jsContent: body })
112110
}
113111
}
114-
req.respond({
115-
status: 200,
116-
headers: new Headers({
117-
'Content-Type': `application/${reqSourceMap ? 'json' : 'javascript'}; charset=utf-8`,
118-
'ETag': mod.hash
119-
}),
120-
body
121-
}).catch(err => log.warn('ServerRequest.respond:', err.message))
112+
resp.setHeader('ETag', mod.hash)
113+
resp.send(body, `application/${reqSourceMap ? 'json' : 'javascript'}; charset=utf-8`, true)
122114
continue
123115
}
124116
}
@@ -127,32 +119,28 @@ export async function start(appDir: string, port: number, isDev = false, reload
127119
// serve public files
128120
const filePath = path.join(project.appRoot, 'public', pathname)
129121
if (existsFileSync(filePath)) {
122+
const info = await Deno.lstat(filePath)
123+
if (info.mtime?.toUTCString() === req.headers.get('If-Modified-Since')) {
124+
resp.end(304)
125+
continue
126+
}
127+
130128
const body = await Deno.readFile(filePath)
131-
req.respond({
132-
status: 200,
133-
headers: new Headers({ 'Content-Type': getContentType(filePath) }),
134-
body
135-
}).catch(err => log.warn('ServerRequest.respond:', err.message))
129+
const ct = getContentType(filePath)
130+
resp.setHeader('Last-Modified', info.mtime!.toUTCString())
131+
resp.send(body, ct, ct.startsWith('text/') || /\.(m?js|json|xml)$/i.test(filePath))
136132
continue
137133
}
138134

139135
// ssr
140136
const [status, html] = await project.getPageHtml({ pathname, search: url.search })
141-
req.respond({
142-
status,
143-
headers: new Headers({ 'Content-Type': 'text/html' }),
144-
body: html
145-
}).catch(err => log.warn('ServerRequest.respond:', err.message))
137+
resp.status(status).send(html, 'text/html', true)
146138
} catch (err) {
147-
req.respond({
148-
status: 500,
149-
headers: new Headers({ 'Content-Type': 'text/html' }),
150-
body: createHtml({
151-
lang: 'en',
152-
head: ['<title>500 - internal server error</title>'],
153-
body: `<p><strong><code>500</code></strong><small> - </small><span>${err.message}</span></p>`
154-
})
155-
}).catch(err => log.warn('ServerRequest.respond:', err.message))
139+
resp.status(500).send(createHtml({
140+
lang: 'en',
141+
head: ['<title>500 - internal server error</title>'],
142+
body: `<p><strong><code>500</code></strong><small> - </small><span>${err.message}</span></p>`
143+
}), 'text/html', true)
156144
}
157145
}
158146
} catch (err) {

0 commit comments

Comments
 (0)