npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gz-fronted/gz-pc

v0.2.0

Published

Shared fetch, hooks and utility primitives for GZ frontend applications.

Readme

@gz-fronted/gz-pc

面向 GZ 前端项目的请求、Hooks 和轻量工具函数包。各子路径独立构建;只使用 utils 时不会加载 Axios、React、ahooks 或 gz-ui-web。

安装

npm install @gz-fronted/gz-pc react@^19 react-dom@^19 [email protected] [email protected] [email protected] [email protected] [email protected]

宿主项目需要提供以下 peer dependencies:

  • React 19
  • gz-ui-web ^1.0.1(开发验证固定使用 1.0.1)

[email protected] 还要求宿主提供 React DOM 19、AntD 6.3.3,以及 ag-grid-react、ag-grid-community、ag-grid-enterprise 36.0.1。 在应用入口引入一次组件库样式:

import 'gz-ui-web/gz-ui-web.css';

从旧版迁移时,宿主需要将组件导入和 ConfigProvider 统一切换到 gz-ui-web, 并将旧样式入口替换为上述入口。本次 peer 依赖迁移包含兼容性变化;React 18 项目需要先升级。

Axios、ahooks 和 lossless-json 是 gz-pc 的普通 dependencies,安装 gz-pc 时会自动安装,宿主 无需手工添加。React 和 gz-ui-web 不会打入本包产物。

本包刻意不提供聚合根入口,请始终从 /fetch、/hooks 或 /utils 子路径导入, 避免加载无关模块。

请求协议

gz-fetch 默认将所有 HTTP 2xx 状态视为成功,包括 200、201、202、204 和 206。 非 2xx 状态进入统一错误处理并抛出 GzFetchError,错误中保留 status 和 responseData。

成功时直接返回后端原始的 response.data,不会返回 AxiosResponse,也不会:

  • 判断业务 code
  • 自动解包 data
  • 转换分页、字段或日期(数值精度保护需在初始化时显式开启)

例如后端返回以下内容时,调用方取得的是包含 code、data、message 的完整 对象:

interface CreateOrderResponse {
  code: number;
  data: {
    orderId: string;
  };
  message: string;
}

const response = await gzFetch<CreateOrderResponse, CreateOrderParams>({
  url: '/order/create',
  method: 'POST',
  params,
});

response.code;
response.data.orderId;
response.message;
import { configureGzFetch, gzFetch } from '@gz-fronted/gz-pc/fetch';

// 应用初始化入口只调用一次;微前端重新挂载时可以覆盖上一次配置。
configureGzFetch({
  baseURL: '/api',
  timeout: 15_000,
  getToken: () => runtimeToken,
  showErrorMessage: true,
});

interface ListResult {
  records: Array<{ id: string }>;
  total: number;
}

const result = await gzFetch<ListResult>({
  url: '/users',
  method: 'GET',
  params: {
    page: 1,
    pageSize: 20,
  },
});
result.records;
result.total;

interface CreateUserParams {
  name: string;
}

await gzFetch<ListResult, CreateUserParams>({
  url: '/users',
  method: 'POST',
  params: {
    name: 'Alice',
  },
});

业务模块直接导入并调用 gzFetch,不需要自行创建请求实例。gz-pc 统一使用 配置对象式请求调用,业务代码不得混用 gzFetch(config) 与 gzFetch.get/post/put/delete 两种风格。快捷方法仅作为内部兼容层保留,不作为 业务开发规范。

如果在 configureGzFetch 之前调用 gzFetch,会明确抛出错误,不会静默使用 空配置,也不会读取 localStorage。

类型签名

gzFetch 的第一个泛型是响应数据类型,第二个泛型是请求参数类型:

function gzFetch<TResponse, TRequestParams = unknown>(
  config: GzRequestConfig<TRequestParams>,
): Promise<TResponse>;

成功时直接返回 response.data,因此调用结果类型是 TResponse,不是 AxiosResponse<TResponse>。

单次请求配置

| 字段 | 类型 | 必填 | 说明 | | ------------------ | -------------------------------------- | ---- | ------------------------------------------ | | url | string | 是 | 请求地址;配置了 baseURL 时会与其组合 | | method | 'GET' \| 'POST' \| 'PUT' \| 'DELETE' | 是 | 请求方法,统一使用大写 | | params | TRequestParams | 否 | 统一请求入参,由第二个泛型约束 | | paramsInUrl | boolean | 否 | 仅 DELETE 生效;为 true 时参数放入 Query | | headers | Record<string, string> | 否 | 本次请求附加的请求头 | | timeout | number | 否 | 本次请求超时时间,单位毫秒;优先于实例配置 | | showErrorMessage | boolean | 否 | 是否调用 gz-ui-web 的 message.error | | skipAuth | boolean | 否 | 为 true 时跳过 Token 注入 | | responseType | 'json' \| 'blob' \| 'text' | 否 | 响应数据类型,默认 json | | signal | AbortSignal | 否 | 取消请求的标准 AbortSignal | | withCredentials | boolean | 否 | 是否携带跨域 Cookie 等凭证 |

请求入参字段统一使用 params,业务代码不需要区分 Axios 的 params 和 data:

  • GET:params 转为 URL Query。
  • POST、PUT、DELETE:params 转为 Request Body。

DELETE 的 paramsInUrl 默认为 false。仅当兼容明确要求 Query 参数的 DELETE 接口时设置为 true,此时 params 只转为 URL Query,不再发送 Request Body:

await gzFetch<void, { id: number }>({
  url: '/users',
  method: 'DELETE',
  params: { id: 1 },
  paramsInUrl: true,
});

业务请求配置不支持 data,也不得混用 params 和 data。 POST、PUT、DELETE 的 params 支持 JSON 对象、FormData、URLSearchParams 和 Blob; 自定义请求头通过 headers 传入。

完整示例:

interface SaveParams {
  id: string;
  name: string;
}

interface SaveResult {
  success: boolean;
}

const controller = new AbortController();

const result = await gzFetch<SaveResult, SaveParams>({
  url: '/user/save',
  method: 'POST',
  params: {
    id: '1001',
    name: '张三',
  },
  headers: {
    'X-Request-Source': 'gz-pc',
  },
  timeout: 10_000,
  showErrorMessage: true,
  skipAuth: false,
  responseType: 'json',
  signal: controller.signal,
});

应用初始化配置

configureGzFetch 只在应用初始化层调用。它接收以下配置:

| 字段 | 类型 | 默认值 | 说明 | | ------------------------- | ----------------------------------------------------------- | ----------------- | --------------------------------- | | baseURL | string | 无 | 所有业务请求的基础地址 | | timeout | number | 15000 | 默认请求超时时间,单位毫秒 | | validateStatus | (status: number) => boolean | 所有 2xx | 自定义 HTTP 成功状态范围 | | getToken | () => string \| undefined \| Promise<string \| undefined> | 无 | 每次请求前动态获取 Token | | showErrorMessage | boolean | true | 实例级错误提示开关 | | preserveNumberPrecision | boolean | false | JSON 数值精度保护,可能返回字符串 | | auth.headerName | string | Authorization | Token 请求头名称 | | auth.formatToken | (token: string) => string | Bearer ${token} | Token 格式化函数 | | unauthorized | GzFetchUnauthorizedOptions | 未开启 | 可选的 HTTP 401 统一处理 | | middlewares | readonly GzFetchMiddleware[] | [] | 请求、响应和错误中间件 |

需要覆盖默认成功状态时,只在应用初始化层配置:

configureGzFetch({
  validateStatus: (status) => status === 200 || status === 304,
});

当前稳定 API 没有开放 Axios 的 paramsSerializer、onUploadProgress 等配置,也 暂不支持 PATCH。业务代码只应传入上表列出的字段;如果后续确有通用场景,再 通过 gz-pc 统一扩展类型和请求核心。

JSON 数值精度保护

交易等需要保留长 ID 或高精度数值的项目,在应用初始化时显式开启:

configureGzFetch({
  baseURL: '/api',
  preserveNumberPrecision: true,
});

默认关闭,继续使用 Axios 的原有解析规则。开启后,在首次 JSON.parse 前处理 原始 JSON:超出安全整数范围或转为 number 会丢失十进制有效数字的数值, 保留为原始字符串;普通数字仍为 number,已有字符串不变。成功响应和 HTTP 错误响应使用相同规则,onResponse 和 GzFetchError.responseData 都能获得保精度的值。

例如原始响应 {"targtAllVarCodeSum":352782533194208303,"count":2} 会返回 { targtAllVarCodeSum: '352782533194208303', count: 2 }。 不能在 onResponse 中对已经舍入的值调用 String() 来恢复精度。

此配置不处理请求参数,不解包响应,也不转换显式 responseType: 'text' 或 'blob' 的内容。独立服务实例同样可通过 createGzFetch 开启。可能返回字符串的 DTO 字段应声明为 string | number,接收后不要再无条件调用 Number()。 该能力保护传输和解析过程,不提供高精度算术运算。

跨域凭证

需要浏览器携带跨域 Cookie 等凭证时,在单次请求中开启 withCredentials:

await gzFetch<QueryPresetResponse, QueryPresetParams>({
  url: '/queryFilterTemplate/list',
  method: 'POST',
  params,
  withCredentials: true,
});

Token

getToken 会在每次请求前动态执行。gz-fetch 不读取 Props、React Context 或 localStorage。

默认请求头为 Authorization: Bearer <token>:

configureGzFetch({
  getToken: async () => tokenStore.get(),
});

await gzFetch<PublicConfig>({
  url: '/public/config',
  method: 'GET',
  skipAuth: true,
});

也可以修改 Header 名称和格式:

configureGzFetch({
  getToken: () => token,
  auth: {
    headerName: 'X-Token',
    formatToken: (value) => `Token ${value}`,
  },
});

错误提示

HTTP 非 2xx 时仅尝试读取响应体的 msg。没有有效 msg 时使用默认文案,最终 抛出 GzFetchError。

错误类型包括:

  • HTTP_ERROR
  • NETWORK_ERROR
  • TIMEOUT_ERROR
  • CANCELED_ERROR
  • UNKNOWN_ERROR

错误 Message 默认开启,优先级为“单请求配置 > 实例配置 > 默认值 true”:

configureGzFetch({ showErrorMessage: true });

await gzFetch<void, SaveParams>({
  url: '/save',
  method: 'POST',
  params,
  showErrorMessage: false,
});

取消请求会转换成 CANCELED_ERROR,且默认不调用 message.error:

const controller = new AbortController();

const promise = gzFetch<UserDetail>({
  url: '/users',
  method: 'GET',
  signal: controller.signal,
});

controller.abort();
await promise;

HTTP 401 统一处理

401 统一处理默认关闭,未显式开启时继续执行原有 HTTP 错误提示和抛错逻辑,不弹窗、 不跳转。需要启用时,在应用初始化配置中传入 unauthorized.enabled: true:

configureGzFetch({
  baseURL: '/api',
  getToken: () => runtimeToken,
  unauthorized: {
    enabled: true,
    loginUrl: '/login',
    modalTitle: '登录失效',
    modalMessage: '当前登录状态已失效,请重新登录。',
  },
});

配置默认值如下:

| 字段 | 类型 | 默认值 | | ---------------- | ------------ | --------------------------------------- | | enabled | boolean | false | | loginUrl | string | /login | | modalTitle | string | 登录失效 | | modalMessage | string | 当前登录状态已失效,请重新登录。 | | onUnauthorized | () => void | 无;确认后使用 window.location.assign |

为了让普通错误消息和 401 弹窗都继承宿主项目当前的 gz-ui-web 主题,需要在应用根部的 ConfigProvider 内挂载一次 GzFetchFeedbackProvider:

import { GzFetchFeedbackProvider } from '@gz-fronted/gz-pc/fetch';
import { ConfigProvider } from 'gz-ui-web';

<ConfigProvider themeMode={themeMode}>
  <GzFetchFeedbackProvider>
    <App />
  </GzFetchFeedbackProvider>
</ConfigProvider>;

该 Provider 使用 message.useMessage() 和受控 gz-ui-web Modal,不会在已接入的项目中 调用脱离 React 上下文的静态反馈 API。因此主题切换时,普通错误消息和 401 弹窗都会 继续读取宿主 ConfigProvider 的主题 Token,无需复制亮色或暗色样式。业务页面不需要 维护反馈状态。未挂载该 Provider 的已有项目仍会回退到原来的静态 message.error, 不会产生 breaking change。GzFetchUnauthorizedModal 继续保留为兼容 API,但新项目 优先使用统一 Provider。

所有由同一份 gz-pc 包创建的默认客户端和独立客户端共享一个 401 管理器。首个 401 打开弹窗,后续并发 401 不会创建新弹窗;取消或弹窗关闭动画结束后会释放状态,后续 独立发生的 401 可以再次打开。确认操作也有同一状态锁,不会重复执行登录跳转。

业务项目需要自定义 SSO、登出或状态清理时传入 onUnauthorized。用户确认后优先执行 该回调;只有未提供回调时才通过 window.location.assign(loginUrl) 跳转:

configureGzFetch({
  unauthorized: {
    enabled: true,
    onUnauthorized: () => {
      authService.logout();
    },
  },
});

开启该能力后,401 仍会作为 GzFetchError 抛给调用方,但请求核心不会再为同一个 401 额外调用普通 message.error。其他 HTTP 错误、网络错误、超时和取消请求行为不变。

中间件

中间件的 onRequest、onResponse 和 onError 都按注册顺序执行,不采用洋葱 模型:

configureGzFetch({
  middlewares: [
    {
      onRequest(config) {
        return {
          ...config,
          headers: {
            ...config.headers,
            'X-Trace-ID': crypto.randomUUID(),
          },
        };
      },
      onResponse(data, context) {
        console.debug(context.status);
        return data;
      },
      onError(error) {
        console.error(error.type);
      },
    },
  ],
});

独立请求实例

普通业务模块禁止反复调用 createGzFetch。它只用于确实需要独立请求实例的高级 场景,例如多后端服务、独立 baseURL、独立 Token 或独立中间件链:

import { createGzFetch } from '@gz-fronted/gz-pc/fetch';

const reportingFetch = createGzFetch({
  baseURL: '/reporting-api',
  getToken: () => reportingToken,
});

const report = await reportingFetch<ReportResult>({
  url: '/reports/latest',
  method: 'GET',
});

默认 gzFetch 和独立实例都复用同一套请求核心、错误处理、Token 注入和中间件 实现。

Blob

gz-fetch 只返回 Blob,不创建下载链接、不解析文件名:

const file = await gzFetch<Blob, ExportParams>({
  url: '/export',
  method: 'POST',
  params,
  responseType: 'blob',
});

Hooks

import {
  useDebounce,
  useDebounceFn,
  usePagination,
  useRequest,
} from '@gz-fronted/gz-pc/hooks';

gz-pc/hooks 通过 export * from 'ahooks' 完整透传 ahooks 的公开 API,作为团队 统一的 Hooks 使用入口。后续自定义 Hook 也从同一入口导出:

export * from 'ahooks';
export * from './use-table-height';

新增自定义 Hook 时不得与 ahooks 已有导出重名。

formatDate

import { formatDate } from '@gz-fronted/gz-pc/utils';

formatDate(new Date()); // YYYY-MM-DD HH:mm:ss
formatDate(Date.now(), 'YYYY-MM-DD');

支持 string | number | Date | null | undefined。null、undefined、空字符串和 无效日期统一返回 --。该入口不依赖 React、ahooks、Axios 或 gz-ui-web。

Query 参数

import { objectToQuery, queryToObject } from '@gz-fronted/gz-pc/utils';

queryToObject('https://example.com/list?page=1&tag=a&tag=b');
// { page: '1', tag: ['a', 'b'] }

objectToQuery({
  page: 1,
  keyword: 'audit log',
  tag: ['a', 'b'],
});
// page=1&keyword=audit+log&tag=a&tag=b

queryToObject 支持完整 URL、带 ? 的 query 和纯 query 字符串;重复参数返回 字符串数组。objectToQuery 返回不带前导 ? 的字符串,跳过 undefined, 将 null 转为空值,并将数组序列化为重复参数。

MSW Mock

完整接入样例位于 examples/msw。核心启动顺序如下:

async function bootstrap(): Promise<void> {
  if (import.meta.env.VITE_USE_MOCK === 'true') {
    const { startMock } = await import('./mock/browser');
    await startMock();
  }

  renderApp();
}

void bootstrap();
worker.start({
  onUnhandledRequest: 'bypass',
});

必须等待 worker.start() 完成后再渲染应用,避免首次请求漏拦截。具体 Handler 和 Mock 数据由业务项目维护,gz-pc 不提供业务 Mock。

本地接入

先在本仓库构建并生成 tarball:

npm run build
npm pack

然后在业务项目安装生成的 .tgz:

npm install ../gz-pc/gz-fronted-gz-pc-0.1.0.tgz

也可以在联调期间使用业务项目支持的 workspace 或本地 file: 依赖。发布前建议 优先用 tarball 验证,因为它与 npm 实际安装内容最接近。

提交规范

项目使用 Husky、lint-staged、Commitlint 和 Conventional Commits。安装依赖时 prepare 脚本会初始化 Husky。

pre-commit 在提交前只检查 Git 暂存区中的文件:

  • JavaScript、JSX、TypeScript、TSX:依次执行 eslint --fix 和 prettier --write
  • JSON、Markdown、YAML、CSS、Less:执行 prettier --write

可以自动修复的问题会写回暂存文件;仍存在的 ESLint 错误会阻止提交。lint-staged 只负责提交前的快速增量检查,不替代完整的 lint、typecheck、test 和 build。

Prettier 对 JavaScript、TypeScript 和 JSX 统一使用单引号;JSON 按标准继续使用 双引号。

commit-msg 使用 Commitlint 校验提交信息:

feat: add request client
fix: handle canceled request

缺少合法 type、subject 或其他不符合 Conventional Commits 的提交信息会被拒绝。

第一版边界

第一版不包含 Token 自动刷新、自动重试、缓存、请求去重、并发控制、业务 code 判断、data 解包、分页/日期转换、错误上报、自动文件下载、内置业务 Mock、 React Context、Zustand 或复杂洋葱中间件。