Skip to content

Commit

Permalink
fix: set gzip level to 6 for preview server (#3101)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenjiahan authored Aug 1, 2024
1 parent fa52cbe commit 5473291
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 78 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/server/getDevMiddlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const applyDefaultMiddlewares = async ({
// compression should be the first middleware
if (server.compress) {
const { gzipMiddleware } = await import('./gzipMiddleware');
middlewares.push(gzipMiddleware);
middlewares.push(gzipMiddleware());
}

middlewares.push((req, res, next) => {
Expand Down
160 changes: 84 additions & 76 deletions packages/core/src/server/gzipMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,95 +20,103 @@ const shouldCompress = (res: ServerResponse) => {
return size === undefined || Number(size) > 1024;
};

export const gzipMiddleware: RequestHandler = (req, res, next): void => {
const accept = req.headers['accept-encoding'];
const encoding = typeof accept === 'string' && ENCODING_REGEX.test(accept);

if (req.method === 'HEAD' || !encoding) {
next();
return;
}

let gzip: zlib.Gzip | undefined;
let writeHeadStatus: number | undefined;
let started = false;

const { end, write, on, writeHead } = res;
const listeners: Array<[string | symbol, (...args: any[]) => void]> = [];

const start = () => {
if (started) {
export const gzipMiddleware =
({
level = zlib.constants.Z_BEST_SPEED,
}: {
level?: number;
} = {}): RequestHandler =>
(req, res, next): void => {
const accept = req.headers['accept-encoding'];
const encoding = typeof accept === 'string' && ENCODING_REGEX.test(accept);

if (req.method === 'HEAD' || !encoding) {
next();
return;
}
started = true;

if (shouldCompress(res)) {
res.setHeader('Content-Encoding', 'gzip');
res.removeHeader('Content-Length');
let gzip: zlib.Gzip | undefined;
let writeHeadStatus: number | undefined;
let started = false;

gzip = zlib.createGzip({ level: zlib.constants.Z_BEST_SPEED });
const { end, write, on, writeHead } = res;
const listeners: Array<[string | symbol, (...args: any[]) => void]> = [];

gzip.on('data', (chunk) => {
if ((write as (chunk: unknown) => boolean).call(res, chunk) === false) {
gzip!.pause();
}
});
const start = () => {
if (started) {
return;
}
started = true;

on.call(res, 'drain', () => gzip!.resume());
if (shouldCompress(res)) {
res.setHeader('Content-Encoding', 'gzip');
res.removeHeader('Content-Length');

gzip.on('end', () => {
(end as () => void).call(res);
});
gzip = zlib.createGzip({ level });

for (const listener of listeners) {
gzip.on.apply(gzip, listener);
}
} else {
for (const listener of listeners) {
on.apply(res, listener);
}
}
gzip.on('data', (chunk) => {
if (
(write as (chunk: unknown) => boolean).call(res, chunk) === false
) {
gzip!.pause();
}
});

writeHead.call(res, writeHeadStatus ?? res.statusCode);
};
on.call(res, 'drain', () => gzip!.resume());

res.writeHead = (status, reason, headers?) => {
if (reason) {
for (const [key, value] of Object.entries(headers || reason)) {
res.setHeader(key, value);
}
}
writeHeadStatus = status;
return res;
};
gzip.on('end', () => {
(end as () => void).call(res);
});

res.write = (...args: unknown[]) => {
start();
return gzip
? gzip.write(...(args as Parameters<typeof write>))
: write.apply(res, args as Parameters<typeof write>);
};
for (const listener of listeners) {
gzip.on.apply(gzip, listener);
}
} else {
for (const listener of listeners) {
on.apply(res, listener);
}
}

res.end = (...args: any[]) => {
start();
return gzip
? (gzip.end as unknown as typeof end)(...args)
: end.apply(res, args as Parameters<typeof end>);
};
writeHead.call(res, writeHeadStatus ?? res.statusCode);
};

res.on = (type, listener) => {
if (started) {
if (!gzip || type !== 'drain') {
on.call(res, type, listener);
res.writeHead = (status, reason, headers?) => {
if (reason) {
for (const [key, value] of Object.entries(headers || reason)) {
res.setHeader(key, value);
}
}
writeHeadStatus = status;
return res;
};

res.write = (...args: unknown[]) => {
start();
return gzip
? gzip.write(...(args as Parameters<typeof write>))
: write.apply(res, args as Parameters<typeof write>);
};

res.end = (...args: any[]) => {
start();
return gzip
? (gzip.end as unknown as typeof end)(...args)
: end.apply(res, args as Parameters<typeof end>);
};

res.on = (type, listener) => {
if (started) {
if (!gzip || type !== 'drain') {
on.call(res, type, listener);
} else {
gzip.on(type, listener);
}
} else {
gzip.on(type, listener);
// store listeners until start
listeners.push([type, listener]);
}
} else {
// store listeners until start
listeners.push([type, listener]);
}
return res;
};
return res;
};

next();
};
next();
};
7 changes: 6 additions & 1 deletion packages/core/src/server/prodServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ export class RsbuildProdServer {
// compression should be the first middleware
if (compress) {
const { gzipMiddleware } = await import('./gzipMiddleware');
this.middlewares.use(gzipMiddleware);
this.middlewares.use(
gzipMiddleware({
// simulates the common gzip compression rates
level: 6,
}),
);
}

if (headers) {
Expand Down

0 comments on commit 5473291

Please sign in to comment.