@meta-1/web-common
v0.0.7
Published
Meta-1 common
Readme
@meta-1/web-common
Meta-1 前端通用库,提供 React 组件、Hooks、工具函数和配置,用于构建 Next.js 应用。
✨ 特性
- 🎨 React 组件 - 通用 UI 组件库
- 🪝 自定义 Hooks - 数据查询、表单验证、国际化等 Hooks
- 🌍 国际化支持 - 基于 i18next 的多语言支持
- 🔧 工具函数 - REST API、加密、Token 管理等工具
- ⚙️ 配置预设 - Next.js 和 i18next 配置
- 🎯 类型安全 - 完整的 TypeScript 支持
📦 安装
此包为 Meta-1 项目内部包,通过 monorepo 工作区使用。
# 在项目根目录安装依赖
pnpm install🚀 使用
组件
RootLayout - 根布局组件
用于 Next.js App Router 的根布局,提供全局 Provider 配置。
import { RootLayout } from "@meta-1/web-common/components/layout/root";
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<RootLayout locale="zh-cn" theme="system">
{children}
</RootLayout>
);
}ThemeSwitcher - 主题切换组件
支持 light、dark、system 三种主题切换,带有平滑的 View Transition 动画。
import { ThemeSwitcher } from "@meta-1/web-common/components/theme-switcher";
function Header() {
return (
<div>
<ThemeSwitcher size="md" />
</div>
);
}Props:
size?: "sm" | "md" | "lg"- 组件尺寸,默认mdactiveClassName?: string- 激活状态的样式类名className?: string- 自定义样式类名
OTPInput - OTP 验证码输入组件
6 位数字验证码输入组件。
import { OTPInput } from "@meta-1/web-common/components/input/otp";
function VerifyCode() {
const [code, setCode] = useState("");
return (
<OTPInput
value={code}
onChange={setCode}
/>
);
}Props:
value?: string- 当前值onChange?: (value: string) => void- 值变化回调
Loading - 加载组件
全屏加载动画组件。
import { Loading } from "@meta-1/web-common/components/loading";
function App() {
if (isLoading) {
return <Loading />;
}
return <div>内容</div>;
}Visible - 可见性控制组件
根据条件显示/隐藏内容。
import { Visible } from "@meta-1/web-common/components/visible";
function MyComponent() {
const [show, setShow] = useState(true);
return (
<Visible visible={show}>
<div>条件显示的内容</div>
</Visible>
);
}Props:
visible?: boolean- 是否显示,默认truechildren: React.ReactNode- 子元素
Uploader - 文件上传组件
文件上传组件,基于 @meta-1/design 的 Uploader 封装。
import { Uploader } from "@meta-1/web-common/components/uploader";
function FileUpload() {
const [files, setFiles] = useState([]);
return (
<Uploader
value={files}
onChange={setFiles}
action="/api/upload"
/>
);
}Props:
value?: UploadFile[]- 已上传的文件列表onChange?: (value: UploadFile[]) => void- 文件变化回调- 其他 props 继承自
@meta-1/design的 Uploader
Hooks
useQuery - REST API 查询 Hook
基于 TanStack Query 封装的查询 Hook,自动处理 REST API 响应格式和错误提示。
import { useQuery } from "@meta-1/web-common/hooks";
import { get } from "@meta-1/web-common/utils/rest";
function UserList() {
const { data, isLoading, error } = useQuery({
queryKey: ["users"],
queryFn: async () => {
return await get<User[]>("/api/users");
},
showError: true, // 是否自动显示错误消息,默认 false
});
if (isLoading) return <div>加载中...</div>;
if (error) return <div>错误: {error.message}</div>;
return (
<ul>
{data?.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}特点:
- 自动处理
RestResult<T>格式的响应 - 自动解包
data字段 - 支持错误自动提示(可选)
- 取消请求的错误(错误码 499)不会显示
useMutation - REST API 变更 Hook
基于 TanStack Query 封装的变更 Hook,用于 POST、PUT、DELETE 等操作。
import { useMutation } from "@meta-1/web-common/hooks";
import { post } from "@meta-1/web-common/utils/rest";
import { useQueryClient } from "@tanstack/react-query";
function CreateUser() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: async (data: CreateUserData) => {
return await post<User>("/api/users", data);
},
showError: true, // 是否自动显示错误消息,默认 true
noErrorCode: [400], // 不显示错误消息的错误码列表
onSuccess: () => {
// 成功后刷新列表
queryClient.invalidateQueries({ queryKey: ["users"] });
},
});
const handleSubmit = (data: CreateUserData) => {
mutation.mutate(data);
};
return (
<form onSubmit={handleSubmit}>
{/* 表单内容 */}
<button type="submit" disabled={mutation.isPending}>
{mutation.isPending ? "提交中..." : "提交"}
</button>
</form>
);
}特点:
- 自动处理
RestResult<T>格式的响应 - 自动解包
data字段 - 支持错误自动提示(默认开启)
- 支持排除特定错误码
- 取消请求的错误(错误码 499)静默处理
useTableLoader - 表格数据加载 Hook
用于表格分页、筛选、排序等场景的数据加载 Hook,支持 URL 参数同步。
import { useTableLoader } from "@meta-1/web-common/hooks";
import { get } from "@meta-1/web-common/utils/rest";
import type { PageResult } from "@meta-1/web-common/types/rest";
function UserTable() {
const { loading, result, query, load, reset, refetch } = useTableLoader<User>({
defaultValues: {
keyword: "",
status: "active",
},
action: async (params) => {
return await get<PageResult<User>>("/api/users", params);
},
withURL: true, // 是否同步 URL 参数,默认 true
encodeParams: ["keyword"], // 需要 URL 编码的参数
keys: ["extraKey"], // 额外的查询参数键
});
const handleSearch = (keyword: string) => {
load({ keyword, page: 1 });
};
const handleReset = () => {
reset();
};
if (loading) return <div>加载中...</div>;
return (
<div>
<input
value={query.keyword}
onChange={(e) => handleSearch(e.target.value)}
/>
<button onClick={handleReset}>重置</button>
<table>
{/* 表格内容 */}
</table>
<div>
当前页: {query.page}, 每页: {query.size}
总数: {result?.data?.total || 0}
</div>
</div>
);
}返回值:
loading: boolean- 是否正在加载result: RestResult<PageData<T>> | null- 查询结果query: any- 当前查询参数load: (params?: any) => Promise<void>- 加载数据(合并参数)reset: () => void- 重置到初始状态refetch: () => Promise<void>- 刷新当前数据
特点:
- 自动同步 URL 查询参数
- 自动处理分页参数(page, size)
- 自动矫正超出范围的页码
- 支持参数合并和重置
- 内置加载状态管理
useLocale - 国际化语言切换 Hook
用于切换应用语言。
import { useLocale } from "@meta-1/web-common/hooks";
function LanguageSwitcher() {
const [locale, setLocale] = useLocale();
return (
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
<option value="zh-cn">中文</option>
<option value="en">English</option>
</select>
);
}返回值:
[locale: string, setLocale: (value: string) => void]- 当前语言和设置函数
useSchema - Zod Schema 国际化 Hook
用于将 Zod Schema 的错误消息进行国际化处理。
import { useSchema } from "@meta-1/web-common/hooks";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
const LoginSchema = z.object({
email: z.string().email("validation.email.invalid"),
password: z.string().min(8, "validation.password.min"),
});
function LoginForm() {
const schema = useSchema(LoginSchema);
const form = useForm({
resolver: zodResolver(schema),
});
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
{/* 表单内容 */}
</form>
);
}特点:
- 自动翻译 Schema 中的错误消息键
- 支持嵌套对象、数组、联合类型等复杂 Schema
- 支持 ZodEffects(refine、superRefine 等)
useEncrypt - RSA 加密 Hook
用于对敏感数据进行 RSA 加密。
import { useEncrypt } from "@meta-1/web-common/hooks";
function LoginForm() {
const encrypt = useEncrypt();
const handleSubmit = async (password: string) => {
const encryptedPassword = encrypt(password);
// 发送加密后的密码
await post("/api/login", { password: encryptedPassword });
};
return <form onSubmit={handleSubmit}>...</form>;
}返回值:
encrypt: (text: string) => string- 加密函数,如果未设置公钥则返回原文
工具函数
REST API 工具
提供 REST API 请求方法,自动处理响应格式和错误。
import {
get,
post,
put,
patch,
del,
download,
request,
alias,
config,
} from "@meta-1/web-common/utils/rest";
import type { RestResult } from "@meta-1/web-common/types/rest";
// GET 请求
const result = await get<User[]>("/api/users", { page: 1, size: 10 });
// POST 请求
const result = await post<User>("/api/users", {
name: "John",
email: "[email protected]",
});
// PUT 请求
const result = await put<User>("/api/users/1", {
name: "John Updated",
});
// PATCH 请求
const result = await patch<User>("/api/users/1", {
name: "John Patched",
});
// DELETE 请求
const result = await del("/api/users/1");
// 文件下载
await download("/api/export", { format: "excel" }, {
fileName: "users.xlsx",
});
// 自定义请求
const result = await request<Data>({
url: "/api/custom",
method: "POST",
data: { ... },
});
// 配置 API 别名
alias({
"@api": {
url: "https://api.example.com",
headers: async () => ({
"X-Custom-Header": "value",
}),
},
});
// 使用别名
await get("@api/users");
// 全局配置
config({
onResponse: (data, response) => {
// 处理响应
},
});响应格式:
所有请求返回 Promise<RestResult<T>>,格式如下:
type RestResult<T> = {
success?: boolean;
code?: number;
message?: string;
data?: T;
};Token 工具
Token 的存储和读取工具。
import {
getToken,
setToken,
clearToken,
} from "@meta-1/web-common/utils/token";
import type { Token } from "@meta-1/web-common/types/token";
// 客户端获取 Token
const token = await getToken();
// 服务端获取 Token
import { cookies } from "next/headers";
const token = await getToken(cookies());
// 设置 Token
setToken({
token: "eyJhbGciOiJIUzI1NiIs...",
expiresIn: 3600,
});
// 清除 Token
clearToken();加密工具
RSA 加密工具。
import { encrypt } from "@meta-1/web-common/utils/crypto";
const publicKey = "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----";
const encrypted = encrypt("sensitive-data", publicKey);环境工具
环境检测和工具函数。
import {
isServer,
isMobile,
getRootDomain,
} from "@meta-1/web-common/utils/env";
// 判断是否在服务端
if (isServer) {
// 服务端代码
}
// 判断是否为移动设备
if (isMobile()) {
// 移动端代码
}
// 获取根域名(用于跨子域 Cookie)
const rootDomain = getRootDomain("app.example.com");
// => ".example.com"格式化工具
数据格式化工具。
import { formatFileSize } from "@meta-1/web-common/utils/format";
const size = formatFileSize(1024 * 1024 * 5);
// => "5 MB"正则表达式常量
常用正则表达式。
import {
EMAIL,
URL,
USERNAME,
PASSWORD,
CODE,
PHONE,
NUMBER,
} from "@meta-1/web-common/utils/regular";
EMAIL.test("[email protected]"); // true
PHONE.test("13800138000"); // true
PASSWORD.test("Abc123!@#"); // trueURL 工具
URL 处理工具。
import { getPathname } from "@meta-1/web-common/utils/url";
const pathname = getPathname("/api/users?page=1");
// => "/api/users"React Query 工具
React Query 客户端和预取工具。
import {
getQueryClient,
prefetchQuery,
dehydrate,
HydrationBoundary,
} from "@meta-1/web-common/utils/query";
import { get } from "@meta-1/web-common/utils/rest";
// 获取 QueryClient(服务端每次新建,客户端复用)
const queryClient = getQueryClient();
// 预取数据(服务端)
await prefetchQuery(queryClient, {
queryKey: ["users"],
queryFn: async () => {
return await get<User[]>("/api/users");
},
});
// 在组件中使用
export default function Page() {
const queryClient = getQueryClient();
const dehydratedState = dehydrate(queryClient);
return (
<HydrationBoundary state={dehydratedState}>
<UserList />
</HydrationBoundary>
);
}请求头工具
客户端和服务端请求头生成工具。
// 客户端
import { get } from "@meta-1/web-common/utils/headers.client";
const headers = await get();
// 包含: Accept-Language, CLIENT-PLATFORM-TYPE, Authorization 等
// 服务端
import { get } from "@meta-1/web-common/utils/headers.server";
const headers = await get();
// 包含: Accept-Language, CLIENT-PLATFORM-TYPE, Authorization 等i18next 工具
i18next 初始化工具。
import { initI18next } from "@meta-1/web-common/utils/i18next";
await initI18next({
"zh-cn": {
translation: {
welcome: "欢迎",
},
},
"en": {
translation: {
welcome: "Welcome",
},
},
});主题服务端工具
服务端获取主题配置。
import { getTheme } from "@meta-1/web-common/utils/theme.server";
const theme = await getTheme();
// => "light" | "dark" | "system"格式化工具
数据格式化工具。
import { join } from "@meta-1/web-common/formatters";
const result = join(["a", "b", "c"], ", ");
// => "a, b, c"状态管理
公共状态 Atoms
使用 Jotai 管理的全局状态。
import {
localeState,
publicKeyState,
} from "@meta-1/web-common/state/public";
import { useAtom, useAtomValue } from "jotai";
function MyComponent() {
const [locale, setLocale] = useAtom(localeState);
const publicKey = useAtomValue(publicKeyState);
return <div>当前语言: {locale}</div>;
}类型定义
REST API 类型
import type {
RestResult,
PageData,
PageResult,
PageRequest,
} from "@meta-1/web-common/types/rest";
type User = {
id: number;
name: string;
};
const result: RestResult<User> = {
success: true,
code: 200,
message: "成功",
data: {
id: 1,
name: "John",
},
};
const pageResult: PageResult<User> = {
success: true,
code: 200,
data: {
total: 100,
data: [/* users */],
},
};Token 类型
import type { Token } from "@meta-1/web-common/types/token";
const token: Token = {
token: "eyJhbGciOiJIUzI1NiIs...",
expiresIn: 3600,
};事件总线
全局事件总线,基于 EventEmitter3。
import eventBus from "@meta-1/web-common/events";
// 监听事件
eventBus.on("user-login", (data) => {
console.log("用户登录", data);
});
// 触发事件
eventBus.emit("user-login", { userId: 123 });
// 移除监听
eventBus.off("user-login", handler);配置
i18next 配置
import {
getBaseI18nextConfig,
FALLBACK,
MISSING_KEY_PREFIX,
} from "@meta-1/web-common/config/i18next";
const config = getBaseI18nextConfig(resources);📦 包含内容
组件
- 布局组件: RootLayout, MainLayout, HtmlLayout, LoginLayout
- 输入组件: OTPInput, CodeInput, EmailCodeInput, SliderInput
- 页面组件: PageHeader, PageTitleBar, TabsTitle
- UI 组件: Loading, Coming, Visible, ThemeSwitcher, LangSelect
- 特效组件: IridescenceBackground
- 上传组件: Uploader
- 工具组件: AtomsHydrate, ThemeSyncProvider, InfoTooltip
Hooks
useQuery- REST API 查询 HookuseMutation- REST API 变更 HookuseTableLoader- 表格数据加载 HookuseLocale- 国际化语言切换 HookuseSchema- Zod Schema 国际化 HookuseEncrypt- RSA 加密 Hook
工具函数
- rest.ts - REST API 请求工具
- token.ts - Token 管理工具
- crypto.ts - RSA 加密工具
- query.ts - React Query 客户端工具
- env.ts - 环境检测工具
- format.ts - 数据格式化工具
- regular.ts - 正则表达式常量
- url.ts - URL 处理工具
- i18next.ts - i18next 初始化工具
- headers.client.ts - 客户端请求头工具
- headers.server.ts - 服务端请求头工具
- theme.server.ts - 主题服务端工具
- locale.server.ts - 语言服务端工具
状态管理
localeState- 语言状态 AtompublicKeyState- 公钥状态 Atom
类型定义
RestResult,PageResult,PageRequest- REST API 类型Token- Token 类型
事件
eventBus- 全局事件总线
格式化工具
join- 数组连接工具
📄 许可证
MIT
