From 2fedf37a481322fcab277b44cbdfc9bb24cc68bb Mon Sep 17 00:00:00 2001 From: neverland Date: Fri, 4 Oct 2024 06:47:24 +0800 Subject: [PATCH] feat: define `import.meta.env.BASE_URL` (#3632) --- .../server/base-url-env-var/index.test.ts | 54 ++++++++++++++++++ .../server/base-url-env-var/src/index.html | 10 ++++ .../{base => base-url-env-var}/src/index.js | 0 .../server/{base => base-url}/index.test.ts | 13 ----- .../server/{base => base-url}/public/aaa.txt | 0 e2e/cases/server/base-url/src/index.js | 5 ++ e2e/cases/server/base/src/index.html | 13 ----- .../tests/__snapshots__/default.test.ts.snap | 4 ++ .../__snapshots__/webpackConfig.test.ts.snap | 1 + packages/core/src/plugins/define.ts | 5 +- .../tests/__snapshots__/builder.test.ts.snap | 1 + .../tests/__snapshots__/default.test.ts.snap | 4 ++ .../tests/__snapshots__/define.test.ts.snap | 1 + .../__snapshots__/environments.test.ts.snap | 2 + .../tests/__snapshots__/index.test.ts.snap | 1 + website/docs/en/guide/advanced/env-vars.mdx | 55 +++++++++++-------- website/docs/zh/guide/advanced/env-vars.mdx | 55 +++++++++++-------- 17 files changed, 153 insertions(+), 71 deletions(-) create mode 100644 e2e/cases/server/base-url-env-var/index.test.ts create mode 100644 e2e/cases/server/base-url-env-var/src/index.html rename e2e/cases/server/{base => base-url-env-var}/src/index.js (100%) rename e2e/cases/server/{base => base-url}/index.test.ts (88%) rename e2e/cases/server/{base => base-url}/public/aaa.txt (100%) create mode 100644 e2e/cases/server/base-url/src/index.js delete mode 100644 e2e/cases/server/base/src/index.html diff --git a/e2e/cases/server/base-url-env-var/index.test.ts b/e2e/cases/server/base-url-env-var/index.test.ts new file mode 100644 index 0000000000..d6d7f62d8c --- /dev/null +++ b/e2e/cases/server/base-url-env-var/index.test.ts @@ -0,0 +1,54 @@ +import { build, dev, rspackOnlyTest } from '@e2e/helper'; +import { expect } from '@playwright/test'; + +rspackOnlyTest( + 'should define BASE_URL env var correctly in dev', + async ({ page }) => { + const rsbuild = await dev({ + cwd: __dirname, + page, + rsbuildConfig: { + html: { + template: './src/index.html', + }, + server: { + base: '/base', + }, + }, + }); + + // should define `process.env.BASE_URL` correctly + await expect(page.locator('#public-base-path-process')).toHaveText('/base'); + + // should define `import.meta.env.BASE_URL` correctly + await expect(page.locator('#public-base-path-meta')).toHaveText('/base'); + + await rsbuild.close(); + }, +); + +rspackOnlyTest( + 'should define BASE_URL env var correctly in build', + async ({ page }) => { + const rsbuild = await build({ + cwd: __dirname, + page, + rsbuildConfig: { + html: { + template: './src/index.html', + }, + server: { + base: '/base', + }, + }, + }); + + // should define `process.env.BASE_URL` correctly + await expect(page.locator('#public-base-path-process')).toHaveText('/base'); + + // should define `import.meta.env.BASE_URL` correctly + await expect(page.locator('#public-base-path-meta')).toHaveText('/base'); + + await rsbuild.close(); + }, +); diff --git a/e2e/cases/server/base-url-env-var/src/index.html b/e2e/cases/server/base-url-env-var/src/index.html new file mode 100644 index 0000000000..fba72835b7 --- /dev/null +++ b/e2e/cases/server/base-url-env-var/src/index.html @@ -0,0 +1,10 @@ + + + + + +
<%= process.env.BASE_URL %>
+
<%= import.meta.env.BASE_URL %>
+
+ + diff --git a/e2e/cases/server/base/src/index.js b/e2e/cases/server/base-url-env-var/src/index.js similarity index 100% rename from e2e/cases/server/base/src/index.js rename to e2e/cases/server/base-url-env-var/src/index.js diff --git a/e2e/cases/server/base/index.test.ts b/e2e/cases/server/base-url/index.test.ts similarity index 88% rename from e2e/cases/server/base/index.test.ts rename to e2e/cases/server/base-url/index.test.ts index a40c1b5500..1a97c89db2 100644 --- a/e2e/cases/server/base/index.test.ts +++ b/e2e/cases/server/base-url/index.test.ts @@ -8,9 +8,6 @@ test('server.base when dev', async ({ page }) => { cwd: __dirname, page, rsbuildConfig: { - html: { - template: './src/index.html', - }, server: { printUrls: true, base: '/base', @@ -23,9 +20,6 @@ test('server.base when dev', async ({ page }) => { expect(page.url().includes('/base/')).toBeTruthy(); - // should define `process.env.BASE_URL` correctly - await expect(page.locator('#public-base-path')).toHaveText('/base'); - // should print url with base path const baseUrlLog = logs.find( (log) => @@ -61,11 +55,7 @@ test('server.base when build & preview', async ({ page }) => { const rsbuild = await build({ cwd: __dirname, page, - runServer: true, rsbuildConfig: { - html: { - template: './src/index.html', - }, server: { printUrls: true, base: '/base', @@ -78,9 +68,6 @@ test('server.base when build & preview', async ({ page }) => { expect(page.url().includes('/base/')).toBeTruthy(); - // should define `process.env.BASE_URL` correctly - await expect(page.locator('#public-base-path')).toHaveText('/base'); - // should print url with base path const baseUrlLog = logs.find( (log) => diff --git a/e2e/cases/server/base/public/aaa.txt b/e2e/cases/server/base-url/public/aaa.txt similarity index 100% rename from e2e/cases/server/base/public/aaa.txt rename to e2e/cases/server/base-url/public/aaa.txt diff --git a/e2e/cases/server/base-url/src/index.js b/e2e/cases/server/base-url/src/index.js new file mode 100644 index 0000000000..28b53a9d64 --- /dev/null +++ b/e2e/cases/server/base-url/src/index.js @@ -0,0 +1,5 @@ +const testEl = document.createElement('div'); +testEl.id = 'test'; +testEl.innerHTML = 'Hello Rsbuild!'; + +document.body.appendChild(testEl); diff --git a/e2e/cases/server/base/src/index.html b/e2e/cases/server/base/src/index.html deleted file mode 100644 index 3def557897..0000000000 --- a/e2e/cases/server/base/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - -
- <%= process.env.BASE_URL %> -
-
- - - diff --git a/packages/compat/webpack/tests/__snapshots__/default.test.ts.snap b/packages/compat/webpack/tests/__snapshots__/default.test.ts.snap index 758b4b0859..338a6e2135 100644 --- a/packages/compat/webpack/tests/__snapshots__/default.test.ts.snap +++ b/packages/compat/webpack/tests/__snapshots__/default.test.ts.snap @@ -302,6 +302,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly 1`] = ` }, DefinePlugin { "definitions": { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": true, "import.meta.env.MODE": ""development"", "import.meta.env.PROD": false, @@ -661,6 +662,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when produ }, DefinePlugin { "definitions": { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": false, "import.meta.env.MODE": ""production"", "import.meta.env.PROD": true, @@ -969,6 +971,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when targe RsbuildCorePlugin {}, DefinePlugin { "definitions": { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": false, "import.meta.env.MODE": ""production"", "import.meta.env.PROD": true, @@ -1260,6 +1263,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when targe RsbuildCorePlugin {}, DefinePlugin { "definitions": { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": false, "import.meta.env.MODE": ""production"", "import.meta.env.PROD": true, diff --git a/packages/compat/webpack/tests/__snapshots__/webpackConfig.test.ts.snap b/packages/compat/webpack/tests/__snapshots__/webpackConfig.test.ts.snap index 97c9ad5349..e22ba0173e 100644 --- a/packages/compat/webpack/tests/__snapshots__/webpackConfig.test.ts.snap +++ b/packages/compat/webpack/tests/__snapshots__/webpackConfig.test.ts.snap @@ -67,6 +67,7 @@ exports[`webpackConfig > should allow to append and prepend plugins 1`] = ` }, DefinePlugin { "definitions": { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": false, "import.meta.env.MODE": ""none"", "import.meta.env.PROD": false, diff --git a/packages/core/src/plugins/define.ts b/packages/core/src/plugins/define.ts index dd80646850..53a76eb0aa 100644 --- a/packages/core/src/plugins/define.ts +++ b/packages/core/src/plugins/define.ts @@ -7,14 +7,17 @@ export const pluginDefine = (): RsbuildPlugin => ({ setup(api) { api.modifyBundlerChain((chain, { CHAIN_ID, bundler, environment }) => { const { config } = environment; + + const baseUrl = JSON.stringify(config.server.base); const builtinVars: Define = { 'import.meta.env.MODE': JSON.stringify(config.mode), 'import.meta.env.DEV': config.mode === 'development', 'import.meta.env.PROD': config.mode === 'production', + 'import.meta.env.BASE_URL': baseUrl, 'process.env.ASSET_PREFIX': JSON.stringify( getPublicPathFromChain(chain, false), ), - 'process.env.BASE_URL': JSON.stringify(config.server.base), + 'process.env.BASE_URL': baseUrl, }; chain diff --git a/packages/core/tests/__snapshots__/builder.test.ts.snap b/packages/core/tests/__snapshots__/builder.test.ts.snap index be82137e89..16381269e8 100644 --- a/packages/core/tests/__snapshots__/builder.test.ts.snap +++ b/packages/core/tests/__snapshots__/builder.test.ts.snap @@ -359,6 +359,7 @@ exports[`should use rspack as default bundler > apply rspack correctly 1`] = ` DefinePlugin { "_args": [ { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": true, "import.meta.env.MODE": ""development"", "import.meta.env.PROD": false, diff --git a/packages/core/tests/__snapshots__/default.test.ts.snap b/packages/core/tests/__snapshots__/default.test.ts.snap index 46550f2f07..bfdbd91a9e 100644 --- a/packages/core/tests/__snapshots__/default.test.ts.snap +++ b/packages/core/tests/__snapshots__/default.test.ts.snap @@ -359,6 +359,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly 1`] = ` DefinePlugin { "_args": [ { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": true, "import.meta.env.MODE": ""development"", "import.meta.env.PROD": false, @@ -780,6 +781,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when prod DefinePlugin { "_args": [ { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": false, "import.meta.env.MODE": ""production"", "import.meta.env.PROD": true, @@ -1117,6 +1119,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when targe DefinePlugin { "_args": [ { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": true, "import.meta.env.MODE": ""development"", "import.meta.env.PROD": false, @@ -1518,6 +1521,7 @@ exports[`tools.rspack > should match snapshot 1`] = ` DefinePlugin { "_args": [ { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": true, "import.meta.env.MODE": ""development"", "import.meta.env.PROD": false, diff --git a/packages/core/tests/__snapshots__/define.test.ts.snap b/packages/core/tests/__snapshots__/define.test.ts.snap index 4fc529917f..e7f7323b2c 100644 --- a/packages/core/tests/__snapshots__/define.test.ts.snap +++ b/packages/core/tests/__snapshots__/define.test.ts.snap @@ -8,6 +8,7 @@ exports[`plugin-define > should register define plugin correctly 1`] = ` "_args": [ { "NAME": ""Jack"", + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": false, "import.meta.env.MODE": ""none"", "import.meta.env.PROD": false, diff --git a/packages/core/tests/__snapshots__/environments.test.ts.snap b/packages/core/tests/__snapshots__/environments.test.ts.snap index 0c23dca7cc..66a224c698 100644 --- a/packages/core/tests/__snapshots__/environments.test.ts.snap +++ b/packages/core/tests/__snapshots__/environments.test.ts.snap @@ -1698,6 +1698,7 @@ exports[`environment config > tools.rspack / bundlerChain can be configured in e DefinePlugin { "_args": [ { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": true, "import.meta.env.MODE": ""development"", "import.meta.env.PROD": false, @@ -2016,6 +2017,7 @@ exports[`environment config > tools.rspack / bundlerChain can be configured in e DefinePlugin { "_args": [ { + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": true, "import.meta.env.MODE": ""development"", "import.meta.env.PROD": false, diff --git a/packages/plugin-vue/tests/__snapshots__/index.test.ts.snap b/packages/plugin-vue/tests/__snapshots__/index.test.ts.snap index 5dc20010f5..8086272a5c 100644 --- a/packages/plugin-vue/tests/__snapshots__/index.test.ts.snap +++ b/packages/plugin-vue/tests/__snapshots__/index.test.ts.snap @@ -78,6 +78,7 @@ DefinePlugin { "__VUE_OPTIONS_API__": true, "__VUE_PROD_DEVTOOLS__": false, "__VUE_PROD_HYDRATION_MISMATCH_DETAILS__": false, + "import.meta.env.BASE_URL": "\\"/\\"", "import.meta.env.DEV": false, "import.meta.env.MODE": ""none"", "import.meta.env.PROD": false, diff --git a/website/docs/en/guide/advanced/env-vars.mdx b/website/docs/en/guide/advanced/env-vars.mdx index 54273855ab..75eff9b6f6 100644 --- a/website/docs/en/guide/advanced/env-vars.mdx +++ b/website/docs/en/guide/advanced/env-vars.mdx @@ -37,6 +37,39 @@ You can also use the following environment variables: - `import.meta.env.DEV`: If [mode](/config/mode) is `'development'`, the value is `true`; otherwise, it is `false`. - `import.meta.env.PROD`: If [mode](/config/mode) is `'production'`, the value is `true`; otherwise, it is `false`. +### import.meta.env.BASE_URL + +You can use `import.meta.env.BASE_URL` in the client code to access the server's [base path](/guide/basic/server#base-path), which is determined by the [server.base](/config/server/base) configuration, which is helpful for referencing [public folder](/guide/basic/static-assets#public-folder) assets in the code. + +For example, we set the base path of the server to `/foo` through [server.base](/config/server/base) configuration: + +```ts +export default { + server: { + base: '/foo', + }, +}; +``` + +Then, the access URL to the `favicon.ico` file in the public directory is `http://localhost:3000/foo/favicon.ico`. You can use `import.meta.env.BASE_URL` to concatenate the URL in JS files: + +```js title="index.js" +const image = new Image(); +// Equivalent to "/foo/favicon.ico" +image.src = `${import.meta.env.BASE_URL}/favicon.ico`; +``` + +In the HTML template, you can also use `import.meta.env.BASE_URL` to concatenate the URL: + +```html title="index.html" + + +``` + +Additionally, you can use the following environment variables: + +- `process.env.BASE_URL`: Equivalent to `import.meta.env.BASE_URL`. + ### process.env.NODE_ENV By default, Rsbuild will automatically set the `process.env.NODE_ENV` environment variable to `'development'` in development mode and `'production'` in production mode. @@ -107,28 +140,6 @@ In production mode, the above code will be compiled to: const Image = ; ``` -### process.env.BASE_URL - -You can use `process.env.BASE_URL` in client code to access the server's [base path](/guide/basic/server#base-path). - -This is helpful for us to reference [public folder](/guide/basic/static-assets#public-folder) assets in HTML templates. - -For example, we set the base path of the server to `/foo` through [server.base](/config/server/base) configuration: - -```ts -export default { - server: { - base: '/foo', - }, -}; -``` - -Then, the access path to the `favicon.ico` file in the public directory is `http://localhost:3000/foo/favicon.ico`. We can reference `./public/favicon.ico` file in the HTML template like this: - -```html title="index.html" - -``` - ## `.env` File When a `.env` file exists in the project root directory, Rsbuild CLI will automatically use [dotenv](https://npmjs.com/package/dotenv) to load these environment variables and add them to the current Node.js process. diff --git a/website/docs/zh/guide/advanced/env-vars.mdx b/website/docs/zh/guide/advanced/env-vars.mdx index 92ae89d22e..2fa1b792d7 100644 --- a/website/docs/zh/guide/advanced/env-vars.mdx +++ b/website/docs/zh/guide/advanced/env-vars.mdx @@ -37,6 +37,39 @@ if (false) { - `import.meta.env.DEV`:当 [mode](/config/mode) 为 `'development'` 时,值为 `true`,否则为 `false`。 - `import.meta.env.PROD`:当 [mode](/config/mode) 为 `'production'` 时,值为 `true`,否则为 `false`。 +### import.meta.env.BASE_URL + +你可以在 client 代码中使用 `import.meta.env.BASE_URL` 来访问服务端的[基础路径](/guide/basic/server#服务端基础路径),它由 [server.base](/config/server/base) 配置项决定,这有助于在代码中引用 [public 目录](/guide/basic/static-assets#public-目录) 下的资源。 + +比如,我们通过 [server.base](/config/server/base) 配置,将服务端的基础路径设置为 `/foo`: + +```ts +export default { + server: { + base: '/foo', + }, +}; +``` + +此时,public 目录下 `favicon.ico` 文件的访问 URL 为 `http://localhost:3000/foo/favicon.ico`,在 JS 文件中可以使用 `import.meta.env.BASE_URL` 来拼接 URL: + +```js title="index.js" +const image = new Image(); +// 等价于 "/foo/favicon.ico" +image.src = `${import.meta.env.BASE_URL}/favicon.ico`; +``` + +在 HTML 模板中,也可以使用 `import.meta.env.BASE_URL` 来拼接 URL: + +```html title="index.html" + + +``` + +此外,你还可以使用以下环境变量: + +- `process.env.BASE_URL`:等同于 `import.meta.env.BASE_URL`。 + ### process.env.NODE_ENV 默认情况下,Rsbuild 会自动设置 `process.env.NODE_ENV` 环境变量,在开发模式为 `'development'`,生产模式为 `'production'`。 @@ -107,28 +140,6 @@ const Image = ; const Image = ; ``` -### process.env.BASE_URL - -你可以在 client 代码中使用 `process.env.BASE_URL` 来访问服务端的[基础路径](/guide/basic/server#服务端基础路径)。 - -这对于我们在 HTML 模版中引用 [public 目录](/guide/basic/static-assets#public-目录) 资源很有帮助。 - -比如,我们通过 [server.base](/config/server/base) 配置,将服务端的基础路径设置为 `/foo`: - -```ts -export default { - server: { - base: '/foo', - }, -}; -``` - -此时,public 目录下 `favicon.ico` 文件的访问路径为 `http://localhost:3000/foo/favicon.ico`,我们可以采用如下方式在 HTML 模板中引用 `./public/favicon.ico` 文件: - -```html title="index.html" - -``` - ## `.env` 文件 当项目根目录存在 `.env` 文件时,Rsbuild CLI 会自动使用 [dotenv](https://npmjs.com/package/dotenv) 来加载这些环境变量,并添加到当前 Node.js 进程中。