diff --git a/e2e/cases/server/fallback/index.test.ts b/e2e/cases/server/fallback/index.test.ts index 180fb5a6a3..dde42bc567 100644 --- a/e2e/cases/server/fallback/index.test.ts +++ b/e2e/cases/server/fallback/index.test.ts @@ -28,6 +28,9 @@ test('OPTIONS request should response correctly with middleware responses', asyn cwd: __dirname, page, rsbuildConfig: { + server: { + cors: false, + }, dev: { setupMiddlewares: [ (middlewares) => { diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index ae4cf47f78..7cde4753c5 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -73,6 +73,15 @@ const getDefaultDevConfig = (): NormalizedDevConfig => ({ }, }); +/** + * Default allowed origins for CORS. + * - localhost + * - 127.0.0.1 + * - [::1] + */ +export const LOCAL_ORIGINS_REGEX: RegExp = + /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/; + const getDefaultServerConfig = (): NormalizedServerConfig => ({ port: DEFAULT_PORT, host: DEFAULT_DEV_HOST, @@ -82,7 +91,9 @@ const getDefaultServerConfig = (): NormalizedServerConfig => ({ compress: true, printUrls: true, strictPort: false, - cors: false, + cors: { + origin: LOCAL_ORIGINS_REGEX, + }, middlewareMode: false, }); diff --git a/packages/core/src/plugins/moduleFederation.ts b/packages/core/src/plugins/moduleFederation.ts index 08bb32096b..fc5880f34b 100644 --- a/packages/core/src/plugins/moduleFederation.ts +++ b/packages/core/src/plugins/moduleFederation.ts @@ -106,7 +106,7 @@ export function pluginModuleFederation(): RsbuildPlugin { // This is required for MF to work properly across different origins // TODO: remove this after https://github.com/module-federation/core/pull/3635 is released config.server ||= {}; - config.server.cors ||= true; + config.server.cors = true; } if (!moduleFederation?.options) { @@ -120,7 +120,7 @@ export function pluginModuleFederation(): RsbuildPlugin { // Allow remote modules to be loaded by setting CORS headers // This is required for MF to work properly across different origins - config.server.cors ||= true; + config.server.cors = true; // For remote modules, Rsbuild should send the ws request to the provider's dev server. // This allows the provider to do HMR when the provider module is loaded in the consumer's page. diff --git a/packages/core/tests/__snapshots__/environments.test.ts.snap b/packages/core/tests/__snapshots__/environments.test.ts.snap index 1c683e4bb6..563aff7d49 100644 --- a/packages/core/tests/__snapshots__/environments.test.ts.snap +++ b/packages/core/tests/__snapshots__/environments.test.ts.snap @@ -111,7 +111,9 @@ exports[`environment config > should normalize environment config correctly 1`] "server": { "base": "/", "compress": true, - "cors": false, + "cors": { + "origin": /\\^https\\?:\\\\/\\\\/\\(\\?:\\(\\?:\\[\\^:\\]\\+\\\\\\.\\)\\?localhost\\|127\\\\\\.0\\\\\\.0\\\\\\.1\\|\\\\\\[::1\\\\\\]\\)\\(\\?::\\\\d\\+\\)\\?\\$/, + }, "host": "0.0.0.0", "htmlFallback": "index", "middlewareMode": false, @@ -253,7 +255,9 @@ exports[`environment config > should normalize environment config correctly 2`] "server": { "base": "/", "compress": true, - "cors": false, + "cors": { + "origin": /\\^https\\?:\\\\/\\\\/\\(\\?:\\(\\?:\\[\\^:\\]\\+\\\\\\.\\)\\?localhost\\|127\\\\\\.0\\\\\\.0\\\\\\.1\\|\\\\\\[::1\\\\\\]\\)\\(\\?::\\\\d\\+\\)\\?\\$/, + }, "host": "0.0.0.0", "htmlFallback": "index", "middlewareMode": false, @@ -395,7 +399,9 @@ exports[`environment config > should print environment config when inspect confi "server": { "base": "/", "compress": true, - "cors": false, + "cors": { + "origin": /\\^https\\?:\\\\/\\\\/\\(\\?:\\(\\?:\\[\\^:\\]\\+\\\\\\.\\)\\?localhost\\|127\\\\\\.0\\\\\\.0\\\\\\.1\\|\\\\\\[::1\\\\\\]\\)\\(\\?::\\\\d\\+\\)\\?\\$/, + }, "host": "0.0.0.0", "htmlFallback": "index", "middlewareMode": false, @@ -533,7 +539,9 @@ exports[`environment config > should print environment config when inspect confi "server": { "base": "/", "compress": true, - "cors": false, + "cors": { + "origin": /\\^https\\?:\\\\/\\\\/\\(\\?:\\(\\?:\\[\\^:\\]\\+\\\\\\.\\)\\?localhost\\|127\\\\\\.0\\\\\\.0\\\\\\.1\\|\\\\\\[::1\\\\\\]\\)\\(\\?::\\\\d\\+\\)\\?\\$/, + }, "host": "0.0.0.0", "htmlFallback": "index", "middlewareMode": false, @@ -691,7 +699,9 @@ exports[`environment config > should support modify environment config by api.mo "server": { "base": "/", "compress": true, - "cors": false, + "cors": { + "origin": /\\^https\\?:\\\\/\\\\/\\(\\?:\\(\\?:\\[\\^:\\]\\+\\\\\\.\\)\\?localhost\\|127\\\\\\.0\\\\\\.0\\\\\\.1\\|\\\\\\[::1\\\\\\]\\)\\(\\?::\\\\d\\+\\)\\?\\$/, + }, "host": "0.0.0.0", "htmlFallback": "index", "middlewareMode": false, @@ -830,7 +840,9 @@ exports[`environment config > should support modify environment config by api.mo "server": { "base": "/", "compress": true, - "cors": false, + "cors": { + "origin": /\\^https\\?:\\\\/\\\\/\\(\\?:\\(\\?:\\[\\^:\\]\\+\\\\\\.\\)\\?localhost\\|127\\\\\\.0\\\\\\.0\\\\\\.1\\|\\\\\\[::1\\\\\\]\\)\\(\\?::\\\\d\\+\\)\\?\\$/, + }, "host": "0.0.0.0", "htmlFallback": "index", "middlewareMode": false, @@ -969,7 +981,9 @@ exports[`environment config > should support modify environment config by api.mo "server": { "base": "/", "compress": true, - "cors": false, + "cors": { + "origin": /\\^https\\?:\\\\/\\\\/\\(\\?:\\(\\?:\\[\\^:\\]\\+\\\\\\.\\)\\?localhost\\|127\\\\\\.0\\\\\\.0\\\\\\.1\\|\\\\\\[::1\\\\\\]\\)\\(\\?::\\\\d\\+\\)\\?\\$/, + }, "host": "0.0.0.0", "htmlFallback": "index", "middlewareMode": false, @@ -1110,7 +1124,9 @@ exports[`environment config > should support modify single environment config by "server": { "base": "/", "compress": true, - "cors": false, + "cors": { + "origin": /\\^https\\?:\\\\/\\\\/\\(\\?:\\(\\?:\\[\\^:\\]\\+\\\\\\.\\)\\?localhost\\|127\\\\\\.0\\\\\\.0\\\\\\.1\\|\\\\\\[::1\\\\\\]\\)\\(\\?::\\\\d\\+\\)\\?\\$/, + }, "host": "0.0.0.0", "htmlFallback": "index", "middlewareMode": false, @@ -1249,7 +1265,9 @@ exports[`environment config > should support modify single environment config by "server": { "base": "/", "compress": true, - "cors": false, + "cors": { + "origin": /\\^https\\?:\\\\/\\\\/\\(\\?:\\(\\?:\\[\\^:\\]\\+\\\\\\.\\)\\?localhost\\|127\\\\\\.0\\\\\\.0\\\\\\.1\\|\\\\\\[::1\\\\\\]\\)\\(\\?::\\\\d\\+\\)\\?\\$/, + }, "host": "0.0.0.0", "htmlFallback": "index", "middlewareMode": false, diff --git a/packages/core/tests/server.test.ts b/packages/core/tests/server.test.ts index fbbeafcf88..3a4ced2b63 100644 --- a/packages/core/tests/server.test.ts +++ b/packages/core/tests/server.test.ts @@ -1,4 +1,5 @@ import { rspack } from '@rspack/core'; +import { LOCAL_ORIGINS_REGEX } from '../src/config'; import { isClientCompiler, setupServerHooks, @@ -307,3 +308,35 @@ describe('test dev server', () => { ).toBeFalsy(); }); }); + +test('local origins regex', () => { + expect(LOCAL_ORIGINS_REGEX.test('http://localhost:3000')).toBeTruthy(); + expect(LOCAL_ORIGINS_REGEX.test('http://foo.localhost:3000')).toBeTruthy(); + expect(LOCAL_ORIGINS_REGEX.test('http://127.0.0.1:3000')).toBeTruthy(); + expect(LOCAL_ORIGINS_REGEX.test('http://[::1]:3000')).toBeTruthy(); + + // HTTPS protocols + expect(LOCAL_ORIGINS_REGEX.test('https://localhost:3000')).toBeTruthy(); + expect(LOCAL_ORIGINS_REGEX.test('https://127.0.0.1:8080')).toBeTruthy(); + expect(LOCAL_ORIGINS_REGEX.test('https://foo.localhost:3000')).toBeTruthy(); + expect(LOCAL_ORIGINS_REGEX.test('https://[::1]:3000')).toBeTruthy(); + + // Without port + expect(LOCAL_ORIGINS_REGEX.test('http://localhost')).toBeTruthy(); + expect(LOCAL_ORIGINS_REGEX.test('https://127.0.0.1')).toBeTruthy(); + expect(LOCAL_ORIGINS_REGEX.test('http://[::1]')).toBeTruthy(); + + // Multi-level subdomains + expect( + LOCAL_ORIGINS_REGEX.test('http://test.dev.localhost:8000'), + ).toBeTruthy(); + + // High port + expect(LOCAL_ORIGINS_REGEX.test('http://localhost:65535')).toBeTruthy(); + + // Invalid cases + expect(LOCAL_ORIGINS_REGEX.test('http://example.com')).toBeFalsy(); + expect(LOCAL_ORIGINS_REGEX.test('http://192.168.1.1:3000')).toBeFalsy(); + expect(LOCAL_ORIGINS_REGEX.test('ftp://localhost:21')).toBeFalsy(); + expect(LOCAL_ORIGINS_REGEX.test('localhost')).toBeFalsy(); // +}); diff --git a/website/docs/en/config/server/cors.mdx b/website/docs/en/config/server/cors.mdx index 32f6650691..722cddb8fe 100644 --- a/website/docs/en/config/server/cors.mdx +++ b/website/docs/en/config/server/cors.mdx @@ -1,7 +1,18 @@ # server.cors - **Type:** `boolean | import('cors').CorsOptions` -- **Default:** `false` + +```ts +const defaultCorsOptions = { + // Default allowed: + // - localhost + // - 127.0.0.1 + // - [::1] + origin: + /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/, +}; +``` + - **Version:** `>= 1.1.11` Configure [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) options for the dev server or preview server, based on the [cors](https://github.com/expressjs/cors) middleware. @@ -114,7 +125,10 @@ Specify multiple allowed origins using an array: export default { server: { cors: { - origin: ['https://example.com', 'https://other.com'], + origin: [ + /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/, + 'https://example.com', + ], }, }, }; diff --git a/website/docs/zh/config/server/base.mdx b/website/docs/zh/config/server/base.mdx index 0bbbcc4888..23cab94e54 100644 --- a/website/docs/zh/config/server/base.mdx +++ b/website/docs/zh/config/server/base.mdx @@ -32,7 +32,7 @@ export default { 此时,可以通过 `http://localhost:3000/foo/` 访问到 `index.html` 以及其他静态资源产物。 -如果您不希望使用此默认行为,可以通过显式设置 `dev.assetPrefix` / `output.assetPrefix` 来覆盖: +如果你不希望使用此默认行为,可以通过显式设置 `dev.assetPrefix` / `output.assetPrefix` 来覆盖: ```ts export default { diff --git a/website/docs/zh/config/server/cors.mdx b/website/docs/zh/config/server/cors.mdx index e949db8fd8..65c41a5a86 100644 --- a/website/docs/zh/config/server/cors.mdx +++ b/website/docs/zh/config/server/cors.mdx @@ -1,7 +1,19 @@ # server.cors - **类型:** `boolean | import('cors').CorsOptions` -- **默认值:** `false` +- **默认值:** + +```ts +const defaultCorsOptions = { + // 默认允许: + // - localhost + // - 127.0.0.1 + // - [::1] + origin: + /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/, +}; +``` + - **版本:** `>= 1.1.11` 为开发服务器和预览服务器配置 [CORS](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS) 选项,基于 [cors](https://github.com/expressjs/cors) 中间件实现。 @@ -11,7 +23,7 @@ - `false`:禁用 CORS。 :::warning -使用 `cors: true` 或 `cors.origin: '*'` 会使您的开发服务器对所有 origin 开放,这可能会危及源代码的安全性,建议使用 [origin](#origin) 选项指定一个受信任 origins 的白名单。 +使用 `cors: true` 或 `cors.origin: '*'` 会使你的开发服务器对所有 origin 开放,这可能会危及源代码的安全性,建议使用 [origin](#origin) 选项指定一个受信任 origins 的白名单。 ::: ## 示例 @@ -114,7 +126,10 @@ export default { export default { server: { cors: { - origin: ['https://example.com', 'https://other.com'], + origin: [ + /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/, + 'https://example.com', + ], }, }, }; diff --git a/website/docs/zh/guide/basic/web-workers.mdx b/website/docs/zh/guide/basic/web-workers.mdx index 879be0285d..04bcffc76f 100644 --- a/website/docs/zh/guide/basic/web-workers.mdx +++ b/website/docs/zh/guide/basic/web-workers.mdx @@ -3,7 +3,7 @@ 本文将介绍在 Rsbuild 项目中如何配置和使用 [Web Workers](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers)。 :::tip Web Workers -Web Workers 是一种 JavaScript API,它允许网页在后台线程中执行脚本,与主线程(网页)分离。这意味着,您可以使用 Web Workers 来执行计算密集型或长时间运行的任务,而无需阻塞主线程,进而影响网页的性能。 +Web Workers 是一种 JavaScript API,它允许网页在后台线程中执行脚本,与主线程(网页)分离。这意味着,你可以使用 Web Workers 来执行计算密集型或长时间运行的任务,而无需阻塞主线程,进而影响网页的性能。 ::: ## 使用 Web Workers diff --git a/website/docs/zh/guide/faq/hmr.mdx b/website/docs/zh/guide/faq/hmr.mdx index a41dfe9643..264b29b28f 100644 --- a/website/docs/zh/guide/faq/hmr.mdx +++ b/website/docs/zh/guide/faq/hmr.mdx @@ -108,4 +108,4 @@ export default { 此问题的解决方法为:点击 Chrome 浏览器问题页面的「高级」->「继续前往 some page(不安全)」。 -> Tips: 当通过 Localhost 访问页面时,「您的连接不是私密连接」字样可能不会出现,可访问 Network 域名进行处理。 +> Tips: 当通过 Localhost 访问页面时,「你的连接不是私密连接」字样可能不会出现,可访问 Network 域名进行处理。