This guide is for the architect, tech lead, or platform engineer deciding whether and how to adopt Ant Design Pro as the foundation for an enterprise web application — and for the developers who will operate, extend, and harden it. It documents the architecture, the complete configuration surface, the request/permission/i18n internals, the demo backend, deployment, security considerations, and the improvements worth making before production.
Where the User Guide shows you how to use the template, this guide explains how it is built and how to make it production-grade.
Table of Contents
- Executive Summary
- Architecture
- Technology Stack
- Requirements
- Repository Structure
- Configuration Mastery
- The Runtime Layer (
src/app.tsx) - Request & Error Handling
- Access Control & Permissions
- Internationalization Internals
- The API Contract & Code Generation
- The Demo Backend (Cloudflare Worker)
- Mock System
- Security Analysis
- Build & Tooling
- Deployment
- Testing Strategy
- Operations & Maintenance
- Code Quality & Conventions
- Potential Improvements
- Quick Reference
1. Executive Summary
Ant Design Pro is an out-of-the-box UI solution for enterprise applications, distributed as a React boilerplate rather than an installable library. It is maintained by the Ant Design team as the canonical "starter" for building admin consoles, internal tools, and data dashboards on the Ant Design ecosystem.
What it provides on day one:
- A configurable application shell (ProLayout) with sidebar/top/mixed navigation, theme switching, and a settings drawer.
- Authentication and route-level access control, pre-wired.
- A dozen production-shaped page templates (dashboards, forms, CRUD tables, lists, profiles, results, exceptions, account pages) and a new AI chat page.
- Internationalization across eight locales.
- A mock-data system and a standalone demo backend, so the UI runs with zero backend setup.
- An OpenAPI-driven code generator for the API service layer.
- A modern toolchain: Vitest, Biome, and the utoopack (Turbopack-based) bundler.
What it is not: a backend, an authentication system, or a finished product. The bundled login and permissions are demonstrations. Adopting Pro means inheriting a well-structured frontend foundation and then supplying your own API, auth, and business logic.
Version under analysis: 6.0.2 (v6 line) — a substantial modernization featuring React 19, antd 6, UmiJS Max 4, Tailwind CSS v4, React Query, Biome, and the Ant Design X AI components.
Note
The single most important architectural fact: almost all behavior is framework configuration, not bespoke code. The menu, routing, login redirect, request handling, permission checks, and i18n are UmiJS Max plugin features driven by
config/config.ts. Understanding Max is understanding Pro.
2. Architecture
Ant Design Pro is a single-page application compiled to static assets. There is no application server in the product itself — the "backend" in this repository is a demo only.
High-level component diagram
┌──────────────────────────────────────────────────────────────────┐
│ Browser (SPA) │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ UmiJS Max runtime │ │
│ │ ├─ Router (config/routes.ts → code-split pages) │ │
│ │ ├─ Layout plugin → ProLayout shell (sidebar/header) │ │
│ │ ├─ Access plugin → src/access.ts (canAdmin, ...) │ │
│ │ ├─ Initial State → src/app.tsx getInitialState() │ │
│ │ ├─ Request plugin (axios) → src/requestErrorConfig.ts │ │
│ │ ├─ React Query → server-state cache │ │
│ │ ├─ Locale plugin → src/locales/* (8 languages) │ │
│ │ └─ Model plugin → src/models/* (useModel global state) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ Pages (src/pages/*) ←uses→ Services (src/services/*) │
│ │ │ │
└────────┼──────────────────────────────┼───────────────────────────┘
│ /api/* (HTTP) │
▼ ▼
┌─────────────────┐ ┌──────────────────────────────┐
│ Dev: mock/* │ OR │ Dev proxy → your backend │
│ & **/_mock.ts │ │ (config/proxy.ts) │
└─────────────────┘ └──────────────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Demo backend (cloudflare-worker/)│
│ Hono app, ~33 routes, fake data │
│ pro-api.ant-design-demo.workers │
└──────────────────────────────────┘
Request lifecycle
- A page component calls a typed function in
src/services/ant-design-pro/(e.g.rule(params)). - That function calls UmiJS Max's
request(axios under the hood), which applies the config insrc/app.tsx(baseURL) and the interceptors/error handlers insrc/requestErrorConfig.ts. - In development with mocks, the request is answered locally; without mocks it goes through the
config/proxy.tsproxy to a real backend. - Responses follow a
{ success, data, errorCode?, errorMessage?, showType? }envelope; the error handler mapsshowTypeto a UI affordance (silent / warning / error message / notification / redirect). - For cached server state, pages wrap calls in React Query (
useQuery/useMutation).
Startup & auth gate
On boot, getInitialState() (in src/app.tsx) fetches the current user unless the route is a public auth page (/user/login, /user/register, /user/register-result). The result populates global state. The layout's onPageChange and the route access rules then gate navigation: an unauthenticated user is redirected to /user/login?redirect=<original-path>.
Important
The architecture cleanly separates framework concerns (routing, layout, request, access, i18n — all in
config/andsrc/app.tsx) from business concerns (pages and services). When you adopt Pro, you mostly touch the latter. This separation is what makes the bundled/pro-upgradeskill able to merge framework updates without clobbering your code.
3. Technology Stack
| Layer | Technology | Version (declared) | Role |
|---|---|---|---|
| UI library | React | ^19.2.5 |
Component runtime. |
| Framework | UmiJS Max (@umijs/max) |
^4.6.64 |
Routing, data flow, request, access, layout, i18n. |
| Component kit | antd | ^6.4.3 |
Core Ant Design components. |
| Pro components | @ant-design/pro-components |
^3.1.12 |
High-level templates: ProLayout, ProTable, ProForm, etc. |
| Charts | @ant-design/plots |
^2.6.8 |
Dashboard visualizations. |
| Maps | d3 + topojson-client |
^7.9.0 / ^3.1.0 |
Monitor-page geographic map. |
| AI components | @ant-design/x, x-sdk, x-markdown |
^2.8.0 |
The AI Assistant chat page. |
| Server state | @tanstack/react-query |
^5.101.0 |
Caching, mutations, invalidation. |
| Styling | Tailwind CSS v4 + antd-style + CSS Modules | ^4.3.0 / ^4.1.0 |
Layered styling strategy. |
| Dates | dayjs | ^1.11.20 |
Replaces moment (via the moment2dayjs plugin). |
| Bundler | utoopack (@utoo/pack) |
via @umijs/max |
Turbopack-based, Webpack-compatible build. |
| Lint/format | Biome | ^2.5.0 |
Single tool replacing ESLint + Prettier. |
| Tests | Vitest | 4.1.8 |
Unit/component tests (happy-dom). |
| API codegen | @umijs/max-plugin-openapi |
^2.0.3 |
Generates services from OpenAPI. |
| Demo backend | Hono | ^4.6.0 |
Cloudflare Worker mock API. |
Note
The v6 upgrade was a deliberate "state of the art" refresh: class → functional components, moment → dayjs, Less → Tailwind/antd-style, useRequest → React Query, ESLint/Prettier → Biome, and Webpack → utoopack. If you're migrating from a v5 Pro project, budget for all of these shifts.
4. Requirements
| Requirement | Value | Source |
|---|---|---|
| Node.js | >= 22.0.0 |
package.json engines.node |
| Package manager | npm / pnpm / yarn | — |
| Build output | Static files (dist/) |
max build |
| Hosting | Any static host or CDN | SPA; needs SPA fallback routing |
| Browsers | Modern (browserslist: ["defaults"]) |
No IE support |
Warning
Because the app is a client-routed SPA, your static host must fall back unknown paths to
index.html(so deep links like/dashboard/analysiswork on refresh). On Nginx usetry_files $uri /index.html;; on object stores enable single-page-application fallback. Without it, refreshing a sub-route returns a 404 from the host.
5. Repository Structure
ant-design-pro/
├── config/ # UmiJS Max build & framework configuration
│ ├── config.ts # Main config — enables every Max plugin
│ ├── routes.ts # Route table (the feature/menu map)
│ ├── routes.simple.ts # Minimal route table (used by `npm run simple`)
│ ├── defaultSettings.ts # ProLayout look & feel
│ ├── proxy.ts # Dev-server proxy targets (per UMI_ENV)
│ ├── oneapi.json # OpenAPI 3.0 contract → drives codegen
│ └── md-raw-loader.cjs # Loader to import .md as raw strings
├── mock/ # Global mock endpoints (auto-registered)
├── cloudflare-worker/ # Standalone demo backend (Hono)
│ ├── src/index.ts # App entry, CORS, route mounting
│ ├── src/routes/*.ts # Route groups (user, table, dashboard, ...)
│ ├── src/data/*.ts # Fake data generators
│ └── wrangler.toml # Cloudflare deploy config
├── src/
│ ├── app.tsx # Runtime config: getInitialState, layout, request, rootContainer
│ ├── access.ts # Permission flags (canAdmin, ...)
│ ├── requestErrorConfig.ts# Request/response interceptors + error mapping
│ ├── global.tsx / .less / .style.ts # Global styles & Tailwind entry
│ ├── service-worker.js # PWA service worker (Workbox)
│ ├── manifest.json # PWA manifest
│ ├── components/ # Shared components (layout + business)
│ ├── locales/ # i18n — 8 locales × 7 files each
│ ├── pages/ # Page templates (the demos)
│ ├── services/ # API client layer (generated + handwritten)
│ └── utils/ # Utilities (e.g. format.ts)
├── docs/ # Project docs (cheatsheet.en-US.md / zh-CN.md, roadmap)
├── tests/ # Test setup & mocks
├── types/ # Ambient type declarations
├── biome.json # Biome lint/format config
├── tailwind.config.js # Tailwind content globs
├── vitest.config.ts # Vitest config (happy-dom, aliases)
└── package.json
Tip
Two directories carry almost all the framework wiring:
config/(build-time) and the three runtime filessrc/app.tsx,src/access.ts,src/requestErrorConfig.ts. Read those five files and you understand the whole application skeleton.
6. Configuration Mastery
config/config.ts — the plugin enable-map
This file is the heart of the build. It calls defineConfig({...}) and turns on every UmiJS Max feature the template uses. Each key is a plugin or a core option.
| Key | Purpose | Notes |
|---|---|---|
hash: true |
Filename hashing for cache-busting | Recommended for production deploys. |
publicPath: '/' |
Base path for assets | Change for sub-path deploys. |
routes |
The route table | Imported from config/routes.ts. |
ignoreMomentLocale: true |
Drop moment locale data | Smaller bundle (moment is replaced by dayjs anyway). |
proxy |
Dev proxy | Selected by UMI_ENV from config/proxy.ts. |
fastRefresh: true |
React Fast Refresh | State-preserving HMR. |
routePrefetch: {} |
Prefetch route chunks | Faster navigation. |
manifest: {} |
Emit an asset manifest | Pairs with prefetch. |
model: {} |
Data-flow plugin | Enables src/models/* + useModel. |
initialState: {} |
Global initial state | Powers getInitialState in app.tsx. |
title: 'Ant Design Pro' |
App title | Header + document title. |
layout: { locale: true, ...defaultSettings } |
ProLayout | Merges defaultSettings.ts. |
moment2dayjs |
Replace moment with dayjs | Preset antd, plus duration/relativeTime plugins. |
locale |
i18n | default: 'zh-CN', antd: true, baseNavigator: true. |
antd |
antd integration | configProvider sets variant filled and a custom font token. |
request: {} |
Unified request | axios + useRequest; configured in app.tsx. |
reactQuery: {} |
React Query plugin | Provides the QueryClient. |
access: {} |
Permission plugin | Reads src/access.ts; requires initialState. |
analytics: { ga_v2: 'G-...' } |
Google Analytics 4 | Replace or remove the GA tag for your own site. |
headScripts |
Extra <head> scripts |
Ships a loading.js to avoid first-paint blank screen. |
plugins |
Extra plugins | @umijs/max-plugin-openapi, @umijs/request-record. |
openAPI |
OpenAPI codegen config | Reads config/oneapi.json; mock: false. |
tailwindcss: {} |
Tailwind v4 plugin | — |
mock |
Mock matching globs | Includes src/pages/**/_mock.ts. |
utoopack |
Bundler options | Custom *.md raw loader rule. |
requestRecord: {} |
Request recording | Used by npm run record. |
exportStatic: {} |
Static HTML export | Pre-renders routes for static hosting. |
define |
Build-time constants | Injects COMMIT_HASH, app/umi/utoo versions, CI. |
Caution
The config hard-codes a Google Analytics measurement ID (
analytics.ga_v2). Remove it or replace it with your own before deploying, or your traffic will report into the template's analytics property.
config/defaultSettings.ts — ProLayout appearance
The layout look & feel. See the User Guide for the per-field table. Key defaults: navTheme: 'light', colorPrimary: '#1677ff', layout: 'mix', contentWidth: 'Fluid', fixSiderbar: true.
config/proxy.ts — environment proxies
Exports proxy maps keyed by UMI_ENV (dev, test, pre). Each maps /api/ to a target with changeOrigin: true. The test environment points at the public demo Worker; dev is commented out (you fill it in); pre is a placeholder.
test: {
'/api/': {
target: 'https://pro-api.ant-design-demo.workers.dev',
changeOrigin: true,
},
},
Warning
Proxies apply only to the dev server. They are absent from production builds. This is the single most common source of "works locally, 404s in prod" confusion. In production, route
/api/*at your infrastructure layer or set an absoluterequest.baseURL.
Environment variables
A frontend scaffold has very few runtime env vars. The ones present:
| Variable | Where | Purpose |
|---|---|---|
UMI_ENV |
start scripts | Selects the proxy/config profile (dev/test/pre). |
MOCK |
start scripts | MOCK=none disables mock data. |
NODE_ENV |
src/app.tsx |
development toggles dev-only behavior (dev API base URL, OpenAPI link). |
CHAT_API_URL |
src/pages/chatbot/service.ts |
Override the AI chat model endpoint. |
COMMIT_HASH / CF_PAGES_COMMIT_SHA |
config/config.ts |
Commit stamp; falls back to git rev-parse HEAD at build time. |
CI |
config/config.ts |
Build-environment flag. |
ANALYZE |
analyze script |
Enables bundle analysis. |
7. The Runtime Layer (src/app.tsx)
src/app.tsx is UmiJS Max's runtime configuration file — it exports specially-named members that the framework wires in at runtime.
| Export | Type | Responsibility |
|---|---|---|
getInitialState() |
async function | Fetch global startup data (the current user) and seed settings. Skips the fetch on auth pages. On fetch failure, redirects to login with a redirect param. |
layout |
RunTimeLayoutConfig |
Configures ProLayout: menu item rendering (with prefetch links), header actions (doc link, version dropdown, language dropdown), avatar dropdown, footer, the per-page auth check (onPageChange), background images, and the Setting Drawer. Replaces ProLayout's default ErrorBoundary with an offline-aware one. |
request |
RequestConfig |
Sets baseURL (empty in dev so the proxy/mock handles it; the demo Worker URL in production) and spreads in errorConfig. |
rootContainer |
function | Wraps the whole app in <OfflineBanner> and <ErrorBoundary>. |
Note
getInitialStateruns once at startup. The user object it returns flows intosrc/access.ts(to compute permissions) and into the layout (to render the avatar and gate pages). This is the backbone of the auth experience — re-implementfetchUserInfoto call your real identity endpoint.
8. Request & Error Handling
src/requestErrorConfig.ts defines the unified request/response behavior. It centers on a response envelope and a showType enum that decides how errors surface to the user.
Response envelope:
interface ResponseStructure {
success: boolean;
data: unknown;
errorCode?: number;
errorMessage?: string;
showType?: ErrorShowType;
}
ErrorShowType → UI behavior:
showType |
Value | Behavior |
|---|---|---|
SILENT |
0 | Do nothing. |
WARN_MESSAGE |
1 | message.warning(...) toast. |
ERROR_MESSAGE |
2 | message.error(...) toast. |
NOTIFICATION |
3 | notification.open(...) panel. |
REDIRECT |
9 | Redirect to /user/login. |
The config has three parts:
errorThrower— whensuccessisfalse, throws a customBizErrorcarrying{ errorCode, errorMessage, showType, data }.errorHandler— catches errors: honorsopts.skipErrorHandler; mapsBizErrorbyshowType; handles raw axios errors (Response status:<code>), offline state (a localized "network unavailable" message), and missing-response cases.requestInterceptors— a single pass-through interceptor with a commented-out token-attachment example. This is where you addAuthorization: Bearer <token>.
Important
The token-attachment interceptor ships disabled (commented out). The demo never sends an auth header. To integrate real auth, uncomment and complete the interceptor to read your token (from memory, cookie, or storage) and attach it. The most-requested community feature — silent token refresh (#11550, #11869) — is implemented here too, by adding a 401 response interceptor that refreshes and retries.
9. Access Control & Permissions
Permissions are computed in src/access.ts, a single function that receives the initial state and returns a flag map:
export default function access(initialState: { currentUser?: API.CurrentUser } | undefined) {
const { currentUser } = initialState ?? {};
return {
canAdmin: currentUser && currentUser.access === 'admin',
};
}
The flags are consumed three ways:
- Route-level: add
access: 'canAdmin'to a route inconfig/routes.ts. Unauthorized routes are hidden from the menu and blocked. (The demo/adminroute uses this.) - Component-level (declarative):
<Access accessible={access.canAdmin}><AdminPanel/></Access>. - Component-level (imperative):
const access = useAccess(); if (access.canAdmin) {...}.
To add a permission, add a flag to the returned object (e.g. canUser: !!currentUser, canEditOrders: currentUser?.roles?.includes('order-editor')) and reference it in routes/components.
Note
Access flags are derived from the current user, which comes from your identity endpoint. This is purely a client-side convenience for UX (hiding menus, gating views). It is not a security boundary — every protected operation must also be authorized server-side. A determined user can call your API directly regardless of what the menu shows.
10. Internationalization Internals
The i18n system is the UmiJS Max locale plugin. Each locale is a directory under src/locales/<locale>/ plus an entry file src/locales/<locale>.ts. Strings are split by concern:
| File | Covers |
|---|---|
menu.ts |
Navigation menu labels (menu.<route-name>). |
pages.ts |
Page content strings. |
component.ts |
Shared component strings. |
globalHeader.ts |
Header/search/notifications. |
settings.ts / settingDrawer.ts |
Setting drawer labels. |
network.ts |
Network/error strings. |
Eight locales ship: zh-CN (default), zh-TW, en-US, ja-JP, pt-BR, id-ID, fa-IR, bn-BD. The language switcher (src/components/RightContent/index.tsx) maps each locale to a flag emoji and native label and only renders when more than one supported locale is present.
Tip
To trim bundle size for a single-language deployment, set
locale.defaultto your language, delete unused locale directories, and (optionally) runnpm run i18n-removeto inline strings and remove theFormattedMessage/useIntlwrappers entirely.
11. The API Contract & Code Generation
The service layer in src/services/ant-design-pro/ is generated from an OpenAPI document, not handwritten.
config/oneapi.jsonis an OpenAPI 3.0 spec describing the frontend's expected API:currentUser,login,outLogin,getFakeCaptcha,getNotices, andruleCRUD (GET/POST/PUT/DELETE /api/rule), plus the shared schemas (CurrentUser,LoginParams,LoginResult,RuleListItem,RuleList,NoticeIconItem,ErrorResponse, ...).- Running
npm run openapi(the@umijs/max-plugin-openapiplugin) regeneratessrc/services/ant-design-pro/api.ts,login.ts,index.ts, and thetypings.d.tsdeclare namespace API {...}types.
The generated functions are thin wrappers over request:
export async function rule(params: { current?: number; pageSize?: number }, options?) {
return request<API.RuleList>('/api/rule', { method: 'GET', params, ...(options || {}) });
}
Important
Files under
src/services/ant-design-pro/are auto-generated — never edit them by hand. To change the API surface, editconfig/oneapi.json(or pointschemaPathat your live OpenAPI endpoint) and runnpm run openapi. Hand edits are silently overwritten on the next generation. The generated types (API.*) are the canonical request/response types used throughout the pages.
12. The Demo Backend (Cloudflare Worker)
To make the live preview and test environment work without a real backend, the repo includes a standalone API under cloudflare-worker/ — a Hono app deployed as a Cloudflare Worker (pro-api.ant-design-demo.workers.dev). It is a separate package (pro-api, its own package.json) and is not part of your application build.
Entry (cloudflare-worker/src/index.ts): sets up CORS with an origin allowlist (utils/cors.ts), exposes /api/auth_routes, mounts ten route groups under /api, and returns a JSON 404 for unmatched paths.
Route groups (~33 endpoints total):
| Group | File | Representative endpoints |
|---|---|---|
| User/auth | routes/user.ts |
POST /api/login/account (always returns admin), POST /api/login/outLogin, GET /api/login/captcha, POST /api/register, GET /api/currentUser, GET /api/users |
| Table | routes/table.ts |
GET /api/rule (search/sort/filter/paginate), POST /api/rule (create/update/delete by method field) |
| Dashboard | routes/dashboard.ts |
GET /api/fake_analysis_chart_data, /fake_workplace_chart_data, /project/notice, /activities |
| List | routes/list.ts |
GET /api/get_list, POST /api/post_fake_list, /fake_list, /card_fake_list, /tags, ... |
| Monitor | routes/monitor.ts |
GET /api/monitor/tags, /map-geo, /map-grid |
| Geographic | routes/geographic.ts |
GET /api/geographic/province, /city/:province |
| Profile | routes/profile.ts |
GET /api/profile/basic, /advanced |
| Settings | routes/settings.ts |
GET /api/accountSettingCurrentUser |
| Notices | routes/notices.ts |
GET /api/notices |
| Errors | routes/errors.ts |
GET /api/401, /403, /404, /500 (status-code demos) |
Notable production-minded touches in the demo code: the list endpoints clamp the count query to [1, 100] to prevent memory exhaustion; the table endpoint validates JSON bodies and sorter/filter shapes, returning 400 on malformed input; CORS falls back to a safe default origin for disallowed origins.
Caution
The demo backend exists to make the UI runnable, not to be used as a real API. Its login grants admin to anyone, it stores no data persistently, and its responses are randomized/fake. Stand up your own backend and repoint
config/proxy.ts(dev) andrequest.baseURL(prod) at it.
13. Mock System
Independent of the Worker, the project supports in-process mocking handled by UmiJS:
- Global mocks:
mock/*.ts(e.g.mock/user.ts,mock/listTableList.ts,mock/notices.ts,mock/route.ts) — exported objects keyed by'METHOD /path'. - Page-level mocks:
src/pages/**/_mock.ts, matched by themock.includeglob inconfig/config.ts.
Mocks are active in dev mode unless MOCK=none. The data layer uses mockjs for realistic random data.
Tip
Mocks (
mock/+_mock.ts) and the Cloudflare Worker are two separate fake-backend mechanisms. Use mocks for local, offline UI work (thenpm startdefault). The Worker backs the hosted preview and thetestenvironment. You generally won't ship either — they're development scaffolding.
14. Security Analysis
Ant Design Pro is a frontend; its security surface is correspondingly narrow, but there are real items to address before production.
What's already handled
| Control | Where | Detail |
|---|---|---|
| Open-redirect protection | src/pages/user/login/index.tsx |
getSafeRedirectUrl rejects non-relative URLs, protocol-relative //host URLs, and cross-origin targets — only same-origin relative paths are honored after login. |
| Service-worker origin check | src/service-worker.js |
The message listener verifies event.origin === self.location.origin before acting, preventing cross-origin postMessage abuse. |
| Worker CORS allowlist | cloudflare-worker/src/utils/cors.ts |
The demo backend restricts allowed origins, with a safe default for disallowed ones. |
| Input clamping/validation | cloudflare-worker/src/routes/*.ts |
List counts clamped to [1,100]; JSON/sorter/filter validated with 400 on bad input. |
What you must add
Warning
The bundled authentication is a demo, not a security control. Before production:
- Implement real authentication. The mock login grants admin to everyone and the request interceptor that would attach an auth token is commented out (
src/requestErrorConfig.ts).- Enforce authorization server-side.
src/access.tsflags only hide UI; they do not protect data. Every privileged API call must be authorized on the server.- Choose secure token handling. Decide between httpOnly cookies (XSS-resistant) and in-memory/storage tokens, and implement refresh. The template leaves this to you.
- Remove demo endpoints and IDs. Drop the demo
request.baseURLpointing atworkers.dev, replace the hard-coded GA tag, and point the AI chat at your own gateway (not the public demo model).- Set security headers and CSP at your hosting/proxy layer (the SPA can't set its own response headers).
Dependency posture
The app pulls in a broad set of dependencies (charts, D3, AI components, React Query). Run npm audit regularly and keep antd/UmiJS Max current — the /pro-upgrade skill helps track template-level updates.
15. Build & Tooling
Bundler: utoopack
v6 builds with utoopack (@utoo/pack), a next-generation, Turbopack-based bundler that is Webpack-compatible. It's configured via the utoopack field in config/config.ts and supports module.rules for custom loaders (the template registers a raw loader for *.md so pages like Welcome can import Markdown as a string).
Lint & format: Biome
biome.json configures a single tool for both linting and formatting (replacing ESLint + Prettier). Highlights: single quotes, space indentation, classic JSX runtime, and a curated rule set with several a11y/correctness rules relaxed for this template. Generated and vendored paths (src/services, mock, dist, .umi*, node_modules) are excluded.
npm run lint # Biome lint + tsc --noEmit
npm run biome # auto-fix (format + lint)
Type checking
npm run tsc runs tsc --noEmit against a TypeScript ^6.0.3 toolchain. Type checking is part of npm run lint, so CI catches type regressions.
Note
Coverage (
codecov.yml) is informational only — it does not block PRs. Small fixes often ship without tests; dedicated test PRs raise coverage. Adopt your own gate if you need a hard coverage floor.
16. Deployment
The build is static, so deployment is "serve a folder," with two caveats: SPA fallback routing and publicPath.
Standard flow
npm run build # → dist/
# upload dist/ to your static host / CDN / bucket
Sub-path deploys
Set publicPath in config/config.ts to the sub-path (e.g. '/admin/') so hashed asset URLs resolve. The default is '/'.
GitHub Pages
npm run deploy builds and pushes dist/ to the gh-pages branch via the gh-pages package. A public/CNAME is present for custom-domain Pages hosting.
PWA
The repo ships a Workbox service worker (src/service-worker.js) and a web app manifest (src/manifest.json, with icons). The service worker uses a network-first strategy for /api/* and selected CDN assets, and an origin-checked skip-waiting handshake.
Important
Configure SPA fallback on your host (route unknown paths to
index.html) or client-side deep links will 404 on refresh. For Cloudflare Pages, enable single-page-application not-found handling; for Nginx, usetry_files $uri $uri/ /index.html;.
Production checklist
- [ ] Set
request.baseURL(or same-origin/api) to your real backend insrc/app.tsx. - [ ] Implement real auth and uncomment/complete the token interceptor.
- [ ] Replace or remove the Google Analytics ID in
config/config.ts. - [ ] Repoint or remove the AI chat endpoint (
CHAT_API_URL). - [ ] Set
publicPathif deploying under a sub-path. - [ ] Configure SPA fallback routing on the host.
- [ ] Add security headers / CSP at the proxy/CDN.
- [ ] Run
npm run lint && npm run buildclean.
17. Testing Strategy
Tests use Vitest with the happy-dom environment and Testing Library.
| Aspect | Detail |
|---|---|
| Runner | Vitest 4.1.8 (npm test / :coverage / :watch / :ui). |
| Environment | happy-dom, globals enabled, tests/setupTests.ts as setup. |
| Match | src/**/*.{test,spec}.{ts,tsx}. |
| Coverage | v8 provider; excludes .umi, generated services, *.d.ts, *.style.ts. |
| Aliases | @ → src, @@ → src/.umi, @root → repo root. |
Representative existing tests: src/access.test.ts (permission logic), src/app.test.tsx (getInitialState redirect-on-401 behavior), src/requestErrorConfig.test.ts (every showType branch and axios/offline error paths), and src/pages/table-list/index.test.tsx (ProTable rendering and the rule API call).
Note
One Umi-integration test (
src/pages/user/login/login.test.tsx) is excluded from Vitest because it depends on Umi's own Jest infrastructure. A migration from Jest to Vitest is in progress (#11823); if you adopt the template, standardize on Vitest for new tests.
18. Operations & Maintenance
Because there's no server runtime in the product, "operations" is mostly about CI, upgrades, and keeping the static deploy healthy.
| Task | How |
|---|---|
| Local dev | npm start (mock) or npm run dev (proxied backend). |
| CI gate | npm run lint && npm test && npm run build. |
| Upgrade the template | npx skills add ant-design/ant-design-pro then /pro-upgrade in Claude Code — diffs the latest template and merges framework changes while preserving business code. |
| Regenerate API client | Edit config/oneapi.json, run npm run openapi. |
| Bundle analysis | npm run analyze. |
| Reset a broken dev server | rm -rf src/.umi && npm start. |
| Deploy the demo backend | cd cloudflare-worker && npm run deploy (Wrangler) — only if you want your own demo API. |
Built-in AI skills
The repo ships two Claude Code skills under .claude/skills/:
/pro-upgrade— clones the latest template, classifies framework vs. business files, merges dependency/config/code-pattern updates, runsnpx antd lint, and verifies withnpm run lint && npm run build./antd— queries antd component APIs, props, tokens, and demos; lints for deprecated usage; assists version migrations — via@ant-design/cliwith offline metadata.
19. Code Quality & Conventions
| Convention | Rule |
|---|---|
| Generated code | src/services/ant-design-pro/ is generated — never edit by hand; change oneapi.json and regenerate. |
| Commits | Conventional Commits enforced via commitlint + Husky (feat:, fix:, chore:, ...). |
| Lint/format | Biome only — do not add ESLint or Prettier. npx antd lint ./src should pass clean. |
| Styling priority | Tailwind (layout) → antd-style (theme tokens) → CSS Modules (component) → Less (legacy global only). |
| Path aliases | @/* → src/*; @@/* → src/.umi/* (Umi temp). |
| Mock priority | mock/ for global, src/pages/**/_mock.ts for page-level; both auto-registered. |
| Components | Functional components throughout (class components removed in v6). |
| Temp dir | src/.umi is generated; never commit it. Delete + restart if behavior is odd. |
Note
Negative knowledge — things that do NOT exist here, so don't look for them: there is no application server in the product (the Worker is a separate demo); no runtime database or ORM; no environment-variable-driven app config beyond the handful listed in §6; no real authentication, session store, or token persistence; no ESLint/Prettier (Biome replaces them); no Webpack config (utoopack); no Redux/MobX (state is
useModel+ React Query +getInitialState).
20. Potential Improvements
Drawn from the code, the project's own roadmap, and community issues — the work most teams do after adopting Pro.
Authentication & session
- Implement real auth and token refresh. Complete the commented-out request interceptor; add a 401 response interceptor with silent refresh and a concurrent-request queue. This is the single most-requested capability (#11550, #11869).
- Dynamic routes/menus from the backend. Several teams want server-driven menus after login (#11802); UmiJS supports patching routes at runtime — wire it into
getInitialState.
UX & features
- Multi-tab navigation (keep-alive tabs) is a common enterprise request (#11627).
- Global search in the header (#11755).
- Fix the sidebar/pagination overlay bug (#11597, #11821) — tracked for v6.1.0.
Engineering hygiene
- Finish the Jest → Vitest migration (#11823) and bring the excluded login test into the Vitest suite.
- Tighten OpenAPI codegen — naming/casing consistency fixes are tracked (#11819, #11846).
- Harden Windows install — the
tailwindcssresolution issue (#11747, #11818) is fixed but worth verifying in your CI. - Raise the coverage floor — coverage is informational; add a hard gate for your business code.
Tip
Track the v6.1.0 release (#11813) and use the
/pro-upgradeskill to pull fixes. Because Pro cleanly separates framework files from business files, staying current is far cheaper here than in a hand-rolled scaffold.
21. Quick Reference
Key files
| File | What it controls |
|---|---|
config/config.ts |
Build + all framework plugins. |
config/routes.ts |
Routes & menu (the feature map). |
config/defaultSettings.ts |
Layout/theme defaults. |
config/proxy.ts |
Dev proxy targets. |
config/oneapi.json |
API contract → codegen. |
src/app.tsx |
Runtime: initial state, layout, request, root container. |
src/access.ts |
Permission flags. |
src/requestErrorConfig.ts |
Request/response interceptors + error mapping. |
Essential commands
| Command | Purpose |
|---|---|
npm start |
Dev server with mocks. |
npm run dev / start:no-mock |
Dev server, real backend via proxy. |
npm run build |
Production build → dist/. |
npm run preview |
Serve the build locally. |
npm run deploy |
Build + publish to GitHub Pages. |
npm run lint |
Biome + tsc. |
npm test |
Vitest. |
npm run openapi |
Regenerate API services. |
npm run simple |
Strip to minimal template (irreversible). |
Default ports & URLs
| Item | Value |
|---|---|
| Dev / preview server | http://localhost:8000 |
| Demo backend | https://pro-api.ant-design-demo.workers.dev |
| Live preview | https://preview.pro.ant.design |
| Demo login | admin / ant.design (or user), mobile captcha 1234 |
Permission flags
| Flag | Definition |
|---|---|
canAdmin |
currentUser.access === 'admin' |