Skip to content

feat(web): support classic Rsbuild dev and build - #5232

Merged
t0ng7u merged 2 commits into
mainfrom
feat/classic-rsbuild-dev-workflow
Jun 2, 2026
Merged

feat(web): support classic Rsbuild dev and build#5232
t0ng7u merged 2 commits into
mainfrom
feat/classic-rsbuild-dev-workflow

Conversation

@QuentinHsu

@QuentinHsu QuentinHsu commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator
  • migrate the classic frontend from Vite to Rsbuild with JSX, Semi UI, proxy, and production build config.
  • update make dev-web to run both default and classic frontends for local theme switching.
  • fix classic public page height, footer, CORS proxy, error handling, and constant export warnings.
  • update Dockerfile and release workflow to install from the web workspace root with the shared lockfile.

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

概述

  • 为 classic 前端补齐 Rsbuild 开发和生产构建链路,并让本地调试可以同时运行 default 与 classic 两套前端。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

改动说明

  • 新增 classic Rsbuild 配置,替换 Vite 脚本与配置,并更新相关依赖锁文件。
  • 更新 make dev-web,同时启动 default 5173 与 classic 5174,并处理子进程退出清理。
  • classic 开发环境 API 默认走同源代理,避免 localhost 前端分离调试时触发 CORS。
  • 修复 classic 首页、关于页、登录/注册/重置、协议、403/404 等公开页高度和 footer 布局问题。
  • 修复 Axios 无 response 时的错误处理,并显式导出 constants,避免 Rsbuild 星号导出冲突告警。
  • 更新 Dockerfile 与 release workflow,从 web workspace 根执行 bun install --frozen-lockfile,保证生产构建使用统一 web/bun.lock。

使用方式

  • 本地运行 make dev-web 可同时访问 default 与 classic 前端。
  • 生产构建继续使用 make build-all-frontends、Dockerfile 或 release workflow,均已切换到 workspace 根依赖安装方式。
  • 已验证 make build-all-frontends、classic 构建、公开页桌面/移动布局和 diff check。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

Summary by CodeRabbit

  • New Features

    • Concurrent dev servers for both frontends with configurable ports.
    • Release/build now supports separate "default" and "classic" frontend flavors.
  • Bug Fixes

    • Prevented runtime errors when HTTP error responses are missing.
    • Improved mobile viewport handling for more reliable full-height layouts.
  • Improvements

    • Switched to frozen dependency installs and updated container build for frontend flavors.
    • Classic frontend migrated to new build tooling and React 19; multiple UI/layout refinements (auth, home, about, error, document).

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ac9d8cfb-779c-4df3-8ac6-a655f0fe4a14

📥 Commits

Reviewing files that changed from the base of the PR and between 1e9ff8a and 0bbcaa8.

📒 Files selected for processing (1)
  • web/classic/src/index.jsx

Walkthrough

Migrates web/classic from Vite to Rsbuild (React → v19), centralizes Bun installs with frozen lockfile, updates CI/Docker/make to build both frontend flavors, refactors layout CSS/PageLayout for fixed/flex behavior, applies classic-page-fill across pages, and converts wildcard constants exports to explicit named exports.

Changes

Classic frontend build system migration

Layer / File(s) Summary
Rsbuild configuration and package setup
web/classic/package.json, web/classic/rsbuild.config.ts, web/classic/index.html, web/classic/src/index.jsx
React upgraded to v19, dev/build/preview scripts switched to rsbuild, Vite config removed, complete rsbuild.config.ts added (env, proxy, aliases, SWC rule), explicit module <script> in index.html removed, and @douyinfe/semi-ui/react19-adapter import added.

Build orchestration across CI, Docker, and local dev

Layer / File(s) Summary
CI and Docker updates
.github/workflows/release.yml, Dockerfile
GitHub Actions now runs bun install --frozen-lockfile from web/ and builds web/default and web/classic; Dockerfile adds per-variant Bun builder stages and copies dist from variant paths into the Go builder.
Makefile and local dev orchestration
makefile
Adds DEV_FRONTEND_DEFAULT_PORT and DEV_FRONTEND_CLASSIC_PORT, runs bun install in ./web before builds, rewrites dev-web to concurrently start both dev servers with explicit hosts/ports and signal handling, and updates classic dev target to bind host/port explicitly.

Layout refactor, component updates, constants and utilities

Layer / File(s) Summary
CSS utilities and PageLayout changes
web/classic/src/index.css, web/classic/src/components/layout/PageLayout.jsx
Replace viewport height rules with min-height/100dvh, add .classic-page-fill, .app-layout-fixed, .public-page-content, and detect isFixedLayout for /console/* and /pricing to control overflow and flex sizing.
Page and component styling updates
web/classic/src/components/*, web/classic/src/components/common/DocumentRenderer/index.jsx, web/classic/src/pages/*
Apply classic-page-fill across auth forms and DocumentRenderer states; update About/Forbidden/Home/NotFound pages; adjust iframe sizing from h-screen to flex-based or h-full.
Constants and minor helper fixes
web/classic/src/constants/index.js, web/classic/src/helpers/*, web/default/rsbuild.config.ts
Convert wildcard exports to explicit named exports for multiple constants modules; change LinkedIn icon import to FaLinkedin; use error.response?.status; enable server.strictPort for default rsbuild dev server.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • QuantumNous/new-api#5227: Related change introducing shared web/package.json workspace and unified Bun lockfile/dependency versions.

Suggested reviewers

  • Calcium-Ion
  • creamlike1024

🐰 From Vite's embrace to Rsbuild's grace,
React nineteen speeds up the race,
Layouts now flex and pages now fill,
With frozen lockfiles bending to will,
Classic and default, both built with a thrill! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: migrating classic frontend from Vite to Rsbuild for development and build support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/classic-rsbuild-dev-workflow

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
web/classic/rsbuild.config.ts (2)

77-100: 💤 Low value

Consider excluding node_modules from the custom .js SWC rule.

test: /src[\\/].*\.js$/ matches any absolute path containing a src/ segment, including dependencies shipped as .../node_modules/<pkg>/src/*.js. Those would be re-parsed with jsx: true and React refresh injected. Adding an exclude keeps the rule scoped to first-party source.

♻️ Scope the rule
             {
               test: /src[\\/].*\.js$/,
+              exclude: /[\\/]node_modules[\\/]/,
               type: 'javascript/auto',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/classic/rsbuild.config.ts` around lines 77 - 100, The SWC rule that
matches test: /src[\\/].*\.js$/ (the rule using loader 'builtin:swc-loader' with
jsc.parser.jsx and react refresh settings) can accidentally process dependency
source under node_modules; update that rule to add an exclude for node_modules
(e.g., exclude: /node_modules/) so only first-party files under src are handled
by this SWC loader and third-party packages are left untouched.

9-12: ⚡ Quick win

Fragile Semi UI directory resolution—derive package root from package.json.

semiUiDir relies on require.resolve('@douyinfe/semi-ui') landing under lib/cjs/index.js and then assumes a fixed ../.. depth to reach the package root (currently true for @douyinfe/semi-ui@2.69.1 and @douyinfe/semi-ui@2.99.3). If Semi moves its main/exports files, the computed root—and thus dist/css/semi.css—will break.

♻️ Resolve via package.json
-const semiUiDir = path.resolve(
-  path.dirname(require.resolve('`@douyinfe/semi-ui`')),
-  '../..',
-)
+const semiUiDir = path.dirname(
+  require.resolve('`@douyinfe/semi-ui/package.json`'),
+)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/classic/rsbuild.config.ts` around lines 9 - 12, The current semiUiDir
calculation is fragile because it assumes require.resolve('`@douyinfe/semi-ui`')
points two levels below the package root; change it to resolve the package root
via require.resolve('`@douyinfe/semi-ui/package.json`') and use path.dirname on
that result to get the package directory. Specifically, replace usage of
require.resolve('`@douyinfe/semi-ui`') when computing semiUiDir with
require.resolve('`@douyinfe/semi-ui/package.json`') and derive semiUiDir from
path.dirname(packageJsonPath) so downstream references (e.g., to
dist/css/semi.css) remain correct even if the package's main/exports layout
changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/classic/package.json`:
- Around line 24-25: The project is upgrading to React 19 but package.json lists
"react-toastify": "^9" whose peerDependencies exclude React 19; update the
"react-toastify" entry in web/classic/package.json to a version that declares
React 19 compatibility (bump to the latest react-19-compatible release, e.g., a
10.x or the current stable that lists react >=19 in its peer range), then
reinstall/update the lockfile (npm/yarn/pnpm) and run the app/tests to ensure no
runtime warnings; also verify peerDependencies for "react-toastify" after
install to confirm React 19 is accepted.

In `@web/classic/rsbuild.config.ts`:
- Around line 37-41: The build config currently injects only
import.meta.env.VITE_REACT_APP_SERVER_URL via the define object in
rsbuild.config.ts so the client bundle won't have VITE_REACT_APP_VERSION
available; add import.meta.env.VITE_REACT_APP_VERSION to the same define map
(using JSON.stringify(process.env.VITE_REACT_APP_VERSION || '') or the same
version source used by performance.buildCache.cacheDigest) so the browser can
read import.meta.env.VITE_REACT_APP_VERSION at runtime; update the define block
that currently references 'import.meta.env.VITE_REACT_APP_SERVER_URL' to also
include 'import.meta.env.VITE_REACT_APP_VERSION'.

---

Nitpick comments:
In `@web/classic/rsbuild.config.ts`:
- Around line 77-100: The SWC rule that matches test: /src[\\/].*\.js$/ (the
rule using loader 'builtin:swc-loader' with jsc.parser.jsx and react refresh
settings) can accidentally process dependency source under node_modules; update
that rule to add an exclude for node_modules (e.g., exclude: /node_modules/) so
only first-party files under src are handled by this SWC loader and third-party
packages are left untouched.
- Around line 9-12: The current semiUiDir calculation is fragile because it
assumes require.resolve('`@douyinfe/semi-ui`') points two levels below the package
root; change it to resolve the package root via
require.resolve('`@douyinfe/semi-ui/package.json`') and use path.dirname on that
result to get the package directory. Specifically, replace usage of
require.resolve('`@douyinfe/semi-ui`') when computing semiUiDir with
require.resolve('`@douyinfe/semi-ui/package.json`') and derive semiUiDir from
path.dirname(packageJsonPath) so downstream references (e.g., to
dist/css/semi.css) remain correct even if the package's main/exports layout
changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c6d04a08-736c-4280-ac7a-0c283eff143d

📥 Commits

Reviewing files that changed from the base of the PR and between 9a2e60d and 6436f2e.

⛔ Files ignored due to path filters (1)
  • web/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • .github/workflows/release.yml
  • Dockerfile
  • makefile
  • web/classic/index.html
  • web/classic/package.json
  • web/classic/rsbuild.config.ts
  • web/classic/src/components/auth/LoginForm.jsx
  • web/classic/src/components/auth/PasswordResetConfirm.jsx
  • web/classic/src/components/auth/PasswordResetForm.jsx
  • web/classic/src/components/auth/RegisterForm.jsx
  • web/classic/src/components/common/DocumentRenderer/index.jsx
  • web/classic/src/components/layout/PageLayout.jsx
  • web/classic/src/constants/index.js
  • web/classic/src/helpers/render.jsx
  • web/classic/src/helpers/utils.jsx
  • web/classic/src/index.css
  • web/classic/src/pages/About/index.jsx
  • web/classic/src/pages/Forbidden/index.jsx
  • web/classic/src/pages/Home/index.jsx
  • web/classic/src/pages/NotFound/index.jsx
  • web/classic/vite.config.js
  • web/default/rsbuild.config.ts
💤 Files with no reviewable changes (2)
  • web/classic/index.html
  • web/classic/vite.config.js

Comment thread web/classic/package.json
Comment on lines +24 to +25
"react": "^19.2.6",
"react-dom": "^19.2.6",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find React 19 removed/changed API usage in the classic app
rg -nP --type=js -g 'web/classic/**' '\bReactDOM\.(render|hydrate)\b|\bunmountComponentAtNode\b|\bfindDOMNode\b'
rg -nP -g 'web/classic/**/*.jsx' '\b(propTypes|defaultProps)\b'
# String refs (ref="...")
rg -nP -g 'web/classic/**/*.jsx' 'ref="[^"]+"'
# Inspect peer ranges of the pinned libs
fd -t f 'package.json' -p node_modules/react-toastify node_modules/react-i18next node_modules/react-router-dom 2>/dev/null | xargs -I{} sh -c 'echo "== {} =="; jq ".name, .version, .peerDependencies" {}'

Repository: QuantumNous/new-api

Length of output: 449


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Search for removed/changed ReactDOM APIs across JS/TS/JSX/TSX
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' '\bReactDOM\.(render|hydrate)\b|\bunmountComponentAtNode\b|\bfindDOMNode\b' web/classic || true

# 2) Search for propTypes/defaultProps usage across relevant source types
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' '\b(propTypes|defaultProps)\b' web/classic || true

# 3) Search for legacy string refs (ref="...")
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' 'ref="[^"]+"' web/classic || true

# 4) Check if react-test-renderer is used anywhere in classic app
rg -nP 'react-test-renderer' web/classic || true

# 5) Inspect the exact locations reported by initial rg for propTypes assignments
for f in \
  web/classic/src/components/common/ui/CompactModeToggle.jsx \
  web/classic/src/components/common/ui/CardTable.jsx \
  web/classic/src/components/common/ui/CardPro.jsx \
  web/classic/src/components/playground/CodeViewer.jsx
do
  echo "==== $f (around propTypes line) ===="
  # extract a small window around any ".propTypes" assignment and the component definition
  rg -n --fixed-string ".propTypes" "$f" || true
  # show 40 lines around the first ".propTypes" occurrence
  ln="$(rg -n --fixed-string ".propTypes" "$f" | head -n1 | cut -d: -f1 || true)"
  if [ -n "${ln:-}" ]; then
    start=$((ln-20)); end=$((ln+40))
    sed -n "${start},${end}p" "$f"
  fi
done

Repository: QuantumNous/new-api

Length of output: 4399


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Search for removed/changed ReactDOM APIs across JS/TS/JSX/TSX
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' '\bReactDOM\.(render|hydrate)\b|\bunmountComponentAtNode\b|\bfindDOMNode\b' web/classic || true

# 2) Search for propTypes/defaultProps usage across relevant source types
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' '\b(propTypes|defaultProps)\b' web/classic || true

# 3) Search for legacy string refs (ref="...")
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' 'ref="[^"]+"' web/classic || true

# 4) Check if react-test-renderer is used anywhere in classic app
rg -nP 'react-test-renderer' web/classic || true

# 5) Inspect the exact locations reported by initial rg for propTypes assignments
for f in \
  web/classic/src/components/common/ui/CompactModeToggle.jsx \
  web/classic/src/components/common/ui/CardTable.jsx \
  web/classic/src/components/common/ui/CardPro.jsx \
  web/classic/src/components/playground/CodeViewer.jsx
do
  echo "==== $f (around propTypes line) ===="
  rg -n --fixed-string ".propTypes" "$f" || true
  ln="$(rg -n --fixed-string ".propTypes" "$f" | head -n1 | cut -d: -f1 || true)"
  if [ -n "${ln:-}" ]; then
    start=$((ln-20)); end=$((ln+40))
    sed -n "${start},${end}p" "$f"
  else
    # for CodeViewer, show around the first appearance of "propTypes" token (if any)
    rg -n '\bpropTypes\b|\bdefaultProps\b' "$f" || true
    tokln="$(rg -n '\bpropTypes\b|\bdefaultProps\b' "$f" | head -n1 | cut -d: -f1 || true)"
    if [ -n "${tokln:-}" ]; then
      start=$((tokln-20)); end=$((tokln+40))
      sed -n "${start},${end}p" "$f"
    fi
  fi
done

Repository: QuantumNous/new-api

Length of output: 6762


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search React 19 legacy/removed APIs across classic source (JS/JSX/TS/TSX)
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' '\bReactDOM\.(render|hydrate)\b|\bunmountComponentAtNode\b|\bfindDOMNode\b' web/classic || true

# String refs (legacy) across classic source
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' 'ref="[^"]+"' web/classic || true

# defaultProps usage across classic source
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' '\bdefaultProps\b' web/classic || true

# react-test-renderer usage
rg -nP 'react-test-renderer' web/classic || true

# Re-run propTypes/defaultProps token match to confirm CodeViewer false positive
rg -nP -g 'web/classic/**/*.{js,jsx,ts,tsx}' '\b(propTypes|defaultProps)\b' web/classic || true

Repository: QuantumNous/new-api

Length of output: 449


🌐 Web query:

react-toastify@9 peerDependencies react

💡 Result:

For react-toastify version 9, the peer dependency requirement for React is "^16.8 || ^17.0 || ^18.0" [1][2][3]. While version 9 supported React 18, it does not officially include support for React 19 in its peer dependency range [1][3]. If you encounter dependency resolution errors when using this version in newer environments, common workarounds include using the --legacy-peer-deps flag with npm or installing the latest version of react-toastify (which supports React 18 and 19) [1][4].

Citations:


🌐 Web query:

react-i18next@13 peerDependencies react

💡 Result:

react-i18next@13 declares a peer dependency on React requiring react >= 16.8.0.[1] Concretely, the npm registry page for react-i18next lists these peer dependencies: i18next >= 26.2.0 and react >= 16.8.0.[1] Note: If you’re using react-i18next in a Next.js integration (next-i18next) at/around its v13, that project documents that i18next and react-i18next were moved to peerDependencies and you should install them as part of next-i18next’s dependencies.[2]

Citations:


🌐 Web query:

react-router-dom@6.3.0 peerDependencies react

💡 Result:

react-router-dom@6.3.0’s peer dependency on React is: react: ">=16.8" [1]. In addition, react-router-dom@6.3.0 declares a peer dependency on react-router-dom itself doesn’t apply here; rather, it has a peerDependencies block that includes React with the constraint ">=16.8" [1].

Citations:


React 19 upgrade: app code is clean of legacy ReactDOM/string-ref APIs, but react-toastify@^9 peer range excludes React 19.

  • web/classic has no ReactDOM.render/hydrate, unmountComponentAtNode, findDOMNode, legacy ref="..." string refs, defaultProps, or react-test-renderer usage. Existing *.propTypes assignments are on function components (e.g., CompactModeToggle, CardTable, CardPro), so React 19 will ignore them (no runtime break, but propTypes validation won’t run).
  • react-toastify@^9 declares React peer support only for ^16.8 || ^17.0 || ^18.0, so React 19 will trigger peer incompatibility (warnings or install failures depending on package manager). Upgrade react-toastify to a React-19-compatible version/range.
  • react-i18next@13 and react-router-dom@6.3.0 peer ranges allow react >= 16.8, so they shouldn’t block React 19.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/classic/package.json` around lines 24 - 25, The project is upgrading to
React 19 but package.json lists "react-toastify": "^9" whose peerDependencies
exclude React 19; update the "react-toastify" entry in web/classic/package.json
to a version that declares React 19 compatibility (bump to the latest
react-19-compatible release, e.g., a 10.x or the current stable that lists react
>=19 in its peer range), then reinstall/update the lockfile (npm/yarn/pnpm) and
run the app/tests to ensure no runtime warnings; also verify peerDependencies
for "react-toastify" after install to confirm React 19 is accepted.

Comment on lines +37 to +41
define: {
'import.meta.env.VITE_REACT_APP_SERVER_URL': JSON.stringify(
clientServerUrl,
),
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the classic app reads the version env var
rg -nP -g 'web/classic/**' 'VITE_REACT_APP_VERSION'

Repository: QuantumNous/new-api

Length of output: 155


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant parts of rsbuild.config.ts (define + env/cacheDigest usage)
nl -ba web/classic/rsbuild.config.ts | sed -n '1,120p'

# Repo-wide where VITE_REACT_APP_VERSION is referenced
rg -n --hidden -S 'VITE_REACT_APP_VERSION' .

Repository: QuantumNous/new-api

Length of output: 106


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show rsbuild.config.ts around define and cacheDigest usage
sed -n '1,120p' web/classic/rsbuild.config.ts

# Find all uses of VITE_REACT_APP_VERSION across the repo
rg -n --hidden -S 'VITE_REACT_APP_VERSION' .

Repository: QuantumNous/new-api

Length of output: 4288


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where the UI reads import.meta.env.VITE_REACT_APP_VERSION
rg -n --hidden -S 'import\.meta\.env\.VITE_REACT_APP_VERSION' web/classic web/default || true

# Compare define blocks between classic and default rsbuild configs
rg -n --hidden -S "source: \\{|define:" web/classic/rsbuild.config.ts web/default/rsbuild.config.ts
sed -n '1,120p' web/default/rsbuild.config.ts

Repository: QuantumNous/new-api

Length of output: 3312


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Any runtime reads of import.meta.env.VITE_REACT_APP_VERSION
rg -n --hidden -S 'import\.meta\.env\.VITE_REACT_APP_VERSION' . || true

# Any reads of VITE_REACT_APP_VERSION in classic code
rg -n --hidden -S 'VITE_REACT_APP_VERSION' web/classic || true

# Inspect default build-metadata.ts to understand how version is used
sed -n '1,120p' web/default/src/lib/build-metadata.ts

Repository: QuantumNous/new-api

Length of output: 4060


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Where classic uses build-metadata/installBuildMetadata
rg -n --hidden -S 'installBuildMetadata' web/classic web/default || true

# Does classic have build-metadata.ts (or similar) that reads import.meta.env.VITE_REACT_APP_VERSION?
fd -t f 'build-metadata.*' web/classic web/default || true

# Confirm whether classic code references VITE_REACT_APP_VERSION via import.meta.env anywhere else
rg -n --hidden -S 'import\.meta\.env\.VITE_REACT_APP_VERSION' web/classic || true

# Same for default to see intended behavior
rg -n --hidden -S 'import\.meta\.env\.VITE_REACT_APP_VERSION' web/default || true

Repository: QuantumNous/new-api

Length of output: 328


🌐 Web query:

Rsbuild import.meta.env automatic injection VITE_ variables source.define behavior loadEnv prefixes

💡 Result:

In Rsbuild, environment variables are not automatically injected into the client code in the same way they are in Vite [1]. While Rsbuild loads variables from .env files into process.env at build time, it requires explicit configuration to expose them to the browser via import.meta.env [2][3][4]. Key mechanisms and behaviors: 1. Automatic Injection: By default, Rsbuild injects a limited set of internal environment variables into import.meta.env, including MODE, DEV, PROD, BASE_URL, and ASSET_PREFIX [2][5][6]. Unlike Vite, it does not automatically expose variables prefixed with VITE_ [1]. By default, Rsbuild looks for variables prefixed with PUBLIC_ [1][7]. 2. source.define and loadEnv: Rsbuild uses the source.define configuration to replace global identifiers with specific values or expressions at compile time [2][8]. To expose custom environment variables to your client-side code, you must manually pass them to source.define [2][1]. The loadEnv utility is the standard way to retrieve these variables [7][9]. It parses .env files and returns a publicVars object containing the mapping required by source.define [7][9][10]. 3. Matching Vite Behavior: To replicate Vite's default behavior (automatically exposing VITE_ variables), you can configure loadEnv with the prefixes option in your rsbuild.config.ts [1][7]: import { defineConfig, loadEnv } from '@rsbuild/core'; // Load variables starting with VITE_ const { publicVars } = loadEnv({ prefixes: ['VITE_'] }); export default defineConfig({ source: { define: publicVars, }, }); This configuration ensures that variables like VITE_API_URL are available in your source code via import.meta.env.VITE_API_URL and process.env.VITE_API_URL [2][7]. Without this manual step, those variables remain restricted to the Node.js process and are not bundled into the client-side code [2][9].

Citations:


Expose VITE_REACT_APP_VERSION in web/classic client bundle

web/classic/rsbuild.config.ts only injects import.meta.env.VITE_REACT_APP_SERVER_URL via source.define; VITE_REACT_APP_VERSION is only used for performance.buildCache.cacheDigest, so it won’t be available as import.meta.env.VITE_REACT_APP_VERSION in the browser (Rsbuild doesn’t auto-expose VITE_ vars like Vite does).

🐛 Add the version to define
       define: {
         'import.meta.env.VITE_REACT_APP_SERVER_URL': JSON.stringify(
           clientServerUrl,
         ),
+        'import.meta.env.VITE_REACT_APP_VERSION': JSON.stringify(
+          process.env.VITE_REACT_APP_VERSION || '',
+        ),
       },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
define: {
'import.meta.env.VITE_REACT_APP_SERVER_URL': JSON.stringify(
clientServerUrl,
),
},
define: {
'import.meta.env.VITE_REACT_APP_SERVER_URL': JSON.stringify(
clientServerUrl,
),
'import.meta.env.VITE_REACT_APP_VERSION': JSON.stringify(
process.env.VITE_REACT_APP_VERSION || '',
),
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/classic/rsbuild.config.ts` around lines 37 - 41, The build config
currently injects only import.meta.env.VITE_REACT_APP_SERVER_URL via the define
object in rsbuild.config.ts so the client bundle won't have
VITE_REACT_APP_VERSION available; add import.meta.env.VITE_REACT_APP_VERSION to
the same define map (using JSON.stringify(process.env.VITE_REACT_APP_VERSION ||
'') or the same version source used by performance.buildCache.cacheDigest) so
the browser can read import.meta.env.VITE_REACT_APP_VERSION at runtime; update
the define block that currently references
'import.meta.env.VITE_REACT_APP_SERVER_URL' to also include
'import.meta.env.VITE_REACT_APP_VERSION'.

- migrate the classic frontend from Vite to Rsbuild with JSX, Semi UI, proxy, and production build config.
- update make dev-web to run both default and classic frontends for local theme switching.
- fix classic public page height, footer, CORS proxy, error handling, and constant export warnings.
- update Dockerfile and release workflow to install from the web workspace root with the shared lockfile.
@QuentinHsu
QuentinHsu force-pushed the feat/classic-rsbuild-dev-workflow branch from 6436f2e to 1e9ff8a Compare June 1, 2026 16:32
@t0ng7u
t0ng7u merged commit 0ff9c35 into main Jun 2, 2026
1 check passed
SamuelSxy pushed a commit to SamuelSxy/new-api-rh that referenced this pull request Jun 7, 2026
Merge pull request QuantumNous#5232 from QuantumNous/feat/classic-rsbuild-dev-workflow
@Calcium-Ion
Calcium-Ion deleted the feat/classic-rsbuild-dev-workflow branch June 13, 2026 08:34
OuYang-HX pushed a commit to OuYang-HX/new-api that referenced this pull request Jun 13, 2026
Merge pull request QuantumNous#5232 from QuantumNous/feat/classic-rsbuild-dev-workflow
@coderabbitai coderabbitai Bot mentioned this pull request Jun 29, 2026
11 tasks
330079598 pushed a commit to 330079598/new-api that referenced this pull request Aug 19, 2026
Merge pull request QuantumNous#5232 from QuantumNous/feat/classic-rsbuild-dev-workflow
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants