Ant Design 定制示例
介绍
Ant Design (Pro) 相关文档:
创建项目
Ant Design Pro 生成项目模板,参考
$ npm i @ant-design/pro-cli -g
$ pro create x-ui
$ cd x-ui
$ tyarn
$ tyarn start
$ tyarn start:dev
# 新版本 6.0
yarn create umi <myapp>
yarn run build
yarn run start
开发工具
目录结构
- 参考:https://pro.ant.design/zh-CN/docs/folder/
- 配置参考 https://v3.umijs.org/zh-CN/config
src/pages/document.ejs
配置加载页,包括对应的 logo 等
src/app.tsx
getInitialState
做权限初始化,如认证等信息
src/models
全局初始化数据,应用加载前初始化用户、权限、菜单等数据,其它地方使用 const { initialState, setInitialState } = useModel('@@initialState');
- 页面组件的定制,需要在
routes.ts
配置,参考 plugin-layout
相关扩展
定制
- 国际化删除
src/locales
对应的文件即可精简
代码生成
参考维生成器
umi generate
umi g
umi g page
umi g page bar --dir
umi g prettier
接口规范
export interface response {
success: boolean; // if request is success
data?: any; // response data
errorCode?: string; // code for errorType
errorMessage?: string; // message display to user
showType?: number; // error display type: 0 silent; 1 message.warn; 2 message.error; 4 notification; 9 page
traceId?: string; // Convenient for back-end Troubleshooting: unique request ID
host?: string; // onvenient for backend Troubleshooting: host of current access server
}
{
list: [
],
current?: number,
pageSize?: number,
total?: number,
}
{
"success": true,
"data": {},
"errorCode": "1001",
"errorMessage": "error message",
"showType": 2,
"traceId": "someid",
"host": "10.1.1.1"
}
# 对于简单的可以如下:
{
"success": true,
"data": {},
"errorMessage": "error message"
}
Mock
基于 OpenAPI 生成 SDK
-
基于 OpenAPI 生成前端调用代码(参考):
-
配置 config/config.ts
import { join } from 'path';
export default defineConfig({
...
openAPI: [
{
requestLibPath: "import { request } from 'umi'",
// 或者使用在线的版本
// schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json"
schemaPath: join(__dirname, 'oneapi.json'),
mock: false, // 为 true 会在 mock 目录生成 mock 文件
projectName: 'swagger',
},
...
- 生成 services 代码到 src/services/目录下
npm openapi
生成 openapi 文档到 src/services/swagger
目录,然后就可以在页面中调用
- requestInterceptors 注入 token 等,具体配置参考
权限
// src/access.ts
export default function (initialState: { currentUser?: API.CurrentUser | undefined }) {
const { currentUser } = initialState || {};
return {
canAdmin: currentUser && currentUser.access === 'admin',
};
}
静态发布时,配置 API 的 baseURL
/**
* @name request 配置,可以配置错误处理
* 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。
* @doc https://umijs.org/docs/max/request#配置
*/
export const request: RequestConfig = {
baseURL: 'https://proapi.azurewebsites.net',
...errorConfig,
};
路由方式
- 参考
- Ant Design Pro 使用的 Umi 可以使用两种路由方式:
browserHistory
使用 browserHistory 则需要服务器做好处理 URL 的准备,处理应用启动最初的 / 这样的请求应该没问题,但当用户来回跳转并在 /users/123 刷新时,服务器就会收到来自 /users/123 的请求,这时你需要配置服务器能处理这个 URL 返回正确的 index.html,否则就会出现 404 找不到该页面的情况
- 建议在配置中开启
exportStatic
,这样编译后的 dist
目录会对每一个路由都生成一个 index.html
,从而每个路由都能支持 deeplink 直接访问
- 强烈推荐使用默认的
browserHistory
hashHistory
使用 hashHistory 时浏览器访问到的始终都是根目录下 index.html,取井号(/#/users/123
)后面的字符作为路径
自定义参数配置
export default defineConfig({
define: {
APP_URL: 'http://dev.xiexianbin.cn:8000', // 当前SaaS发布的URL地址
},
...
declare const APP_URL: string;
css/less
- CSS Modules 的基本原理很简单,就是对每个类名(非 :global 声明的)按照一定规则进行转换,保证它的唯一性
多主题
参考 switch-theme
jsx
{/* jsx 单行注释 */}
{/*
多行注释
*/}
发布
npm run build
server {
listen 80;
# gzip config
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
root /usr/share/nginx/html;
location / {
# 用于配合 browserHistory使用
try_files $uri $uri/index.html /index.html;
# 如果有资源,建议使用 https + http2,配合按需加载可以获得更好的体验
# rewrite ^/(.*)$ https://preview.pro.ant.design/$1 permanent;
}
location /api {
proxy_pass https://ant-design-pro.netlify.com;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
# 如果有资源,建议使用 https + http2,配合按需加载可以获得更好的体验
listen 443 ssl http2 default_server;
# 证书的公私钥
ssl_certificate /path/to/public.crt;
ssl_certificate_key /path/to/private.key;
location / {
# 用于配合 browserHistory使用
try_files $uri $uri/index.html /index.html;
}
location /api {
proxy_pass https://ant-design-pro.netlify.com;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
}
}
自动修复 lint 的错误
npm run lint:fix
websocket 代理
// config/proxy.js
export default {
dev: {
// websocket代理
'/ws/': {
target: 'ws://localhost:1323',
ws: true,
logLevel: 'debug',
secure: false,
pathRewrite: {
'^/ws': '',
},
},
},
}
组件总览
Tailwind CSS
Ant Design vs UmiJS
Ant Design 和 UmiJS 都是由蚂蚁集团(Ant Group)开源的前端工具,它们之间存在着紧密的协作关系,但扮演的角色不同:
Ant Design
Ant Design (antd) 是一个基于 React 的UI 组件库。
- 它提供了一套开箱即用的高质量 React 组件,涵盖了从按钮、表格、表单到日期选择器、模态框等各种常用的 UI 元素。
- 它的核心目标是帮助开发者快速构建美观、专业的企业级中后台产品。
- Ant Design 强调设计规范和一致性,提供了完整的设计体系,让开发者能够专注于业务逻辑而不用过多关注 UI 的细节。
UmiJS
UmiJS (Umi) 是一个可扩展的企业级前端应用框架。
- 它是一个更底层的框架,负责处理项目构建、路由、数据流、国际化、权限管理等一整套前端开发所需的基础设施。
- Umi 提供了基于约定式或配置式的路由,拥有强大的插件系统,可以覆盖从源代码到构建产物的每一个生命周期,以满足各种功能和业务需求。
- 它是蚂蚁集团内部广泛使用的前端框架,直接或间接服务了上万个应用。
它们之间的关系
可以把 Ant Design 和 UmiJS 的关系理解为:
- Umi 是一个“骨架”或“地基”:它提供了构建一个完整前端应用所需的基础架构和开发环境,包括项目结构、构建工具、路由管理等。
- Ant Design 是“装修材料”或“家具”:它提供了在 Umi 构建好的应用框架上,用来构建用户界面(UI)的各种组件。
在实际开发中,UmiJS 经常与 Ant Design 结合使用,形成一个高效的企业级前端开发解决方案:
- 开箱即用: Umi 提供了对 Ant Design 的良好支持,通常在创建 Umi 项目时,可以选择包含 Ant Design 的模板,从而自动集成 Ant Design 的依赖和配置。
- 插件集成: Umi 提供了专门的插件,例如
@umijs/preset-ant-design-pro
或 @umijs/plugin-layout
等,可以进一步简化 Ant Design 的使用,例如自动生成 ProLayout 布局、支持 Ant Design 的主题定制等。
- Ant Design Pro: 值得一提的是 Ant Design Pro,它是基于 Umi 和 Ant Design 构建的一套开箱即用的中后台前端解决方案。它不仅包含了 Ant Design 的组件,还预设了常见的页面布局、数据流方案、权限管理等,大大加速了企业级应用开发。
简单来说,UmiJS 是一个框架,提供项目基础设施;Ant Design 是一个 UI 组件库,提供界面元素。它们经常被一起使用,特别是在开发企业级中后台应用时,能够极大地提高开发效率和一致性。
F&Q
CORS 问题
需求是实现 http://dev.xiexianbin.cn:8001 调用 http://dev.xiexianbin.cn:8888 时,将 .xiexianbin.cn 的 cookie 带过去
Access to fetch at 'http://dev.xiexianbin.cn:8888/api/v1/user' from origin 'http://dev.xiexianbin.cn:8001' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
export async function user(options?: { [key: string]: any }) {
return request<{
data: API.User;
}>('/api/v1/user', {
method: 'GET',
credentials: 'include', // 添加改行实现将 .xiexianbin.cn 的 cookie 带过去
...(options || {}),
});
}
// origin := c.Request.Header.Get("Origin")
// c.Header("Access-Control-Allow-Origin", origin)
c.Writer.Header().Set("Access-Control-Allow-Origin", c.Request.Header.Get("Origin") // 这一行是核心
c.Writer.Header().Set("Access-Control-Max-Age", "86400")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Access-Control-Allow-Origin, Origin, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
cors 示例