diff --git a/.changeset/evil-pigs-doubt.md b/.changeset/evil-pigs-doubt.md new file mode 100644 index 0000000000..1b1b229bd8 --- /dev/null +++ b/.changeset/evil-pigs-doubt.md @@ -0,0 +1,5 @@ +--- +"@lynx-js/rspeedy": patch +--- + +Support `server.compress` diff --git a/packages/rspeedy/core/etc/rspeedy.api.md b/packages/rspeedy/core/etc/rspeedy.api.md index 75a74ad37e..a5db0d3a29 100644 --- a/packages/rspeedy/core/etc/rspeedy.api.md +++ b/packages/rspeedy/core/etc/rspeedy.api.md @@ -4,6 +4,7 @@ ```ts +import type { CompressOptions } from '@rsbuild/core'; import type { CreateRsbuildOptions } from '@rsbuild/core'; import type { DataUriLimit } from '@rsbuild/core'; import type { DistPathConfig } from '@rsbuild/core'; @@ -304,6 +305,7 @@ export type RspeedyInstance = RsbuildInstance & { // @public export interface Server { base?: string | undefined; + compress?: boolean | CompressOptions | undefined; headers?: Record | undefined; host?: string | undefined; port?: number | undefined; diff --git a/packages/rspeedy/core/src/config/rsbuild/index.ts b/packages/rspeedy/core/src/config/rsbuild/index.ts index 79361224c8..678d4e5a6d 100644 --- a/packages/rspeedy/core/src/config/rsbuild/index.ts +++ b/packages/rspeedy/core/src/config/rsbuild/index.ts @@ -88,6 +88,8 @@ export function toRsbuildConfig( server: { base: config.server?.base, + compress: config.server?.compress, + headers: config.server?.headers, host: config.server?.host, diff --git a/packages/rspeedy/core/src/config/server/index.ts b/packages/rspeedy/core/src/config/server/index.ts index f89f99cf4d..73be254084 100644 --- a/packages/rspeedy/core/src/config/server/index.ts +++ b/packages/rspeedy/core/src/config/server/index.ts @@ -2,7 +2,7 @@ // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. -import type { ProxyConfig } from '@rsbuild/core' +import type { CompressOptions, ProxyConfig } from '@rsbuild/core' /** * {@inheritdoc Config.server} @@ -32,6 +32,60 @@ export interface Server { */ base?: string | undefined + /** + * Configure whether to enable {@link https://developer.mozilla.org/en-US/docs/Glossary/gzip_compression | gzip compression } for static assets served by the dev server or preview server. + * + * Default: true + * + * See {@link https://rsbuild.rs/config/server/compress | Rsbuild - server.compress } for details. + * + * @example + * + * To disable the gzip compression, set compress to false: + * + * ```js + * export default { + * server: { + * compress: false, + * }, + * } + * ``` + * + * @example + * + * Compress if it starts with /foo + * + * ```js + * export default { + * server: { + * compress: { + * filter: (req) => { + * if (req.url?.includes('/foo')) { + * return false; + * } + * return true; + * }, + * }, + * }, + * } + * ``` + * + * @example + * + * set level of zlib compression + * + * ```js + * export default { + * server: { + * compress: { + * level: 6, + * }, + * }, + * } + * ``` + */ + compress?: boolean | CompressOptions | undefined + /** * Adds headers to all responses. * diff --git a/packages/rspeedy/core/test/config/rsbuild.test.ts b/packages/rspeedy/core/test/config/rsbuild.test.ts index 5bd57e8556..279a835931 100644 --- a/packages/rspeedy/core/test/config/rsbuild.test.ts +++ b/packages/rspeedy/core/test/config/rsbuild.test.ts @@ -1,6 +1,8 @@ // Copyright 2024 The Lynx Authors. All rights reserved. // Licensed under the Apache License Version 2.0 that can be found in the // LICENSE file in the root directory of this source tree. +import type { IncomingMessage } from 'node:http' + import type { RsbuildPlugin } from '@rsbuild/core' import { describe, expect, test } from 'vitest' @@ -618,6 +620,64 @@ describe('Config - toRsBuildConfig', () => { }) }) + describe('Server', () => { + test('transform server.compress: undefined (no server)', () => { + const rsbuildConfig = toRsbuildConfig({}) + expect(rsbuildConfig.server?.compress).toBeUndefined() + }) + + test('transform server.compress: undefined (empty server)', () => { + const rsbuildConfig = toRsbuildConfig({ server: {} }) + expect(rsbuildConfig.server?.compress).toBeUndefined() + }) + + test('transform server.compress: false', () => { + const rsbuildConfig = toRsbuildConfig({ + server: { compress: false }, + }) + expect(rsbuildConfig.server?.compress).toBe(false) + }) + + test('transform server.compress: true', () => { + const rsbuildConfig = toRsbuildConfig({ + server: { compress: true }, + }) + expect(rsbuildConfig.server?.compress).toBe(true) + }) + + test('transform server.compress: { level } object format', () => { + const rsbuildConfig = toRsbuildConfig({ + server: { compress: { level: 6 } }, + }) + expect(rsbuildConfig.server?.compress).toMatchInlineSnapshot(` + { + "level": 6, + } + `) + }) + + test('transform server.compress: { filter } object format', () => { + const filter = (req: IncomingMessage) => + !(req.url ?? '').startsWith('/nozip') + const rsbuildConfig = toRsbuildConfig({ + server: { compress: { filter } }, + }) + expect( + rsbuildConfig.server + && typeof rsbuildConfig.server.compress === 'object', + ).toBe(true) + const compress = rsbuildConfig.server!.compress as { + filter: typeof filter + } + expect(typeof compress.filter).toBe('function') + const expectFunction = compress.filter + expect(expectFunction({ url: '/nozip/a.js' } as IncomingMessage)).toBe( + false, + ) + expect(expectFunction({ url: '/ok/b.js' } as IncomingMessage)).toBe(true) + }) + }) + describe('Source', () => { test('transform empty source.alias', () => { const rsbuildConfig = toRsbuildConfig({ diff --git a/packages/rspeedy/core/test/config/server.test-d.ts b/packages/rspeedy/core/test/config/server.test-d.ts index 5ea3872474..b00ccb8a35 100644 --- a/packages/rspeedy/core/test/config/server.test-d.ts +++ b/packages/rspeedy/core/test/config/server.test-d.ts @@ -14,6 +14,23 @@ describe('Config - Server', () => { assertType({ base: '/foo' }) }) + test('server.compress', () => { + assertType({}) + assertType({ compress: undefined }) + assertType({ compress: false }) + assertType({ compress: true }) + assertType({ compress: { level: 1 } }) + assertType({ + compress: { + filter: (req, res) => { + assertType(req) + assertType(res) + return true + }, + }, + }) + }) + test('server.headers', () => { assertType({}) assertType({