@oj-module/cli 0.2.64 → 0.2.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/devkit/README.md +9 -3
- package/devkit/SKILL.md +5 -2
- package/devkit/framework-dev.md +12 -7
- package/devkit/manual.md +123 -56
- package/devkit/menu-rules.md +4 -1
- package/package.json +3 -2
- package/shell-dist/assets/ahooks.2l850ymmh0.js +18 -0
- package/shell-dist/assets/antd-es-locale-zh_CN.1gjjsvxbf0.js +1 -0
- package/shell-dist/assets/antd-img-crop.196rkty480.js +99 -0
- package/shell-dist/assets/antd-locale-en_US.561tozx860.js +1 -0
- package/shell-dist/assets/antd-locale-zh_CN.1cmpmgzh70.js +1 -0
- package/shell-dist/assets/antd.uw1coq15l0.js +348 -0
- package/shell-dist/assets/clsx.jotilrt2e0.js +1 -0
- package/shell-dist/assets/contract-errors.2o17vz9u50.js +1 -0
- package/shell-dist/assets/contract.3h327o3mj0.js +57 -0
- package/shell-dist/assets/cssinjs.atgmhan7m0.js +3 -0
- package/shell-dist/assets/dayjs-plugin-advancedFormat.3vsyd2eis0.js +1 -0
- package/shell-dist/assets/dayjs-plugin-customParseFormat.13xhghv1d0.js +1 -0
- package/shell-dist/assets/dayjs-plugin-isoWeek.1fn1tw82p0.js +1 -0
- package/shell-dist/assets/dayjs-plugin-localeData.2rwbjp9nk0.js +1 -0
- package/shell-dist/assets/dayjs-plugin-quarterOfYear.2oqo1lcx80.js +1 -0
- package/shell-dist/assets/dayjs-plugin-relativeTime.2pqs3et4y0.js +1 -0
- package/shell-dist/assets/dayjs-plugin-weekOfYear.gvn9iph080.js +1 -0
- package/shell-dist/assets/dayjs-plugin-weekYear.2u78l3ex10.js +1 -0
- package/shell-dist/assets/dayjs-plugin-weekday.2d56a4tml0.js +1 -0
- package/shell-dist/assets/dayjs.pa60l6wjo0.js +1 -0
- package/shell-dist/assets/dnd-kit-core.1xyreig6r0.js +5 -0
- package/shell-dist/assets/dnd-kit-sortable.s94qciuft0.js +1 -0
- package/shell-dist/assets/dnd-kit-utilities.1umw4xphb0.js +1 -0
- package/shell-dist/assets/i18next.33zqofapj0.js +1 -0
- package/shell-dist/assets/icons-es-components-Context.365qmflwg0.js +1 -0
- package/shell-dist/assets/icons.159wjwals0.js +57 -0
- package/shell-dist/assets/jsx-dev-runtime.3uibuc82f0.js +14 -0
- package/shell-dist/assets/jsx-runtime.h40xu4o5b0.js +14 -0
- package/shell-dist/assets/keepalive-for-react.xenu5vam70.js +1 -0
- package/shell-dist/assets/kit.37kr8ui390.js +1 -0
- package/shell-dist/assets/ky.1cgch7gu60.js +6 -0
- package/shell-dist/assets/motion-react.pjsxytvjs0.js +12 -0
- package/shell-dist/assets/motion.21tciqutg0.js +4 -0
- package/shell-dist/assets/nprogress.2nz76n9ny0.js +7 -0
- package/shell-dist/assets/ojm-dayjs-locale-zh-cn.3vr3beiyp0.js +9 -0
- package/shell-dist/assets/pinyin-pro.3v0mnxczn0.js +1 -0
- package/shell-dist/assets/pro-components.2kyot1vcl0.js +83 -0
- package/shell-dist/assets/react-countup.2x8idnr8y0.js +10 -0
- package/shell-dist/assets/react-dom-client.ick0v05ob0.js +43 -0
- package/shell-dist/assets/react-dom.2so9uxg3f0.js +22 -0
- package/shell-dist/assets/react-error-boundary.2dncdfj3b0.js +1 -0
- package/shell-dist/assets/react-i18next.auhvjhqv00.js +1 -0
- package/shell-dist/assets/react-jss.1ei6dr9e00.js +29 -0
- package/shell-dist/assets/react-query.3rln45ow00.js +1 -0
- package/shell-dist/assets/react-router-dom.3c6zld8h40.js +44 -0
- package/shell-dist/assets/react-router.2h9rebcv50.js +56 -0
- package/shell-dist/assets/react.1ew63mwts0.js +14 -0
- package/shell-dist/assets/runtime.1xfsxcajj0.js +21702 -0
- package/shell-dist/assets/simplebar-react.2g739uvai0.js +1 -0
- package/shell-dist/assets/spin-delay.yjeyj6iwp0.js +9 -0
- package/shell-dist/assets/tailwind-merge.125ehiqjw0.js +1 -0
- package/shell-dist/assets/use-sync-external-store-shim.1nz1pi9bb0.js +22 -0
- package/shell-dist/assets/zustand-middleware.1xaxjueme0.js +6 -0
- package/shell-dist/assets/zustand-react-shallow.pybayv1hx0.js +1 -0
- package/shell-dist/assets/zustand-react.9fsl9brxy0.js +1 -0
- package/shell-dist/assets/zustand-shallow.6cz0yyv9x0.js +1 -0
- package/shell-dist/assets/zustand-vanilla-shallow.3424monv50.js +1 -0
- package/shell-dist/assets/zustand-vanilla.1mo3ka3g30.js +1 -0
- package/shell-dist/assets/zustand.3gjgzlnqo0.js +1 -0
- package/shell-dist/index.html +67 -118
- package/shell-dist/versions.json +3 -3
- package/src/esm-exports.ts +152 -70
- package/src/shared-deps.ts +69 -19
- package/src/site-base.ts +4 -0
- package/templates/src/app/web/home/pages/components/bar-chart.tsx +5 -3
- package/templates/src/app/web/home/pages/components/echarts-setup.ts +30 -0
- package/templates/src/app/web/home/pages/components/line-chart.tsx +5 -3
- package/templates/src/app/web/home/pages/components/pie-chart.tsx +6 -3
- package/templates/src/app/web/home/pages/index.tsx +3 -2
- package/templates/src/app/web/home/routes.ts +3 -2
- package/vendor/host-versions.json +3 -3
- package/shell-dist/assets/ahooks.js +0 -6909
- package/shell-dist/assets/antd-es-locale-zh_CN.js +0 -257
- package/shell-dist/assets/antd-img-crop.js +0 -1495
- package/shell-dist/assets/antd-locale-en_US.js +0 -374
- package/shell-dist/assets/antd-locale-zh_CN.js +0 -379
- package/shell-dist/assets/antd.js +0 -106874
- package/shell-dist/assets/clsx.js +0 -33
- package/shell-dist/assets/contract-errors.js +0 -30
- package/shell-dist/assets/contract.js +0 -18900
- package/shell-dist/assets/cssinjs.js +0 -2595
- package/shell-dist/assets/dayjs-plugin-advancedFormat.js +0 -98
- package/shell-dist/assets/dayjs-plugin-customParseFormat.js +0 -173
- package/shell-dist/assets/dayjs-plugin-isoWeek.js +0 -77
- package/shell-dist/assets/dayjs-plugin-localeData.js +0 -126
- package/shell-dist/assets/dayjs-plugin-quarterOfYear.js +0 -77
- package/shell-dist/assets/dayjs-plugin-relativeTime.js +0 -92
- package/shell-dist/assets/dayjs-plugin-weekOfYear.js +0 -73
- package/shell-dist/assets/dayjs-plugin-weekYear.js +0 -63
- package/shell-dist/assets/dayjs-plugin-weekday.js +0 -63
- package/shell-dist/assets/dayjs.js +0 -326
- package/shell-dist/assets/dnd-kit-core.js +0 -3601
- package/shell-dist/assets/dnd-kit-sortable.js +0 -717
- package/shell-dist/assets/dnd-kit-utilities.js +0 -340
- package/shell-dist/assets/i18next.js +0 -2321
- package/shell-dist/assets/icons-es-components-Context.js +0 -20
- package/shell-dist/assets/icons.js +0 -34961
- package/shell-dist/assets/jsx-dev-runtime.js +0 -75
- package/shell-dist/assets/jsx-runtime.js +0 -97
- package/shell-dist/assets/keepalive-for-react.js +0 -283
- package/shell-dist/assets/kit.js +0 -151
- package/shell-dist/assets/ky.js +0 -1427
- package/shell-dist/assets/motion-react.js +0 -13589
- package/shell-dist/assets/motion.js +0 -9959
- package/shell-dist/assets/nprogress.js +0 -314
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-BarsOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-CalendarOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-CaretDownFilled.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-CaretDownOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-CaretUpOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-CheckCircleFilled.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-CheckOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-ClockCircleOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-CloseCircleFilled.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-CloseOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-CopyOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-DeleteOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-DoubleLeftOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-DoubleRightOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-DownOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-DownloadOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-EditOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-EllipsisOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-EnterOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-ExclamationCircleFilled.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-EyeInvisibleOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-EyeOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-FileOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-FileTextOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-FilterFilled.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-FolderOpenOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-FolderOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-HolderOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-InfoCircleFilled.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-LeftOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-LoadingOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-MinusOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-MinusSquareOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-PaperClipOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-PictureOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-PlusOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-PlusSquareOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-QuestionCircleOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-ReloadOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-RightOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-RotateLeftOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-RotateRightOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-SearchOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-StarFilled.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-SwapOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-SwapRightOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-UpOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-VerticalAlignTopOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-WarningFilled.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-ZoomInOutlined.js +0 -7
- package/shell-dist/assets/ojm--ant-design-icons-es-icons-ZoomOutOutlined.js +0 -7
- package/shell-dist/assets/ojm-dayjs-locale-zh-cn.js +0 -81
- package/shell-dist/assets/pinyin-pro.js +0 -25175
- package/shell-dist/assets/pro-components.js +0 -44627
- package/shell-dist/assets/react-countup.js +0 -525
- package/shell-dist/assets/react-dom-client.js +0 -12134
- package/shell-dist/assets/react-dom.js +0 -266
- package/shell-dist/assets/react-error-boundary.js +0 -141
- package/shell-dist/assets/react-i18next.js +0 -1773
- package/shell-dist/assets/react-jss.js +0 -4089
- package/shell-dist/assets/react-query.js +0 -3072
- package/shell-dist/assets/react-router-dom.js +0 -9927
- package/shell-dist/assets/react-router.js +0 -14584
- package/shell-dist/assets/react.js +0 -590
- package/shell-dist/assets/runtime.js +0 -28311
- package/shell-dist/assets/simplebar-react.js +0 -1119
- package/shell-dist/assets/spin-delay.js +0 -111
- package/shell-dist/assets/tailwind-merge.js +0 -3364
- package/shell-dist/assets/use-sync-external-store-shim.js +0 -130
- package/shell-dist/assets/zustand-middleware.js +0 -513
- package/shell-dist/assets/zustand-react-shallow.js +0 -27
- package/shell-dist/assets/zustand-react.js +0 -39
- package/shell-dist/assets/zustand-shallow.js +0 -22
- package/shell-dist/assets/zustand-vanilla-shallow.js +0 -71
- package/shell-dist/assets/zustand-vanilla.js +0 -40
- package/shell-dist/assets/zustand.js +0 -32
- /package/shell-dist/assets/{index-xZhmujjM.js → index.i0kqbxp050.js} +0 -0
- /package/shell-dist/assets/{nprogress-css.js → nprogress-css.1cq2pzkre0.js} +0 -0
- /package/shell-dist/assets/{ojm-antd-es-button.js → ojm-antd-es-button.2uriphio50.js} +0 -0
- /package/shell-dist/assets/{ojm-antd-es-modal.js → ojm-antd-es-modal.bf3tgdh8v0.js} +0 -0
- /package/shell-dist/assets/{ojm-antd-es-slider.js → ojm-antd-es-slider.xyvptuhid0.js} +0 -0
- /package/shell-dist/assets/{ojm-antd-es-upload.js → ojm-antd-es-upload.13gx45e0g0.js} +0 -0
package/src/esm-exports.ts
CHANGED
|
@@ -14,14 +14,19 @@
|
|
|
14
14
|
* 本模块只做「扫描产物文本、回答谁导出/导入了什么」,不含修复逻辑,
|
|
15
15
|
* 供 shell 构建(门禁,失败即中断)与 tests/ 共用,避免两套正则漂移。
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
* `minify: false`
|
|
19
|
-
*
|
|
17
|
+
* 解析口径:`es-module-lexer` 真词法扫描,而非行首正则。
|
|
18
|
+
* 早先的实现假设「esbuild/vite 在 `minify: false` 下顶层语句一律顶格」,一旦
|
|
19
|
+
* 共享资产开启压缩(`minifyWhitespace` 会把 `export{a as b}` / `}from"react"`
|
|
20
|
+
* 挤成一行且行内任意位置),行首锚定的正则全部失配 → 门禁集体误报「零具名导出」
|
|
21
|
+
* 和「裸说明符未登记」。词法扫描只依赖语法、与压缩/换行无关,故换掉。
|
|
22
|
+
* 顺带消灭了「字符串字面量里恰好写了 import/from」的误报(原先靠行首锚定压制)。
|
|
20
23
|
*/
|
|
21
24
|
|
|
22
25
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
23
26
|
import { resolve } from "node:path";
|
|
24
27
|
|
|
28
|
+
import { ImportType, initSync, parse as lexModule } from "es-module-lexer";
|
|
29
|
+
|
|
25
30
|
/** 一个 ESM 文件的导出面 */
|
|
26
31
|
export interface EsmExports {
|
|
27
32
|
/** 静态具名导出(不含 `default`、不含 `export *` 透传的部分) */
|
|
@@ -56,22 +61,6 @@ export interface EsmImport {
|
|
|
56
61
|
needsDefault: boolean
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
/**
|
|
60
|
-
* `export { a, b as c }`(本地导出块)与 `export { a, b as c } from "x"`(再导出)
|
|
61
|
-
* 的公共部分:取出**对外暴露**的名字(`b as c` 取 `c`)。
|
|
62
|
-
*/
|
|
63
|
-
function exportedNamesFromClause(clause: string): string[] {
|
|
64
|
-
return clause
|
|
65
|
-
.split(",")
|
|
66
|
-
.map(part => part.trim())
|
|
67
|
-
.filter(Boolean)
|
|
68
|
-
.map((part) => {
|
|
69
|
-
const as = part.split(/\s+as\s+/);
|
|
70
|
-
return (as[as.length - 1] ?? part).trim();
|
|
71
|
-
})
|
|
72
|
-
.filter(name => name !== "default");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
64
|
/**
|
|
76
65
|
* `import { a, b as c }` 中被**请求**的名字。
|
|
77
66
|
*
|
|
@@ -88,51 +77,75 @@ function importedNamesFromClause(clause: string): string[] {
|
|
|
88
77
|
.filter(name => name !== "default");
|
|
89
78
|
}
|
|
90
79
|
|
|
80
|
+
/** wasm 实例化只需一次;按需初始化,避免「只是 import 一下」的消费方付启动开销 */
|
|
81
|
+
let lexReady = false;
|
|
82
|
+
function lex(source: string): ReturnType<typeof lexModule> {
|
|
83
|
+
if (!lexReady) {
|
|
84
|
+
initSync();
|
|
85
|
+
lexReady = true;
|
|
86
|
+
}
|
|
87
|
+
return lexModule(source);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** 语句文本;`ss`/`se` 是 lexer 给出的整条语句区间(含分号) */
|
|
91
|
+
function statementAt(source: string, ss: number, se: number): string {
|
|
92
|
+
return source.slice(ss, se);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 从一条 `import … from "x"` / `export … from "x"` 语句里分出关键字与子句。
|
|
97
|
+
*
|
|
98
|
+
* 语句边界已由 lexer 确定,这里只处理语句内部的切片,因此不再需要行首锚定,
|
|
99
|
+
* 压缩后(`import{a as b}from"react"`)同样成立。
|
|
100
|
+
*/
|
|
101
|
+
function clauseOf(statement: string): { keyword: "import" | "export", clause: string } | undefined {
|
|
102
|
+
const head = /^\s*(import|export)\b/.exec(statement);
|
|
103
|
+
if (!head)
|
|
104
|
+
return undefined;
|
|
105
|
+
const rest = statement.slice(head[0].length);
|
|
106
|
+
// `from` 后必须紧跟说明符字符串,才不会误取子句里的同名标识符
|
|
107
|
+
const fromIdx = rest.search(/\bfrom\s*["']/);
|
|
108
|
+
if (fromIdx < 0)
|
|
109
|
+
return undefined;
|
|
110
|
+
return { keyword: head[1] as "import" | "export", clause: rest.slice(0, fromIdx) };
|
|
111
|
+
}
|
|
112
|
+
|
|
91
113
|
/** 解析产物的静态导出面 */
|
|
92
114
|
export function parseEsmExports(source: string): EsmExports {
|
|
115
|
+
const [imports, exports] = lex(source);
|
|
93
116
|
const names = new Set<string>();
|
|
117
|
+
let hasDefault = false;
|
|
94
118
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
for (const clause of clauses) {
|
|
102
|
-
for (const name of exportedNamesFromClause(clause))
|
|
103
|
-
names.add(name);
|
|
119
|
+
for (const exp of exports) {
|
|
120
|
+
if (exp.n === "default")
|
|
121
|
+
hasDefault = true;
|
|
122
|
+
else
|
|
123
|
+
names.add(exp.n);
|
|
104
124
|
}
|
|
105
125
|
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
126
|
+
// `export * from "x"` 不产生具名导出(静态不可展开),lexer 也不把它列进 exports,
|
|
127
|
+
// 只能从「语句以 export 开头、星号之后不带 as」反推。
|
|
128
|
+
// `export * as ns from "x"` 是有名字的导出(ns),导出面仍可静态确定,不算在内。
|
|
129
|
+
const hasStarReexport = imports.some((imp) => {
|
|
130
|
+
if (imp.t !== ImportType.Static || imp.ss < 0)
|
|
131
|
+
return false;
|
|
132
|
+
return /^export\s*\*(?!\s*as\b)/.test(statementAt(source, imp.ss, imp.se));
|
|
133
|
+
});
|
|
110
134
|
|
|
111
|
-
|
|
112
|
-
// (esbuild 产出的正是后者,形如 `rad_shim_xxx_default as default`)
|
|
113
|
-
const hasDefaultClause = clauses.some(clause => clause
|
|
114
|
-
.split(",")
|
|
115
|
-
.map(part => part.trim())
|
|
116
|
-
.some(part => /\bas\s+default$/.test(part)));
|
|
117
|
-
|
|
118
|
-
return {
|
|
119
|
-
names,
|
|
120
|
-
hasDefault: /^export\s+default\b/m.test(source) || hasDefaultClause,
|
|
121
|
-
hasStarReexport: /^export\s*\*/m.test(source),
|
|
122
|
-
};
|
|
135
|
+
return { names, hasDefault, hasStarReexport };
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
/**
|
|
126
139
|
* 解析产物消费了哪些说明符的哪些具名导出。
|
|
127
140
|
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* `export { a } from "x"`(再导出同样是消费)。
|
|
141
|
+
* 覆盖:`import { a, b as c } from "x"`、`import X, { a } from "x"`、
|
|
142
|
+
* `export { a } from "x"`(再导出同样是消费)。
|
|
131
143
|
*
|
|
132
144
|
* 不覆盖:`import * as ns from "x"`、动态 `import("x")` 后取属性——
|
|
133
145
|
* 这些都拿不到具名绑定,无从校验。
|
|
134
146
|
*/
|
|
135
147
|
export function parseEsmImports(source: string): EsmImport[] {
|
|
148
|
+
const [imports] = lex(source);
|
|
136
149
|
const found = new Map<string, { names: Set<string>, needsDefault: boolean }>();
|
|
137
150
|
|
|
138
151
|
const slot = (specifier: string) => {
|
|
@@ -144,25 +157,30 @@ export function parseEsmImports(source: string): EsmImport[] {
|
|
|
144
157
|
return entry;
|
|
145
158
|
};
|
|
146
159
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
160
|
+
for (const imp of imports) {
|
|
161
|
+
// 动态 import / import.meta 不带静态具名绑定
|
|
162
|
+
if (imp.t !== ImportType.Static || imp.ss < 0 || !imp.n)
|
|
163
|
+
continue;
|
|
164
|
+
const parsed = clauseOf(statementAt(source, imp.ss, imp.se));
|
|
165
|
+
if (!parsed)
|
|
166
|
+
continue;
|
|
153
167
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
168
|
+
const entry = slot(imp.n);
|
|
169
|
+
const brace = /\{([^}]*)\}/.exec(parsed.clause);
|
|
170
|
+
if (brace) {
|
|
171
|
+
for (const name of importedNamesFromClause(brace[1] ?? ""))
|
|
172
|
+
entry.names.add(name);
|
|
173
|
+
}
|
|
160
174
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
175
|
+
// default 导入:子句去掉 `{…}` 后仍剩标识符(`X` / `X,`)。
|
|
176
|
+
// `* as ns` 是命名空间导入,不消费 default。
|
|
177
|
+
// 不能假定它一定可用——只有 default 的包若 shim 没兜住,浏览器同样是
|
|
178
|
+
// "does not provide an export named 'default'"。
|
|
179
|
+
if (parsed.keyword === "import") {
|
|
180
|
+
const head = parsed.clause.replace(/\{[^}]*\}/g, "").trim();
|
|
181
|
+
if (head && !head.startsWith("*"))
|
|
182
|
+
entry.needsDefault = true;
|
|
183
|
+
}
|
|
166
184
|
}
|
|
167
185
|
|
|
168
186
|
return [...found].map(([specifier, entry]) => ({
|
|
@@ -233,24 +251,88 @@ export function collectDynamicRequires(distDir: string): DynamicRequireHit[] {
|
|
|
233
251
|
}
|
|
234
252
|
|
|
235
253
|
/**
|
|
236
|
-
*
|
|
254
|
+
* 产物引用的全部裸说明符(静态/副作用 import、`import("x")`、再导出)。
|
|
237
255
|
*
|
|
238
256
|
* 浏览器只能解析 importmap 里登记过的裸说明符,漏一个就是
|
|
239
257
|
* `Failed to resolve module specifier` 白屏。
|
|
240
258
|
*/
|
|
241
259
|
export function parseBareSpecifiers(source: string): string[] {
|
|
260
|
+
const [imports] = lex(source);
|
|
242
261
|
const found = new Set<string>();
|
|
243
|
-
//
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
262
|
+
// lexer 已给出每条语句的说明符原文;非字符串字面量(`import(x)`)为 undefined,跳过
|
|
263
|
+
for (const imp of imports) {
|
|
264
|
+
const spec = imp.n;
|
|
265
|
+
if (!spec)
|
|
266
|
+
continue;
|
|
267
|
+
if (spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("data:") || spec.startsWith("http"))
|
|
248
268
|
continue;
|
|
249
269
|
found.add(spec);
|
|
250
270
|
}
|
|
251
271
|
return [...found];
|
|
252
272
|
}
|
|
253
273
|
|
|
274
|
+
/**
|
|
275
|
+
* 产物的**静态**依赖说明符:`import … from "x"`、副作用 `import "x"`、再导出。
|
|
276
|
+
*
|
|
277
|
+
* 与 {@link parseBareSpecifiers} 的差别有两点,都是为了算「首屏静态闭包」:
|
|
278
|
+
* - **排除动态 `import("x")`**:那是懒加载,不在首屏关键路径上,预取它会白拉;
|
|
279
|
+
* - **保留相对/绝对路径**:闭包要顺着 `/assets/x.hash.js` 继续走,不能只看裸名。
|
|
280
|
+
*
|
|
281
|
+
* 静态图的切分口径与浏览器一致(缓存模块记录前先取完整静态图),所以这里能算出
|
|
282
|
+
* 「浏览器一定会请求的最小集合」。
|
|
283
|
+
*/
|
|
284
|
+
export function parseStaticSpecifiers(source: string): string[] {
|
|
285
|
+
const [imports] = lex(source);
|
|
286
|
+
const found = new Set<string>();
|
|
287
|
+
for (const imp of imports) {
|
|
288
|
+
// d === -1 才是静态导入;`import("x")` 的 d 是 `(` 的偏移
|
|
289
|
+
if (imp.d !== -1 || !imp.n)
|
|
290
|
+
continue;
|
|
291
|
+
found.add(imp.n);
|
|
292
|
+
}
|
|
293
|
+
return [...found];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* 首屏静态依赖闭包:从入口出发,顺着**静态** import 一直走到没得走。
|
|
298
|
+
*
|
|
299
|
+
* 这就是浏览器一定会请求的集合(ESM 语义:先取完整静态图再执行),所以可以放心
|
|
300
|
+
* 全量预取;动态 `import()` 不在其中。裸说明符经 importmap 解析,相对路径按当前
|
|
301
|
+
* 文件所在目录拼。
|
|
302
|
+
*
|
|
303
|
+
* `readAsset` 返回 undefined 表示读不到(跨源 CDN 资产、或缺失文件):该 URL 仍算
|
|
304
|
+
* 闭包成员(预取它对浏览器有效),但不再往下展开。
|
|
305
|
+
*
|
|
306
|
+
* 与构建脚本共用同一份实现,是为了让测试能重算一遍对撞产物——两套实现必然漂移。
|
|
307
|
+
*/
|
|
308
|
+
export function collectStaticClosure(
|
|
309
|
+
entryUrl: string,
|
|
310
|
+
importmap: Record<string, string>,
|
|
311
|
+
readAsset: (url: string) => string | undefined,
|
|
312
|
+
): string[] {
|
|
313
|
+
const seen = new Set<string>();
|
|
314
|
+
const queue = [entryUrl];
|
|
315
|
+
while (queue.length) {
|
|
316
|
+
const url = queue.shift()!;
|
|
317
|
+
if (seen.has(url))
|
|
318
|
+
continue;
|
|
319
|
+
seen.add(url);
|
|
320
|
+
const source = readAsset(url);
|
|
321
|
+
if (source === undefined)
|
|
322
|
+
continue;
|
|
323
|
+
for (const spec of parseStaticSpecifiers(source)) {
|
|
324
|
+
const target = spec.startsWith("/")
|
|
325
|
+
? spec
|
|
326
|
+
: spec.startsWith(".")
|
|
327
|
+
? resolve("/", url.slice(0, url.lastIndexOf("/") + 1), spec)
|
|
328
|
+
: importmap[spec];
|
|
329
|
+
if (target)
|
|
330
|
+
queue.push(target);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return [...seen];
|
|
334
|
+
}
|
|
335
|
+
|
|
254
336
|
/** 一处「资产引用了 importmap 未登记的裸说明符」 */
|
|
255
337
|
export interface UnresolvedSpecifier {
|
|
256
338
|
file: string
|
package/src/shared-deps.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* 共享依赖表 —— 单一常量源(设计文档 §4.3,解决 B11 / B12)。
|
|
3
5
|
*
|
|
@@ -21,15 +23,18 @@ export interface SharedDepEntry {
|
|
|
21
23
|
/** 硬共享:模块不得自带 */
|
|
22
24
|
hard: boolean
|
|
23
25
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
26
|
+
* 模块自打包:宿主 shell 不预构建该资产、importmap 不列该键,模块若 import 它
|
|
27
|
+
* 则自行打包进模块产物(设计文档 §4.3 的「软共享缺席→模块自带副本兜底」语义)。
|
|
28
|
+
* 用于**仅模块使用、宿主与共享 chunk 永不 import**的重型依赖(编辑器 / 图表 /
|
|
29
|
+
* Markdown),避免把它们 5~6MB 的体量无谓铺进 shell-dist 并要求公开链路多传
|
|
30
|
+
* 一堆文件。宿主侧有真实 import 的共享依赖(antd / pro-components / icons 内部
|
|
31
|
+
* 依赖的 motion / react-jss / dayjs / zustand / @dnd-kit 等)绝不能标 bundle ——
|
|
32
|
+
* 否则会被 antd 等共享 chunk 经 importmap 解析不到而 404。判定依据:宿主
|
|
33
|
+
* host.tsx + runtime.js 的传递 import 图,以及 antd/pro-components/icons 的
|
|
34
|
+
* 传递依赖图,都不含这些说明符。
|
|
35
|
+
*
|
|
36
|
+
* ⚠️ 本档位**不计入宿主版本一致性保障**:模块把副本打进产物,多副本不会报错,
|
|
37
|
+
* 只会重复体积。体积怎么控,见 docs/devkit/manual.md §2.6。
|
|
33
38
|
*/
|
|
34
39
|
bundle?: boolean
|
|
35
40
|
}
|
|
@@ -66,9 +71,10 @@ export const SHARED_DEPS: SharedDepEntry[] = [
|
|
|
66
71
|
* - 无单例语义。kit 必须唯一是因为多副本 = 两份 antd 上下文树;编辑器资产
|
|
67
72
|
* 把 @tiptap/*、@plane/ui 等**全部内联**在自身里,跨边界穿过的只有 React
|
|
68
73
|
* 家族(那是独立的硬共享条目),多一份编辑器副本不会拆散任何 context。
|
|
69
|
-
* -
|
|
70
|
-
*
|
|
71
|
-
*
|
|
74
|
+
* - 不是每个模块都用编辑器。软共享的语义是「允许缺席」——宿主**不预构建**
|
|
75
|
+
* 这份资产(bundle: true,不进 shell-dist、不进 importmap),模块 import 它
|
|
76
|
+
* 就自己打进产物。代价是每个用编辑器的模块各带一份约 5.4 MB,换来宿主
|
|
77
|
+
* 分发体积不被没人用的重型依赖撑大。
|
|
72
78
|
*/
|
|
73
79
|
{ specifier: "@plane/editor", asset: "editor", hard: false, bundle: true },
|
|
74
80
|
// 注:@rc-component/form(antd 6 Form 底层)曾尝试单例化以修 my-profile
|
|
@@ -120,6 +126,9 @@ export const SHARED_DEPS: SharedDepEntry[] = [
|
|
|
120
126
|
{ specifier: "dayjs/plugin/weekday", asset: "dayjs-plugin-weekday", hard: false },
|
|
121
127
|
{ specifier: "dayjs/plugin/weekOfYear", asset: "dayjs-plugin-weekOfYear", hard: false },
|
|
122
128
|
{ specifier: "dayjs/plugin/weekYear", asset: "dayjs-plugin-weekYear", hard: false },
|
|
129
|
+
// echarts 家族:模块自打包。整包 index(`import * as echarts from "echarts"`)会让
|
|
130
|
+
// 单个模块产物从 ~180KB 涨到 1.7MB(实测 echarts 918KB + zrender 221KB 占 87%),
|
|
131
|
+
// 故脚手架改用 `echarts/core` 按需注册;接入方写法见 docs/devkit/manual.md §2.6。
|
|
123
132
|
{ specifier: "echarts", asset: "echarts", hard: false, bundle: true },
|
|
124
133
|
{ specifier: "echarts/charts", asset: "echarts-charts", hard: false, bundle: true },
|
|
125
134
|
{ specifier: "echarts/features.js", asset: "echarts-features", hard: false, bundle: true },
|
|
@@ -147,18 +156,21 @@ export const SHARED_DEPS: SharedDepEntry[] = [
|
|
|
147
156
|
{ specifier: "tailwind-merge", asset: "tailwind-merge", hard: false },
|
|
148
157
|
/**
|
|
149
158
|
* Markdown 编辑器(Vditor v4,M5 回升自下游 oj-wiki):npm 包是 webpack **UMD**
|
|
150
|
-
* 单产物(main=dist/index.js,无 ESM 出口、仅 default
|
|
151
|
-
*
|
|
159
|
+
* 单产物(main=dist/index.js,无 ESM 出口、仅 default 导出)。bundle: true 表示
|
|
160
|
+
* 宿主不预构建 —— CJS/UMD interop 交给模块自己的 rolldown 打包链路处理。
|
|
152
161
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
162
|
+
* 为什么不预构建:体积大(gzip ≈700 KiB)且不是每个模块都用。宿主为它留一份
|
|
163
|
+
* /assets/vditor.js,等于给所有站点无条件加 700 KiB 分发体积,而只有编辑器页
|
|
164
|
+
* 才用得上。改由模块自带后,代价转给「真正 import 它的那个模块」。
|
|
165
|
+
*
|
|
166
|
+
* 副作用(写文档时容易说错):模块产物是单文件(codeSplitting: false),
|
|
167
|
+
* 所以 `import("vditor")` 会被内联回去,**动态导入并不能把它从首屏摘掉**;
|
|
168
|
+
* 要省这笔体积只能把编辑器页拆成独立模块/方案。
|
|
157
169
|
*
|
|
158
170
|
* 深路径只登记 CSS 主样式(nprogress 同款样式垫片)。vditor 其余 dist 深路径
|
|
159
171
|
* (lute / i18n / icons / 主题 CSS…)是**运行期经 cdn 选项按需拉取的资源**而非
|
|
160
172
|
* import 说明符,由模块侧自行处理(自注入或指向宿主可服务的路径);若模块代码
|
|
161
|
-
* 直接 import 它们,会命中前缀 external
|
|
173
|
+
* 直接 import 它们,会命中前缀 external 但无共享表键 → 构建期深路径报错,
|
|
162
174
|
* 属预期拦截(与 dayjs/plugin/* 同规则)。
|
|
163
175
|
*/
|
|
164
176
|
{ specifier: "vditor", asset: "vditor", hard: false, bundle: true },
|
|
@@ -182,6 +194,10 @@ export function generateShellEntries(): { name: string, pkg: string }[] {
|
|
|
182
194
|
/**
|
|
183
195
|
* 由共享表生成 importmap:说明符 → /assets/<asset>.js。
|
|
184
196
|
* baseUrl 供宿主部署在子路径时使用。
|
|
197
|
+
*
|
|
198
|
+
* 注意:这里给出的是**逻辑名**。shell 构建落盘时会把每个资产改名成
|
|
199
|
+
* `<asset>.<hash>.js`(见 `hashedAssetFileName`),importmap 由构建脚本同步改写,
|
|
200
|
+
* 运行时拿到的仍是 `/assets/<asset>.<hash>.js`。
|
|
185
201
|
*/
|
|
186
202
|
export function generateImportmap(baseUrl = ""): Record<string, string> {
|
|
187
203
|
const map: Record<string, string> = {};
|
|
@@ -196,3 +212,37 @@ export function generateImportmap(baseUrl = ""): Record<string, string> {
|
|
|
196
212
|
export function isPrebuiltDep(id: string): boolean {
|
|
197
213
|
return SHARED_DEPS.some(dep => !dep.bundle && (id === dep.specifier || id.startsWith(`${dep.specifier}/`)));
|
|
198
214
|
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* 共享资产的内容哈希段:10 位 base36,且**保证**同时含数字与字母。
|
|
218
|
+
*
|
|
219
|
+
* 为什么必须保证:oj serve ≥ 0.1.116 的默认缓存策略按**文件名**判定
|
|
220
|
+
* (`serve/src/static_files.rs::default_cache_control`)——文件名 stem 按 `-` `_` `.`
|
|
221
|
+
* 切段,末段 ≥8 位且同时含数字与字母才发 `public, max-age=31536000, immutable`,
|
|
222
|
+
* 其余一律 `no-cache`。纯 base36 有十万分之一量级会全数字(vite 的 base64url 更糟:
|
|
223
|
+
* 8 位全字母约 19%),漏判就白丢一年缓存。这里按「缺哪类补哪类」定长补齐,
|
|
224
|
+
* 让每个资产 100% 命中长缓存,而不是赌概率。
|
|
225
|
+
*
|
|
226
|
+
* 9 位 base36 ≈ 46.5 bit,65 个资产量级碰撞概率可忽略。
|
|
227
|
+
*/
|
|
228
|
+
export function assetHash(content: string | Uint8Array): string {
|
|
229
|
+
const digest = createHash("sha256").update(content).digest();
|
|
230
|
+
const body = digest.readBigUInt64BE(0).toString(36).slice(0, 9).padStart(9, "0");
|
|
231
|
+
// 已有字母 → 补数字;全数字 → 补字母。两类必在其一,补齐另一类即可。
|
|
232
|
+
return /[a-z]/.test(body) ? `${body}0` : `${body}z`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** 内容寻址文件名:`<base>.<hash>.js`(js 与 map 同为 .js 后缀,map 保持原名不动) */
|
|
236
|
+
export function hashedAssetFileName(base: string, content: string | Uint8Array): string {
|
|
237
|
+
return `${base}.${assetHash(content)}.js`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 与 oj serve 的 `default_cache_control` 同口径:末段 ≥8 位且数字字母都有 → 可发 immutable。
|
|
242
|
+
* 构建期用它断言产物名,避免哪天哈希算法换掉后长缓存静默失效。
|
|
243
|
+
*/
|
|
244
|
+
export function isImmutableAssetFileName(fileName: string): boolean {
|
|
245
|
+
const stem = fileName.replace(/\.[^.]*$/, "");
|
|
246
|
+
const seg = stem.split(/[-_.]/).pop() ?? "";
|
|
247
|
+
return seg.length >= 8 && /\d/.test(seg) && /[a-z]/i.test(seg);
|
|
248
|
+
}
|
package/src/site-base.ts
CHANGED
|
@@ -102,6 +102,10 @@ export function rewriteIndexHtml(html: string, siteBase: string | undefined, api
|
|
|
102
102
|
// 上一步已处理,二者不重叠。
|
|
103
103
|
out = out.replace(/(\b(?:href|src|data-ojm-entry)=")(\/[^/"][^"]*|\/")/g, (_m, attr: string, url: string) =>
|
|
104
104
|
`${attr}${withSiteBase(url, base)}`);
|
|
105
|
+
// data-ojm-preload 是**逗号分隔的 URL 列表**(构建期算好的首屏静态闭包),
|
|
106
|
+
// 上面那条单值正则匹配不到列表,漏改会让子路径部署下预取全 404(退化回瀑布,不白屏但慢)
|
|
107
|
+
out = out.replace(/(\bdata-ojm-preload=")([^"]*)"/g, (_m, attr: string, list: string) =>
|
|
108
|
+
`${attr}${list.split(",").map(url => url.startsWith("/") ? withSiteBase(url, base) : url).join(",")}"`);
|
|
105
109
|
globals.push(`window.__OJ_BASE__=${JSON.stringify(base)};`);
|
|
106
110
|
}
|
|
107
111
|
if (api) {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { EChartsOption } from "echarts";
|
|
2
2
|
import { Card } from "antd";
|
|
3
|
-
import
|
|
3
|
+
import ReactEChartsCore from "echarts-for-react/esm/core";
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import { echarts } from "./echarts-setup";
|
|
7
|
+
|
|
8
|
+
/** 柱状图:按需注册的 `echarts` + `echarts-for-react/esm/core`(见 echarts-setup.ts)。 */
|
|
7
9
|
export default function BarChart() {
|
|
8
10
|
const { t } = useTranslation();
|
|
9
11
|
const categories = [
|
|
@@ -25,7 +27,7 @@ export default function BarChart() {
|
|
|
25
27
|
};
|
|
26
28
|
return (
|
|
27
29
|
<Card title={t("home:views")}>
|
|
28
|
-
<
|
|
30
|
+
<ReactEChartsCore echarts={echarts} opts={{ height: 320, width: "auto" }} option={option} />
|
|
29
31
|
</Card>
|
|
30
32
|
);
|
|
31
33
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 按需注册的 echarts 实例(体积治理)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么不用 `import ReactECharts from "echarts-for-react"`:
|
|
5
|
+
* 那条路径会 `import * as echarts from "echarts"`(整包 index),把 **全部图表类型 +
|
|
6
|
+
* 全部组件 + 全部渲染器** 打进模块产物。实测 `app` 模块 entry.js 1,697,666 B 中
|
|
7
|
+
* echarts 918 KB + zrender 221 KB,占 **87%**;而首页只用到折线/柱状/饼图三种。
|
|
8
|
+
*
|
|
9
|
+
* 这里改用 `echarts/core` 按需注册:只留 3 种图表 + 3 个组件 + Canvas 渲染器,
|
|
10
|
+
* 同一份代码实测 1,125 KB → 572 KB(−49%)。
|
|
11
|
+
*
|
|
12
|
+
* 新图表类型/组件时,务必在这里 `use()` 补上——否则运行期渲染为空且**不报错**,
|
|
13
|
+
* 是最常见的 echarts 按需踩坑。
|
|
14
|
+
*/
|
|
15
|
+
import { BarChart, LineChart, PieChart } from "echarts/charts";
|
|
16
|
+
import { GridComponent, LegendComponent, TooltipComponent } from "echarts/components";
|
|
17
|
+
import * as echarts from "echarts/core";
|
|
18
|
+
import { CanvasRenderer } from "echarts/renderers";
|
|
19
|
+
|
|
20
|
+
echarts.use([
|
|
21
|
+
BarChart,
|
|
22
|
+
LineChart,
|
|
23
|
+
PieChart,
|
|
24
|
+
GridComponent,
|
|
25
|
+
LegendComponent,
|
|
26
|
+
TooltipComponent,
|
|
27
|
+
CanvasRenderer,
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
export { echarts };
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { EChartsOption } from "echarts";
|
|
2
2
|
import { Card, Radio } from "antd";
|
|
3
3
|
import dayjs from "dayjs";
|
|
4
|
-
import
|
|
4
|
+
import ReactEChartsCore from "echarts-for-react/esm/core";
|
|
5
5
|
import { useMemo, useState } from "react";
|
|
6
6
|
import { useTranslation } from "react-i18next";
|
|
7
7
|
|
|
8
|
+
import { echarts } from "./echarts-setup";
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
|
-
*
|
|
11
|
+
* 折线图:按需注册的 `echarts` + `echarts-for-react/esm/core`(见 echarts-setup.ts)。
|
|
10
12
|
* 数据为静态演示值——真实业务请走模块契约 + `ojm api` 生成的 client
|
|
11
13
|
* (参考 `demo` 模块的裸 fetch 与教程里 books 模块的契约式接法)。
|
|
12
14
|
*/
|
|
@@ -69,7 +71,7 @@ export default function LineChart() {
|
|
|
69
71
|
</Radio.Group>
|
|
70
72
|
)}
|
|
71
73
|
>
|
|
72
|
-
<
|
|
74
|
+
<ReactEChartsCore echarts={echarts} opts={{ height: 320, width: "auto" }} option={option} />
|
|
73
75
|
</Card>
|
|
74
76
|
);
|
|
75
77
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { EChartsOption } from "echarts";
|
|
2
2
|
import { Card, Segmented } from "antd";
|
|
3
|
-
import
|
|
3
|
+
import ReactEChartsCore from "echarts-for-react/esm/core";
|
|
4
4
|
import { useMemo, useState } from "react";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
|
|
7
|
+
import { echarts } from "./echarts-setup";
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
10
|
+
* 饼图:按需注册的 `echarts` + `echarts-for-react/esm/core` + antd `Segmented` 联动
|
|
11
|
+
* (注册清单见 echarts-setup.ts)。
|
|
9
12
|
* 数据为静态演示值(各渠道 × 品类)。
|
|
10
13
|
*/
|
|
11
14
|
const VALUES: Record<string, number[]> = {
|
|
@@ -59,7 +62,7 @@ export default function PieChart() {
|
|
|
59
62
|
/>
|
|
60
63
|
)}
|
|
61
64
|
>
|
|
62
|
-
<
|
|
65
|
+
<ReactEChartsCore echarts={echarts} opts={{ height: 320, width: "auto" }} option={option} />
|
|
63
66
|
</Card>
|
|
64
67
|
);
|
|
65
68
|
}
|
|
@@ -19,8 +19,9 @@ const wrapperCol: ColProps = {
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* 首页:结构对齐 playground home,用自带的统计卡片与三类图表
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* 演示依赖矩阵(react-countup / dayjs / antd / @ant-design/icons / react-i18next
|
|
23
|
+
* 由宿主 importmap 单例提供;echarts 由模块自打包并按需注册,
|
|
24
|
+
* 见 `./components/echarts-setup.ts`)。
|
|
24
25
|
*/
|
|
25
26
|
export default function HomePage() {
|
|
26
27
|
return (
|
|
@@ -14,8 +14,9 @@ const Home = lazy(() => import("./pages/index"));
|
|
|
14
14
|
* 工程缺 `/home` 路由时这些跳转会落到错误边界。
|
|
15
15
|
*
|
|
16
16
|
* 结构对齐 playground-oj/web/src/home;页面用统计卡片 + 折线/柱/饼图
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* 演示依赖矩阵(react-countup / dayjs / antd / @ant-design/icons / react-i18next
|
|
18
|
+
* 由宿主 importmap 提供单例;echarts 属模块自打包的重型依赖,走按需注册,
|
|
19
|
+
* 见 `pages/components/echarts-setup.ts`)。
|
|
19
20
|
* 图表数据为静态演示值——真实业务走模块契约 + `ojm api` 生成的 client。
|
|
20
21
|
*/
|
|
21
22
|
export const routes: AppRouteRecordRaw[] = [
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"react-router": "7.18.2",
|
|
9
9
|
"react-router/dom": "7.18.2",
|
|
10
10
|
"@tanstack/react-query": "5.102.8",
|
|
11
|
-
"@oj-module/runtime": "0.2.
|
|
12
|
-
"@oj-module/runtime/contract": "0.2.
|
|
13
|
-
"@oj-module/runtime/contract/errors": "0.2.
|
|
11
|
+
"@oj-module/runtime": "0.2.66",
|
|
12
|
+
"@oj-module/runtime/contract": "0.2.66",
|
|
13
|
+
"@oj-module/runtime/contract/errors": "0.2.66",
|
|
14
14
|
"@plane/kit": "0.1.20",
|
|
15
15
|
"@plane/editor": "0.1.20",
|
|
16
16
|
"antd": "6.6.1",
|