From 90f738a4c73fb4e4fe6aa09ec4635d98332a00f3 Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:26:38 +0800 Subject: [PATCH] build(web): react-free vendor list for the incremental markdown pipeline, npmPackageOf scoped guard, chunk audit script --- apps/web/vite.config.ts | 25 +++++++++++++++++-------- scripts/attribute-chunk-bytes.mjs | Bin 0 -> 4072 bytes 2 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 scripts/attribute-chunk-bytes.mjs diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index d2d717f0dc..c5a6e6cc11 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -22,32 +22,40 @@ function rejectStandaloneServe(): Plugin { * Vendor-chunk membership, by exact npm package name — the heavy render * families (math, highlight, markdown) that change only on dependency bumps. * Only packages workspace code imports DIRECTLY need listing: their private - * transitive dependencies (unified/hast/oniguruma machinery, ~50 packages) - * are imported solely by these and rollup's chunk coloring pulls them into + * transitive dependencies (oniguruma machinery, character tables, …) are + * imported solely by these and rollup's chunk coloring pulls them into * vendor automatically. A dependency shared with index-side code falls back * to index — a few kB of dilution, never a correctness problem. Anything not * listed (react family, the vendored cordis workspace, tiny helpers like * anser/clsx, all workspace code) stays in the default `index` chunk, so * editing shell code re-hashes only index and returning clients keep the * cached vendor chunk. + * + * Boundary invariant: every member must be react-free. A package that + * imports react/jsx-runtime must never be listed — rollup folds a module + * shared between the entry and a manual chunk into the manual chunk, so one + * react-importing member would drag the single shared react copy into + * vendor. The React side of markdown/math rendering is workspace code and + * rides index. */ const VENDOR_PACKAGES: ReadonlySet = new Set([ // math 'katex', - 'rehype-katex', // syntax highlight (@shikijs/langs is handled separately below — // lazy grammars must not land here) 'shiki', - // markdown pipeline - 'react-markdown', - 'remark-gfm', - 'remark-math', + // markdown parse pipeline (micromark/mdast; the incremental React renderer + // over it is workspace code) 'mdast-util-from-markdown', 'mdast-util-gfm', + 'mdast-util-math', + 'micromark-core-commonmark', 'micromark-extension-gfm', 'micromark-extension-math', 'micromark-factory-space', 'micromark-util-character', + 'micromark-util-classify-character', + 'micromark-util-sanitize-uri', 'micromark-util-symbol', 'micromark-util-types', ]) @@ -74,7 +82,8 @@ function npmPackageOf(id: string): string | undefined { if (parts.length === 1) return undefined const [first, second] = parts[parts.length - 1].split('/') if (first.startsWith('.')) return undefined // .pnpm store segment, not a package - return first.startsWith('@') ? `${first}/${second}` : first + if (first.startsWith('@')) return second === undefined ? undefined : `${first}/${second}` + return first } export default defineConfig({ diff --git a/scripts/attribute-chunk-bytes.mjs b/scripts/attribute-chunk-bytes.mjs new file mode 100644 index 0000000000000000000000000000000000000000..d7cc1130d9e012897433d25ad13b4688ff3550cc GIT binary patch literal 4072 zcmb7HYj@i=65Y@G74yMclC??7j^j<`*sYz{rcLZLPSSQ|wWUZ%V#HSg(6-{}zwaG@ zq$Jlqdp0MDNMIg!26qO-Fr*W$Wje04poqqGnrVt>buo7oT-+$uw5BzH}_Kj8F_%$&%rh`2325kRINKODk0_swR zDX`yAF7mOEYL-?MO|+1J6&2I8n9`>gXV1^y|MBkR*-t00UR+Qqk>k3)@lhGR?%r zqKIip6Itfuu;sx-IlW$77OFYacafga5mmB`g;GHzr&q(hQ6mAfXV^TeIXrhmX8k2F zSva4#jzQvhv`xDs`udgj`(Epe!#dgk=9&-~zz#XJo;-0{VW!6s{djSH7F3Z`!d;JN zr3N=n09mKg_uAM_5B6cfIXQjy{Kd;x|9<`BPjB9yoxl6}{l$lmpMLrExBo=rI1!WS zEd4ys@}jK%l1kTC*EfqV{oTDs`;QO)_2j$l&}q@nBKe_wU1%6B#5KK*Dt8zJ0o;rj zf$PRQlzMc8)8MC(2P8Pt=Z4Ny7J}LBgXTy>LP|`Ti$}F*>RS#r9=LG%F>;3 z1CMvMw>`S;5#nWHa`bOR0X3szlF+$h1FAQkoy@f=Lb;Fd+pvmOF{l7T_ps+57eNMeS*9L@TJsEdQD*n@OeWkWL zI_yZlTHUj&e9EiEN7lprKK4CoOJt?7-)ivb+oTLFa8qfhr;!c(P9E95&WH~JqeNkx7}j;2 zY_+rOEls~YnNFpcMwnchxuoLj%|C8u6I{OWTaOu&V;%Q-5-X(hokMw(ENNI{{BM{j`;ao?=lRh9#e}U z7J1wM3H*BXhcwBeLPWXh_MZOB{S`Au-&;dDeYxj;# zI~27RA2!ttPY)ZyErC>EAbSuEORxZEw}~CWF%4|4$BR>Q)Cju0u-ERSwQ}J5YxBNb zs|wCSN6K_WN4PP-Q@AiU1AI5$;HG2Jn#Ca|0SL8V0);+2-eH>-ooUQt!!4NIUKIfA zEqk39>p5;q`~jsHWF=<4DQ<@q(RR8<(9J=*)Dhq0W{|K&-y}$u*XG&*9XmIeNhF3_ z*Bc=vQoC-nLqLbAX3RzEQ-q&(NSlv2x4h{V82NYmd;4CX%a`emNZefylUs7ZCFDM7 zHLAGNFe(O|N8duXf4}Nut6F9v$jYhvr)MCELs`=N6l`w3 zU3M_+3V-?~t-L?)nBTf}=BLg&@+Is#|6E&o?7?GG3Q*_5QnT`!n;v>y6my7uJN#H` z4EcIM8u^21#CJ9)ey!86^7b}*Ef3pvlc{SD*>6Tenr*z2J@QE&+jzSM)+7 z2-YxZ*~zLu++!MdB2FG=)+K!dVo7-^F_N14QFn8M5X+jsqxcwH4)}qDBh>$KCNRxI z@+(=^6{$MUBe}o_5I!YsgP<$5`jQMxuA2>$Y{Oq9y~O9B{6Evq$=m4gXmH%hVYAC5 z*&)X?+q>c}3tPu`NmnjRP*#eGQX}8!C3{&2L-t& Mu#81_zZf$AUtLfIzW@LL literal 0 HcmV?d00001