Skip to content

Commit 9fa7fd0

Browse files
committed
feat: support compression
1 parent 4090147 commit 9fa7fd0

File tree

5 files changed

+38
-3
lines changed

5 files changed

+38
-3
lines changed

fixtures/css.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
html {
22
background-color: #000;
3+
color: #fff;
34
}

fixtures/html.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
<link rel="stylesheet" href="css.css" />
88
</head>
99
<body>
10-
html
10+
html - 中文
1111
</body>
1212
</html>

src/cli.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ const cliOptions = [
3434
defaultValue: false,
3535
usage: `htttp-server -dc`,
3636
},
37+
{
38+
option: '--compress',
39+
description: 'Enable compress',
40+
defaultValue: false,
41+
usage: `htttp-server --compress`,
42+
},
3743
];
3844

3945
cliOptions.forEach(({ option, description, defaultValue }) => program.option(option, description, defaultValue.toString()));
@@ -52,5 +58,6 @@ const server = new Server({
5258
dataPosition: opts.data,
5359
cors: JSON.parse(opts.cors),
5460
cache: !JSON.parse(opts.disableCache),
61+
compress: JSON.parse(opts.compress),
5562
});
5663
server.start();

src/index.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import * as fs from 'node:fs/promises';
44
import { createReadStream, readFileSync, statSync } from 'node:fs';
55
import * as path from 'node:path';
66
import { Buffer } from 'node:buffer';
7+
import { createBrotliCompress, createDeflate, createGzip } from 'node:zlib';
8+
import type { Gzip } from 'node:zlib';
79
import chalk from 'chalk';
810
import * as ejs from 'ejs';
911
import mine from 'mime';
@@ -17,6 +19,7 @@ export default class Server {
1719
data: { [k: string]: ResourceItem[] } = {};
1820
cors: boolean = false;
1921
cache: boolean = true;
22+
compress: boolean = false;
2023

2124
constructor(options?: ServerOptions) {
2225
if (options?.port) {
@@ -40,6 +43,9 @@ export default class Server {
4043
if (!options?.cache) {
4144
this.cache = false;
4245
}
46+
if (options?.compress) {
47+
this.compress = true;
48+
}
4349
}
4450

4551
start() {
@@ -57,7 +63,7 @@ export default class Server {
5763
if (stat.isDirectory()) {
5864
this.processDirectory(wholePath, res, requestUrl);
5965
} else {
60-
this.processFile(wholePath, res);
66+
this.processFile(wholePath, res, req);
6167
}
6268
}
6369
} catch {
@@ -92,11 +98,20 @@ export default class Server {
9298
res.end(html);
9399
}
94100

95-
private async processFile(file: string, res: Res) {
101+
private async processFile(file: string, res: Res, req: Req) {
96102
if (this.cache) {
97103
this.processCache(res, file); // The homepage will not be cached.
98104
}
99105
res.setHeader('Content-Type', `${mine.getType(file) ?? 'text/plain'};charset=utf-8`);
106+
if (this.compress) {
107+
const compressedStreamResponse = this.processCompress(req);
108+
if (compressedStreamResponse) {
109+
const [compressedStream, encoding] = compressedStreamResponse;
110+
res.setHeader('Content-Encoding', encoding);
111+
createReadStream(file).pipe(compressedStream).pipe(res);
112+
return;
113+
}
114+
}
100115
createReadStream(file).pipe(res);
101116
}
102117

@@ -244,4 +259,15 @@ export default class Server {
244259
return res.end();
245260
}
246261
}
262+
263+
private processCompress(req: Req): [Gzip, string] | undefined {
264+
const acceptEncoding = req.headers['accept-encoding'];
265+
if (acceptEncoding?.includes('gzip')) {
266+
return [createGzip(), 'gzip'];
267+
} else if (acceptEncoding?.includes('deflate')) {
268+
return [createDeflate(), 'deflate'];
269+
} else if (acceptEncoding?.includes('br')) {
270+
return [createBrotliCompress(), 'br'];
271+
}
272+
}
247273
}

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface ServerOptions {
66
dataPosition?: string;
77
cors?: boolean;
88
cache?: boolean;
9+
compress?: boolean;
910
}
1011

1112
export type Res = http.ServerResponse<http.IncomingMessage> & {

0 commit comments

Comments
 (0)