From ed3e8ace8934b9753ed7acabc1399ec1125cccae Mon Sep 17 00:00:00 2001 From: afc163 Date: Mon, 20 Apr 2026 16:05:50 +0800 Subject: [PATCH] chore: reduce bundle size by replacing heavy dependencies (#11698) Co-authored-by: Claude Sonnet 4.6 Co-authored-by: afc163 --- config/config.ts | 1 + jest.config.ts | 1 + package.json | 3 - pnpm-lock.yaml | 70 ------------------- src/components/Footer/index.tsx | 21 +++--- .../center/components/Applications/index.tsx | 4 +- .../analysis/components/Charts/index.tsx | 8 +-- .../analysis/components/IntroduceRow.tsx | 17 ++--- .../analysis/components/ProportionSales.tsx | 4 +- .../analysis/components/SalesCard.tsx | 6 +- .../analysis/components/TopSearch.tsx | 4 +- src/pages/dashboard/monitor/index.tsx | 17 +++-- src/pages/list/search/applications/index.tsx | 4 +- .../login/__snapshots__/login.test.tsx.snap | 4 +- src/typings.d.ts | 3 +- src/utils/format.ts | 16 +++++ 16 files changed, 64 insertions(+), 119 deletions(-) create mode 100644 src/utils/format.ts diff --git a/config/config.ts b/config/config.ts index 3d2450d9..a9a7ca57 100644 --- a/config/config.ts +++ b/config/config.ts @@ -200,5 +200,6 @@ export default defineConfig({ 'process.env.CI': process.env.CI, 'process.env.COMMIT_HASH': process.env.COMMIT_HASH || '', 'process.env.CF_PAGES_COMMIT_SHA': process.env.CF_PAGES_COMMIT_SHA || '', + __APP_VERSION__: JSON.stringify(require('./../package.json').version), }, }); diff --git a/jest.config.ts b/jest.config.ts index d0f5a262..f61808c0 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -21,6 +21,7 @@ export default async (): Promise => { globals: { ...config.globals, localStorage: null, + __APP_VERSION__: 'test', }, }; }; diff --git a/package.json b/package.json index 990729b0..9221f5b1 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,6 @@ "antd-style": "^4.1.0", "clsx": "^2.1.1", "dayjs": "^1.11.19", - "git-url-parse": "^16.1.0", - "numeral": "^2.0.6", "react": "^19.2.4", "react-dom": "^19.2.4" }, @@ -66,7 +64,6 @@ "@types/express": "^5.0.6", "@types/jest": "^30.0.0", "@types/node": "^25.0.3", - "@types/numeral": "^2.0.5", "@types/react": "^19.2.10", "@types/react-dom": "^19.2.3", "@types/react-helmet": "^6.1.11", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d5ae736b..89b56106 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,12 +50,6 @@ importers: dayjs: specifier: ^1.11.19 version: 1.11.20 - git-url-parse: - specifier: ^16.1.0 - version: 16.1.0 - numeral: - specifier: ^2.0.6 - version: 2.0.6 react: specifier: ^19.2.4 version: 19.2.5 @@ -90,9 +84,6 @@ importers: '@types/node': specifier: ^25.0.3 version: 25.6.0 - '@types/numeral': - specifier: ^2.0.5 - version: 2.0.5 '@types/react': specifier: ^19.2.10 version: 19.2.14 @@ -2988,16 +2979,9 @@ packages: '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - '@types/numeral@2.0.5': - resolution: {integrity: sha512-kH8I7OSSwQu9DS9JYdFWbuvhVzvFRoCPCkGxNwoGgaPeDfEPJlcxNvEOypZhQ3XXHsGbfIuYcxcJxKUfJHnRfw==} - '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/parse-path@7.1.0': - resolution: {integrity: sha512-EULJ8LApcVEPbrfND0cRQqutIOdiIgJ1Mgrhpy755r14xMohPTEpkV/k28SJvuOs9bHRFW8x+KeDAEPiGQPB9Q==} - deprecated: This is a stub types definition. parse-path provides its own type definitions, so you do not need this installed. - '@types/pbf@3.0.5': resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} @@ -5773,12 +5757,6 @@ packages: engines: {node: '>=18'} hasBin: true - git-up@8.1.1: - resolution: {integrity: sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==} - - git-url-parse@16.1.0: - resolution: {integrity: sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==} - gl-matrix@3.4.4: resolution: {integrity: sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==} @@ -6426,9 +6404,6 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} - is-ssh@1.4.1: - resolution: {integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==} - is-stream@1.1.0: resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} engines: {node: '>=0.10.0'} @@ -7526,9 +7501,6 @@ packages: number-to-words@1.2.4: resolution: {integrity: sha512-/fYevVkXRcyBiZDg6yzZbm0RuaD6i0qRfn8yr+6D0KgBMOndFPxuW10qCHpzs50nN8qKuv78k8MuotZhcVX6Pw==} - numeral@2.0.6: - resolution: {integrity: sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==} - nunjucks@3.2.4: resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==} engines: {node: '>= 6.9.0'} @@ -7744,13 +7716,6 @@ packages: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} - parse-path@7.1.0: - resolution: {integrity: sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==} - - parse-url@9.2.0: - resolution: {integrity: sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==} - engines: {node: '>=14.13.0'} - parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -8263,9 +8228,6 @@ packages: protocol-buffers-schema@3.6.1: resolution: {integrity: sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==} - protocols@2.0.2: - resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -13969,14 +13931,8 @@ snapshots: '@types/normalize-package-data@2.4.4': {} - '@types/numeral@2.0.5': {} - '@types/parse-json@4.0.2': {} - '@types/parse-path@7.1.0': - dependencies: - parse-path: 7.1.0 - '@types/pbf@3.0.5': {} '@types/prismjs@1.26.6': {} @@ -17755,15 +17711,6 @@ snapshots: - conventional-commits-filter - conventional-commits-parser - git-up@8.1.1: - dependencies: - is-ssh: 1.4.1 - parse-url: 9.2.0 - - git-url-parse@16.1.0: - dependencies: - git-up: 8.1.1 - gl-matrix@3.4.4: {} glob-parent@5.1.2: @@ -18429,10 +18376,6 @@ snapshots: dependencies: call-bound: 1.0.4 - is-ssh@1.4.1: - dependencies: - protocols: 2.0.2 - is-stream@1.1.0: {} is-stream@2.0.1: {} @@ -19797,8 +19740,6 @@ snapshots: number-to-words@1.2.4: {} - numeral@2.0.6: {} - nunjucks@3.2.4(chokidar@3.6.0): dependencies: a-sync-waterfall: 1.0.1 @@ -20054,15 +19995,6 @@ snapshots: parse-node-version@1.0.1: {} - parse-path@7.1.0: - dependencies: - protocols: 2.0.2 - - parse-url@9.2.0: - dependencies: - '@types/parse-path': 7.1.0 - parse-path: 7.1.0 - parse5@7.3.0: dependencies: entities: 6.0.1 @@ -20537,8 +20469,6 @@ snapshots: protocol-buffers-schema@3.6.1: {} - protocols@2.0.2: {} - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx index 5d441171..d4d62a52 100644 --- a/src/components/Footer/index.tsx +++ b/src/components/Footer/index.tsx @@ -1,17 +1,22 @@ import { GithubOutlined } from '@ant-design/icons'; import { DefaultFooter } from '@ant-design/pro-components'; import packageJson from '@root/package.json'; -import GitUrlParse from 'git-url-parse'; import React from 'react'; const getRepoUrl = () => { if (!packageJson.repository) return 'https://github.com/ant-design/ant-design-pro'; - const parsed = GitUrlParse(packageJson.repository); - return `https://${parsed.source}/${parsed.owner}/${parsed.name}`; + const repo = + typeof packageJson.repository === 'string' + ? packageJson.repository + : (packageJson.repository as { url: string }).url; + // Parse git URLs like git@github.com:owner/name.git or https://github.com/owner/name.git + const match = repo.match(/github\.com[:/]([^/]+)\/([^/.]+)/); + if (!match) return 'https://github.com/ant-design/ant-design-pro'; + return `https://github.com/${match[1]}/${match[2]}`; }; -const REPO = getRepoUrl(); +const REPO_URL = getRepoUrl(); // Git commit hash, can be updated via CI/CD (GitHub Actions or Cloudflare Pages) const COMMIT_HASH = @@ -27,8 +32,8 @@ const Footer: React.FC = () => { links={[ { key: 'version', - title: `v${packageJson.version}`, - href: REPO, + title: `v${__APP_VERSION__}`, + href: REPO_URL, blankTarget: true, }, ...(COMMIT_HASH @@ -36,7 +41,7 @@ const Footer: React.FC = () => { { key: 'commit', title: COMMIT_HASH.slice(0, 7), - href: `${REPO}/commit/${COMMIT_HASH}`, + href: `${REPO_URL}/commit/${COMMIT_HASH}`, blankTarget: true, }, ] @@ -49,7 +54,7 @@ const Footer: React.FC = () => { Ant Design Pro ), - href: REPO, + href: REPO_URL, blankTarget: true, }, ]} diff --git a/src/pages/account/center/components/Applications/index.tsx b/src/pages/account/center/components/Applications/index.tsx index cb00aa78..b7100e42 100644 --- a/src/pages/account/center/components/Applications/index.tsx +++ b/src/pages/account/center/components/Applications/index.tsx @@ -6,8 +6,8 @@ import { } from '@ant-design/icons'; import { useQuery } from '@tanstack/react-query'; import { Avatar, Card, Dropdown, List, Tooltip } from 'antd'; -import numeral from 'numeral'; import React from 'react'; +import { formatNumber } from '@/utils/format'; import type { ListItemDataType } from '../../data.d'; import { queryFakeList } from '../../service'; import useStyles from './index.style'; @@ -123,7 +123,7 @@ const Applications: React.FC = () => {
diff --git a/src/pages/dashboard/analysis/components/Charts/index.tsx b/src/pages/dashboard/analysis/components/Charts/index.tsx index d9851aeb..d407c39b 100644 --- a/src/pages/dashboard/analysis/components/Charts/index.tsx +++ b/src/pages/dashboard/analysis/components/Charts/index.tsx @@ -1,13 +1,11 @@ -import numeral from 'numeral'; +import { formatYuan } from '@/utils/format'; import ChartCard from './ChartCard'; import Field from './Field'; -const yuan = (val: number | string) => `¥ ${numeral(val).format('0,0')}`; - const Charts = { - yuan, + yuan: formatYuan, ChartCard, Field, }; -export { ChartCard, Charts as default, Field, yuan }; +export { ChartCard, Charts as default, Field, formatYuan as yuan }; diff --git a/src/pages/dashboard/analysis/components/IntroduceRow.tsx b/src/pages/dashboard/analysis/components/IntroduceRow.tsx index 6e21f1f3..fe1031d3 100644 --- a/src/pages/dashboard/analysis/components/IntroduceRow.tsx +++ b/src/pages/dashboard/analysis/components/IntroduceRow.tsx @@ -1,7 +1,7 @@ import { InfoCircleOutlined } from '@ant-design/icons'; import { Area, Column } from '@ant-design/plots'; import { Col, Progress, Row, Tooltip } from 'antd'; -import numeral from 'numeral'; +import { formatNumber } from '@/utils/format'; import type { DataItem } from '../data.d'; import useStyles from '../style.style'; import Yuan from '../utils/Yuan'; @@ -39,12 +39,7 @@ const IntroduceRow = ({ } loading={loading} total={() => 126560} - footer={ - - } + footer={} contentHeight={46} > } - total={numeral(8846).format('0,0')} - footer={ - - } + total={formatNumber(8846)} + footer={} contentHeight={46} > } - total={numeral(6560).format('0,0')} + total={formatNumber(6560)} footer={} contentHeight={46} > diff --git a/src/pages/dashboard/analysis/components/ProportionSales.tsx b/src/pages/dashboard/analysis/components/ProportionSales.tsx index 4466481a..ae7fa1fc 100644 --- a/src/pages/dashboard/analysis/components/ProportionSales.tsx +++ b/src/pages/dashboard/analysis/components/ProportionSales.tsx @@ -1,7 +1,7 @@ import { Pie } from '@ant-design/plots'; import { Card, Segmented, Typography } from 'antd'; -import numeral from 'numeral'; import React from 'react'; +import { formatNumber } from '@/utils/format'; import type { DataItem } from '../data.d'; import useStyles from '../style.style'; @@ -58,7 +58,7 @@ const ProportionSales = ({ label={{ position: 'spider', text: (item: { x: number; y: number }) => - `${item.x}: ${numeral(item.y).format('0,0')}`, + `${item.x}: ${formatNumber(item.y)}`, }} /> diff --git a/src/pages/dashboard/analysis/components/SalesCard.tsx b/src/pages/dashboard/analysis/components/SalesCard.tsx index 31c10cde..00e0c32c 100644 --- a/src/pages/dashboard/analysis/components/SalesCard.tsx +++ b/src/pages/dashboard/analysis/components/SalesCard.tsx @@ -1,7 +1,7 @@ import { Column } from '@ant-design/plots'; import { Button, Card, Col, DatePicker, Row, Tabs } from 'antd'; import type { RangePickerProps } from 'antd/es/date-picker'; -import numeral from 'numeral'; +import { formatNumber } from '@/utils/format'; import type { DataItem } from '../data.d'; import useStyles from '../style.style'; @@ -147,7 +147,7 @@ const SalesCard = ({ > {item.title} - {numeral(item.total).format('0,0')} + {formatNumber(item.total)} ))} @@ -208,7 +208,7 @@ const SalesCard = ({ > {item.title} - {numeral(item.total).format('0,0')} + {formatNumber(item.total)} ))} diff --git a/src/pages/dashboard/analysis/components/TopSearch.tsx b/src/pages/dashboard/analysis/components/TopSearch.tsx index 2833b0a4..28e8b5a5 100644 --- a/src/pages/dashboard/analysis/components/TopSearch.tsx +++ b/src/pages/dashboard/analysis/components/TopSearch.tsx @@ -1,8 +1,8 @@ import { InfoCircleOutlined } from '@ant-design/icons'; import { Area } from '@ant-design/plots'; import { Card, Col, Row, Table, Tooltip } from 'antd'; -import numeral from 'numeral'; import React from 'react'; +import { formatNumber } from '@/utils/format'; import type { DataItem } from '../data.d'; import NumberInfo from './NumberInfo'; import Trend from './Trend'; @@ -105,7 +105,7 @@ const TopSearch = ({ } gap={8} - total={numeral(12321).format('0,0')} + total={formatNumber(12321)} status="up" subTotal={17.1} /> diff --git a/src/pages/dashboard/monitor/index.tsx b/src/pages/dashboard/monitor/index.tsx index ebf238ee..27997d86 100644 --- a/src/pages/dashboard/monitor/index.tsx +++ b/src/pages/dashboard/monitor/index.tsx @@ -1,14 +1,15 @@ import { Gauge, Liquid, WordCloud } from '@ant-design/plots'; import { GridContent } from '@ant-design/pro-components'; import { useQuery } from '@tanstack/react-query'; -import { Card, Col, Progress, Row, Statistic } from 'antd'; -import numeral from 'numeral'; -import type { FC } from 'react'; +import { Card, Col, Progress, Row, Spin, Statistic } from 'antd'; +import { type FC, lazy, Suspense } from 'react'; +import { formatNumber } from '@/utils/format'; import ActiveChart from './components/ActiveChart'; -import MonitorMap from './components/Map'; import { queryTags } from './service'; import useStyles from './style.style'; +const MonitorMap = lazy(() => import('./components/Map')); + const deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; // Moment is also OK const Monitor: FC = () => { @@ -43,7 +44,7 @@ const Monitor: FC = () => { @@ -61,12 +62,14 @@ const Monitor: FC = () => {
- + }> + +
diff --git a/src/pages/list/search/applications/index.tsx b/src/pages/list/search/applications/index.tsx index acbff65d..ca621436 100644 --- a/src/pages/list/search/applications/index.tsx +++ b/src/pages/list/search/applications/index.tsx @@ -16,10 +16,10 @@ import { Select, Tooltip, } from 'antd'; -import numeral from 'numeral'; import type { FC } from 'react'; import React from 'react'; import { StandardFormRow, TagSelect } from '@/components'; +import { formatNumber } from '@/utils/format'; import { categoryOptions } from '../../mock'; import type { ListItemDataType } from './data.d'; import { queryFakeList } from './service'; @@ -232,7 +232,7 @@ export const Applications: FC> = () => {
diff --git a/src/pages/user/login/__snapshots__/login.test.tsx.snap b/src/pages/user/login/__snapshots__/login.test.tsx.snap index e189dffb..7eb5afaf 100644 --- a/src/pages/user/login/__snapshots__/login.test.tsx.snap +++ b/src/pages/user/login/__snapshots__/login.test.tsx.snap @@ -473,7 +473,7 @@ exports[`Login Page should login success 1`] = ` target="_blank" title="version" > - v6.0.0-beta.4 + vtest - v6.0.0-beta.4 + vtest { + const parsed = Number(val); + return Number.isFinite(parsed) ? numberFormatter.format(parsed) : ''; +}; + +/** + * Format a number as yuan currency string. + * Replaces `¥ ${numeral(val).format('0,0')}` + */ +export const formatYuan = (val: number | string) => `¥ ${formatNumber(val)}`;