mermaid 换成 obsidianmd/pele:同一套 Mermaid 语法、同步渲染、没有依赖。 库里 2170 张图(题目参考图 36、学生提交 2134)两边逐张对过,能画的和报错的完全一致。 配色按 pele 的 DOM 重写选择器,颜色不变;版本锁死在 1.6.0。 顺带按 modernPolyfills: true 重新探测了 polyfill 清单(50 项),并改正注释里 「DEBUG 会打印全集」的说法 —— 写死清单时它只回显清单。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a1d14a06bc
commit
38360e8668
6 files changed
+78
-471
No files matched your search
+1
-1
@@ -59,7 +59,7 @@ API 调用不按模块分:学生端全在 `oj/api.ts`、后台全在 `admin/ap
|
||||
|
||||
Shared logic lives in `shared/`:
|
||||
- `store/` — Pinia stores: `user` (auth/roles), `config` (site-wide settings), `authModal` (登录框、注册框开没开), `collab` (help-request queue + collab room), `achievement` (解锁弹窗队列), `myFlowchart` (题面「你画的流程图」那张 A/S 图的 mermaid 源码)
|
||||
- `composables/` — `aiStream`, `pagination` (URL-synced), `websocket` (reconnect + heartbeat), `collabDoc` (Yjs binding for the collab channel), `configUpdate` (WS-pushed config sync), `useMermaid` (lazy Mermaid render), `darkTransition` (View Transitions,111 以下走降级分支), `leaveStudents` (课堂看板的「请假」), `problemJump` (按题号直达), `teacherHelp` (老师接单 / 打开学生编辑器), `chartTheme`, `breakpoints`, `rarity`
|
||||
- `composables/` — `aiStream`, `pagination` (URL-synced), `websocket` (reconnect + heartbeat), `collabDoc` (Yjs binding for the collab channel), `configUpdate` (WS-pushed config sync), `useMermaid` (lazy Mermaid render,渲染器是 pele 不是 mermaid), `darkTransition` (View Transitions,111 以下走降级分支), `leaveStudents` (课堂看板的「请假」), `problemJump` (按题号直达), `teacherHelp` (老师接单 / 打开学生编辑器), `chartTheme`, `breakpoints`, `rarity`
|
||||
- `layout/` — `default.vue` and `admin.vue` layout wrappers
|
||||
- `api.ts` — shared API calls (auth, profile, tags, captcha)
|
||||
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
"fflate": "^0.8.3",
|
||||
"lib0": "0.2.119",
|
||||
"markdown-it": "^14.3.0",
|
||||
"mermaid": "^12.1.0",
|
||||
"naive-ui": "^2.45.3",
|
||||
"nanoid": "^6.0.2",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pele": "1.6.0",
|
||||
"pinia": "^4.0.3",
|
||||
"pinyin-pro": "^3.29.5",
|
||||
"vue": "^3.5.43",
|
||||
|
||||
@@ -1,24 +1,10 @@
|
||||
import { getRandomId } from "utils/functions"
|
||||
|
||||
const mermaidThemeVariables = {
|
||||
primaryColor: "#e0f2fe",
|
||||
primaryTextColor: "#0f172a",
|
||||
primaryBorderColor: "#0284c7",
|
||||
lineColor: "#64748b",
|
||||
arrowheadColor: "#64748b",
|
||||
secondaryColor: "#f5f3ff",
|
||||
tertiaryColor: "#ecfdf5",
|
||||
background: "#ffffff",
|
||||
mainBkg: "#f8fafc",
|
||||
secondBkg: "#eef2ff",
|
||||
tertiaryBkg: "#f0fdfa",
|
||||
nodeBorder: "#2563eb",
|
||||
clusterBkg: "#f8fafc",
|
||||
clusterBorder: "#cbd5e1",
|
||||
edgeLabelBackground: "#ffffff",
|
||||
fontFamily:
|
||||
'Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
||||
}
|
||||
/**
|
||||
* Mermaid 文本画成 SVG。渲染器是 pele(obsidianmd/pele),不是 mermaid 本身:
|
||||
* 同一套语法,同步渲染、没有依赖,流程图部分 gzip 后 44 kB(mermaid 要 200 kB 以上)。
|
||||
* 换之前拿库里全部 2170 张图对过:两边能画的、报错的完全一致。
|
||||
*
|
||||
* pele 的版本号锁死(不带 ^):项目 2026-10 才开,小版本也在改排版。
|
||||
*/
|
||||
|
||||
const semanticNodeClasses = [
|
||||
"startNode",
|
||||
@@ -33,189 +19,70 @@ const semanticNodeClasses = [
|
||||
|
||||
const displayStyleId = "oj-mermaid-display-style"
|
||||
|
||||
/** 框的颜色:[class, 底色, 边框]。pele 把 `class n0 startNode` 原样挂在节点的 <g> 上 */
|
||||
const nodeColors: [string, string, string][] = [
|
||||
["startNode", "#eef8f2", "#18a058"],
|
||||
["startEnd", "#eef8f2", "#18a058"],
|
||||
["endNode", "#eef8f2", "#18a058"],
|
||||
["input", "#eef4fd", "#2f6bc4"],
|
||||
["output", "#eef4fd", "#2f6bc4"],
|
||||
["process", "#ffffff", "#7d828a"],
|
||||
["decision", "#fdf5e6", "#d08a1c"],
|
||||
["loop", "#fdf5e6", "#d08a1c"],
|
||||
["oj-node-palette-0", "#dbeafe", "#2563eb"],
|
||||
["oj-node-palette-1", "#ccfbf1", "#0d9488"],
|
||||
["oj-node-palette-2", "#ede9fe", "#7c3aed"],
|
||||
["oj-node-palette-3", "#ffe4e6", "#e11d48"],
|
||||
["oj-node-palette-4", "#fef3c7", "#d97706"],
|
||||
["oj-node-palette-5", "#dcfce7", "#16a34a"],
|
||||
]
|
||||
|
||||
// !important 是为了压过老提交里 classDef 写进 style 属性的颜色,全站的图一个样
|
||||
const mermaidDisplayStyle = `
|
||||
.oj-mermaid-flowchart {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
--pele-bg: #ffffff;
|
||||
--pele-fg: #0f172a;
|
||||
--pele-line: #64748b;
|
||||
--pele-surface: #f8fafc;
|
||||
--pele-border: #2563eb;
|
||||
--pele-muted: #334155;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node rect,
|
||||
.oj-mermaid-flowchart g.node polygon,
|
||||
.oj-mermaid-flowchart g.node ellipse,
|
||||
.oj-mermaid-flowchart g.node circle,
|
||||
.oj-mermaid-flowchart g.node path {
|
||||
.oj-mermaid-flowchart .pele-node > :not(text) {
|
||||
stroke-width: 2px !important;
|
||||
filter: drop-shadow(0 6px 12px rgba(15, 23, 42, 0.12));
|
||||
}
|
||||
${nodeColors
|
||||
.map(
|
||||
([cls, fill, stroke]) => `
|
||||
.oj-mermaid-flowchart .pele-node.${cls} > :not(text) {
|
||||
fill: ${fill} !important;
|
||||
stroke: ${stroke} !important;
|
||||
}`,
|
||||
)
|
||||
.join("")}
|
||||
|
||||
.oj-mermaid-flowchart g.node.startNode rect,
|
||||
.oj-mermaid-flowchart g.node.startNode polygon,
|
||||
.oj-mermaid-flowchart g.node.startNode ellipse,
|
||||
.oj-mermaid-flowchart g.node.startNode circle,
|
||||
.oj-mermaid-flowchart g.node.startNode path,
|
||||
.oj-mermaid-flowchart g.node.startEnd rect,
|
||||
.oj-mermaid-flowchart g.node.startEnd polygon,
|
||||
.oj-mermaid-flowchart g.node.startEnd ellipse,
|
||||
.oj-mermaid-flowchart g.node.startEnd circle,
|
||||
.oj-mermaid-flowchart g.node.startEnd path {
|
||||
fill: #eef8f2 !important;
|
||||
stroke: #18a058 !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.endNode rect,
|
||||
.oj-mermaid-flowchart g.node.endNode polygon,
|
||||
.oj-mermaid-flowchart g.node.endNode ellipse,
|
||||
.oj-mermaid-flowchart g.node.endNode circle,
|
||||
.oj-mermaid-flowchart g.node.endNode path {
|
||||
fill: #eef8f2 !important;
|
||||
stroke: #18a058 !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.input rect,
|
||||
.oj-mermaid-flowchart g.node.input polygon,
|
||||
.oj-mermaid-flowchart g.node.input ellipse,
|
||||
.oj-mermaid-flowchart g.node.input circle,
|
||||
.oj-mermaid-flowchart g.node.input path {
|
||||
fill: #eef4fd !important;
|
||||
stroke: #2f6bc4 !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.output rect,
|
||||
.oj-mermaid-flowchart g.node.output polygon,
|
||||
.oj-mermaid-flowchart g.node.output ellipse,
|
||||
.oj-mermaid-flowchart g.node.output circle,
|
||||
.oj-mermaid-flowchart g.node.output path {
|
||||
fill: #eef4fd !important;
|
||||
stroke: #2f6bc4 !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.process rect,
|
||||
.oj-mermaid-flowchart g.node.process polygon,
|
||||
.oj-mermaid-flowchart g.node.process ellipse,
|
||||
.oj-mermaid-flowchart g.node.process circle,
|
||||
.oj-mermaid-flowchart g.node.process path {
|
||||
fill: #ffffff !important;
|
||||
stroke: #7d828a !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.decision rect,
|
||||
.oj-mermaid-flowchart g.node.decision polygon,
|
||||
.oj-mermaid-flowchart g.node.decision ellipse,
|
||||
.oj-mermaid-flowchart g.node.decision circle,
|
||||
.oj-mermaid-flowchart g.node.decision path {
|
||||
fill: #fdf5e6 !important;
|
||||
stroke: #d08a1c !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.loop rect,
|
||||
.oj-mermaid-flowchart g.node.loop polygon,
|
||||
.oj-mermaid-flowchart g.node.loop ellipse,
|
||||
.oj-mermaid-flowchart g.node.loop circle,
|
||||
.oj-mermaid-flowchart g.node.loop path {
|
||||
fill: #fdf5e6 !important;
|
||||
stroke: #d08a1c !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-0 rect,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-0 polygon,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-0 ellipse,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-0 circle,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-0 path {
|
||||
fill: #dbeafe !important;
|
||||
stroke: #2563eb !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-1 rect,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-1 polygon,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-1 ellipse,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-1 circle,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-1 path {
|
||||
fill: #ccfbf1 !important;
|
||||
stroke: #0d9488 !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-2 rect,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-2 polygon,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-2 ellipse,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-2 circle,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-2 path {
|
||||
fill: #ede9fe !important;
|
||||
stroke: #7c3aed !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-3 rect,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-3 polygon,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-3 ellipse,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-3 circle,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-3 path {
|
||||
fill: #ffe4e6 !important;
|
||||
stroke: #e11d48 !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-4 rect,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-4 polygon,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-4 ellipse,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-4 circle,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-4 path {
|
||||
fill: #fef3c7 !important;
|
||||
stroke: #d97706 !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-5 rect,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-5 polygon,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-5 ellipse,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-5 circle,
|
||||
.oj-mermaid-flowchart g.node.oj-node-palette-5 path {
|
||||
fill: #dcfce7 !important;
|
||||
stroke: #16a34a !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart g.node .label,
|
||||
.oj-mermaid-flowchart g.node .nodeLabel,
|
||||
.oj-mermaid-flowchart g.node .nodeLabel p,
|
||||
.oj-mermaid-flowchart g.node .label span {
|
||||
color: #0f172a !important;
|
||||
.oj-mermaid-flowchart .pele-node text {
|
||||
fill: #0f172a !important;
|
||||
font-weight: 650 !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart .edgePaths path.path,
|
||||
.oj-mermaid-flowchart .flowchart-link {
|
||||
stroke: #64748b !important;
|
||||
stroke-width: 2.4px !important;
|
||||
.oj-mermaid-flowchart .pele-edge > path:not(.pele-marker) {
|
||||
stroke-width: 2.4px;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart marker path,
|
||||
.oj-mermaid-flowchart .marker {
|
||||
fill: #64748b !important;
|
||||
stroke: #64748b !important;
|
||||
.oj-mermaid-flowchart .pele-edge-label rect {
|
||||
fill: rgba(255, 255, 255, 0.94);
|
||||
stroke: #cbd5e1;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart .edgeLabel rect,
|
||||
.oj-mermaid-flowchart .edgeLabel .labelBkg {
|
||||
fill: rgba(255, 255, 255, 0.94) !important;
|
||||
stroke: #cbd5e1 !important;
|
||||
}
|
||||
|
||||
.oj-mermaid-flowchart .edgeLabel,
|
||||
.oj-mermaid-flowchart .edgeLabel span,
|
||||
.oj-mermaid-flowchart .edgeLabel p {
|
||||
color: #334155 !important;
|
||||
font-weight: 600 !important;
|
||||
.oj-mermaid-flowchart .pele-edge-label text {
|
||||
fill: #334155;
|
||||
font-weight: 600;
|
||||
}
|
||||
`
|
||||
|
||||
const svgNamespace = "http://www.w3.org/2000/svg"
|
||||
|
||||
function getNodeLabel(node: SVGGElement): string {
|
||||
const el =
|
||||
node.querySelector(".nodeLabel p") ||
|
||||
node.querySelector(".nodeLabel") ||
|
||||
node.querySelector(".label span") ||
|
||||
node.querySelector(".label")
|
||||
return el?.textContent?.trim() ?? ""
|
||||
}
|
||||
|
||||
function applyFlowchartDisplayStyle(container: HTMLElement) {
|
||||
container.classList.add("oj-mermaid-surface")
|
||||
|
||||
@@ -224,7 +91,7 @@ function applyFlowchartDisplayStyle(container: HTMLElement) {
|
||||
|
||||
svg.classList.add("oj-mermaid-flowchart")
|
||||
|
||||
const nodes = Array.from(svg.querySelectorAll<SVGGElement>("g.node"))
|
||||
const nodes = Array.from(svg.querySelectorAll<SVGGElement>("g.pele-node"))
|
||||
|
||||
// Assign palette indices by label so same label → same color, different labels → different colors
|
||||
const labelPaletteMap = new Map<string, number>()
|
||||
@@ -235,7 +102,7 @@ function applyFlowchartDisplayStyle(container: HTMLElement) {
|
||||
node.classList.contains(className),
|
||||
)
|
||||
if (!hasSemanticClass) {
|
||||
const label = getNodeLabel(node)
|
||||
const label = node.querySelector(".pele-label")?.textContent?.trim() ?? ""
|
||||
if (!labelPaletteMap.has(label)) {
|
||||
labelPaletteMap.set(label, paletteCounter % 6)
|
||||
paletteCounter++
|
||||
@@ -251,36 +118,6 @@ function applyFlowchartDisplayStyle(container: HTMLElement) {
|
||||
svg.insertBefore(style, svg.firstChild)
|
||||
}
|
||||
|
||||
let mermaidPromise: Promise<any> | null = null
|
||||
|
||||
function loadMermaid(): Promise<any> {
|
||||
// 缓存 Promise 而不是实例:同一屏里两个组件一起挂载时,缓存实例会让两边都
|
||||
// 落进 if (!mermaidInstance),import 两次、initialize 两次
|
||||
if (!mermaidPromise) {
|
||||
mermaidPromise = (async () => {
|
||||
const instance = (await import("mermaid")).default
|
||||
instance.initialize({
|
||||
startOnLoad: false,
|
||||
securityLevel: "strict",
|
||||
theme: "base",
|
||||
// 解析失败时 mermaid 默认会先把一张「错误图」画进挂在 document.body 上的
|
||||
// 临时容器,再抛异常,而清理临时容器的那行在 throw 之后,永远执行不到;
|
||||
// 每次 render 用的又是新的随机 id,旧的也清不掉。于是每失败一次就往
|
||||
// body 里留一个 div#dmermaid-xxx —— 出题页每敲一个字符渲染一次,一段
|
||||
// 代码写下来能堆几十个。打开这个开关后 mermaid 会先清理再抛。
|
||||
suppressErrorRendering: true,
|
||||
themeVariables: mermaidThemeVariables,
|
||||
})
|
||||
return instance
|
||||
})().catch((error) => {
|
||||
// 失败的 Promise 不能留在缓存里,否则后面每次渲染都直接复用这个失败结果
|
||||
mermaidPromise = null
|
||||
throw error
|
||||
})
|
||||
}
|
||||
return mermaidPromise
|
||||
}
|
||||
|
||||
export function useMermaid() {
|
||||
const renderError = ref<string | null>(null)
|
||||
const renderSuccess = ref(false)
|
||||
@@ -296,9 +133,15 @@ export function useMermaid() {
|
||||
|
||||
const gen = ++renderGeneration
|
||||
try {
|
||||
const m = await loadMermaid()
|
||||
const id = `mermaid-${getRandomId()}`
|
||||
const { svg } = await m.render(id, mermaidCode)
|
||||
// pele/lazy 按图的类型现拉对应的模块,题目里绝大多数是流程图,只拉那一块
|
||||
const { renderAsync } = await import("pele/lazy")
|
||||
const { svg } = await renderAsync(mermaidCode, {
|
||||
// 量字宽用页面真实的字体,否则框会比字窄或宽
|
||||
fontFamily: getComputedStyle(container).fontFamily,
|
||||
// 题目是老师写的、提交是学生写的,图里的链接和外链图片一律不画
|
||||
links: false,
|
||||
images: false,
|
||||
})
|
||||
if (gen !== renderGeneration) return
|
||||
container.innerHTML = svg
|
||||
applyFlowchartDisplayStyle(container)
|
||||
|
||||
@@ -9,9 +9,10 @@ import { NaiveUiResolver } from "unplugin-vue-components/resolvers"
|
||||
// 但比 vite 8 的默认构建 target(chrome111)低。所以这个插件必须留着:它同时管两件事
|
||||
// —— 把 build.target 压到 chrome105/es2020,再给现代产物补 core-js 的 API polyfill。
|
||||
//
|
||||
// 下面这份清单是 `modernPolyfills: true` 自动探测出来的 52 项,抄下来写死:自动探测要
|
||||
// 下面这份清单是 `modernPolyfills: true` 自动探测出来的 50 项,抄下来写死:自动探测要
|
||||
// 对每个产物跑一遍 Babel 扫描,构建从 3 秒涨到 12 秒。**升级前端依赖后重新审计一次**:
|
||||
// DEBUG=vite:legacy bun run build # 会打印 modern polyfills 的全集
|
||||
// 临时把下面的 modernPolyfills 改成 true,再 DEBUG=vite:legacy bun run build
|
||||
// (写死清单时它只回显这份清单,不会重新探测)
|
||||
// 少一项就是老机器上一个静默的 TypeError(这批缺的大多是 Chrome 110+ 的
|
||||
// Array.prototype.toSorted / Set 运算 / 迭代器辅助)。
|
||||
const polyfills = [
|
||||
@@ -23,7 +24,6 @@ const polyfills = [
|
||||
"es.array.to-reversed",
|
||||
"es.array.to-sorted",
|
||||
"es.array.to-spliced",
|
||||
"es.array.with",
|
||||
"es.iterator.constructor",
|
||||
"es.iterator.drop",
|
||||
"es.iterator.every",
|
||||
@@ -34,12 +34,12 @@ const polyfills = [
|
||||
"es.iterator.map",
|
||||
"es.iterator.reduce",
|
||||
"es.iterator.some",
|
||||
"es.iterator.take",
|
||||
"es.iterator.to-array",
|
||||
"es.json.parse",
|
||||
"es.json.stringify",
|
||||
"es.map.get-or-insert",
|
||||
"es.map.get-or-insert-computed",
|
||||
"es.object.group-by",
|
||||
"es.regexp.escape",
|
||||
"es.regexp.flags",
|
||||
"es.set.difference.v2",
|
||||
@@ -61,7 +61,6 @@ const polyfills = [
|
||||
"esnext.array.group",
|
||||
"web.dom-exception.stack",
|
||||
"web.immediate",
|
||||
"web.structured-clone",
|
||||
"web.url-search-params.delete",
|
||||
"web.url-search-params.has",
|
||||
"web.url-search-params.size",
|
||||
@@ -128,10 +127,11 @@ export default defineConfig(() => {
|
||||
tsconfigPaths: true,
|
||||
},
|
||||
build: {
|
||||
// 超过 500 kB 的两个 chunk 都是懒加载的:wangeditor(后台富文本,TextEditor-*.js)、
|
||||
// @mermaid-js/parser,各 660 kB 上下。默认阈值下这条警告每次构建都在报,真涨了
|
||||
// 反而没人看,所以抬到比它们略高。首屏入口 index-*.js 在 175 kB 左右。
|
||||
// (原来还有 Python 语法检查用的 skulpt,语法检查挪到服务端的 CPython 之后删了)
|
||||
// 超过 500 kB 的 chunk 只有懒加载的 wangeditor(后台富文本,TextEditor-*.js),
|
||||
// 640 kB 上下。默认阈值下这条警告每次构建都在报,真涨了反而没人看,所以抬到比它
|
||||
// 略高。首屏入口 index-*.js 在 175 kB 左右。
|
||||
// (原来还有 Python 语法检查用的 skulpt、mermaid 的 @mermaid-js/parser,前者挪到
|
||||
// 服务端的 CPython、后者换成 pele 之后都没了)
|
||||
chunkSizeWarningLimit: 1000,
|
||||
},
|
||||
server: {
|
||||
|
||||
Reference in new issue
Block a user