Build1 distinct publisher3 min readUpdated
ViteDash 2.2 declared a dependency npm's flat node_modules had been hiding, then found its own manual chunk config had made first paint worse than shipping one big file.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
ViteDash, a free admin template built on React 19, Vite 8 and Ant Design 6, shipped version 2.2 with two repairs: a dependency it had never declared, and a production build that was one 1,620,471-byte JavaScript file [1][3]. The install bug is the one to copy into your own checklist, because npm's flat node_modules hid it from the maintainer and from every npm user while breaking pnpm and Yarn PnP users outright [5][6].
According to the maintainer's write-up on dev.to, `@ant-design/icons` was imported in 22 source files and was absent from package.json [4]. Under npm the import resolves anyway: npm flattens node_modules, antd itself depends on the icons package, and the import finds a copy sitting at the top level [5]. pnpm keeps a strict node_modules where a package can only import what it declared, and Yarn PnP behaves the same way [6]. Users who cloned, installed and ran dev got `Failed to resolve import "@ant-design/icons"` [6]. The README recommended pnpm [7]. The fix was one line in package.json [8]; the detection cost is one install run under a strict resolver, which is the maintainer's own conclusion: a transitive dependency you never asked for is not a dependency you have [9].
The bundle story is the more interesting failure. With everything in one chunk, the sign-in screen waited on the Kanban board, the invoice drawer and every other page before it painted [10]. Route-level lazy imports, with the Suspense boundary inside the shell rather than around it so the sidebar and header stay on screen, fixed that [11]. Then came the advice from every "Vite bundle too large" thread: a `manualChunks` function grouping React, antd, icons and charts into named vendor chunks [12]. The chunk list looked tidy. Summing the files named in the built index.html's modulepreload tags gave 2,086 kB raw and 643 kB gzipped before first paint [13], roughly 29 percent more raw bytes than the single unsplit chunk it replaced [3].
The mechanism is worth understanding before you write your own version. `manualChunks` is a hard instruction, not a hint, and a chunk is eager if any module in it is reachable from the entry [14]. The app shell imports Layout, Menu and Button, so the antd chunk went eager and carried Table, Splitter and Calendar along with it [14]. Recharts is imported only by the Charts page, but naming it as a chunk pulled 427 kB of chart library into the entry graph for people who never opened a chart [15]. Deleting the config dropped the eager set to 1,004 kB raw across 12 files and 324 kB gzipped [16], about 52 percent less raw and 50 percent less gzipped [1][2].
The default behaviour is already the behaviour most apps want: a module reachable from the entry lands in the entry chunk, a module used by two lazy routes lands in a shared chunk that loads when either does, and a module used by one lazy route lands in that route's chunk [17]. The maintainer's remaining case for `manualChunks` is narrow: group a library when the analyzer shows it genuinely duplicated across many chunks, because you measured rather than because vendor splitting is considered good practice [18].
Two checks fall out of this for anyone shipping code other people install. Add a pnpm or Yarn PnP install to CI, so "works on my machine" means "resolves without hoisting". And judge a chunking change by the eager modulepreload set in the built HTML, not by the shape of the chunk list.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
ViteDash is a free admin dashboard template built with React 19, Vite 8 and Ant Design 6; version 2.2 was released.
The template has twenty something pages and light and dark mode implemented through Ant Design's theme algorithm rather than CSS overrides.
The production build was a single chunk: dist/assets/index-BkAqHA3M.js at 1,620,471 bytes.
@ant-design/icons was imported in 22 files and was not listed in package.json.
The undeclared import works for npm users because npm flattens node_modules and antd depends on the icons package, so the import resolves through a copy sitting at the top level.
pnpm keeps a strict node_modules where a package can only import what it declared, and Yarn PnP is the same; those users cloned the repo, ran install and dev, and got 'Failed to resolve import "@ant-design/icons"'.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Concrete but single-source and self-reported
The technical core is unusually well specified for a single blog post: an exact build artifact size in bytes, a named measurement method (summing modulepreload targets from the built index.html), before/after raw and gzipped totals, the specific 427 kB Recharts figure, the reproduced error string, and the actual manualChunks function. The mechanism offered - manualChunks as a hard instruction, and a chunk being eager if any of its modules is entry-reachable - is internally consistent with the measurements and with the observable npm-hoisting behaviour that hid the undeclared import. What is missing is any verification outside the maintainer's own machine: no independent reproduction, no analyzer output, no timing on real networks, and no issue links quantifying affected users. Evidence quality is therefore good in specificity and weak in corroboration.
No usage data in supplied sources
The cluster contains a release announcement and a self-run benchmark, but nothing that measures uptake: no download or install counts, no repository stars or forks, no issue or bug-report volume from the blocked pnpm users, and no third-party deployments. The phrase 'a chunk of my audience' is the only sizing language and it is unquantified. Scoring adoption would require inventing numbers the source does not provide.
Broadly aligned; headline generalizes a narrower result
The body is close to the evidence and runs against the usual promotional grain - the maintainer leads with his own broken install and a self-inflicted performance regression, and explicitly warns that the template's role-based access control is not security. The mild overstatement is scoping: the headline's 'halved my dashboard bundle' describes the eager first-paint payload, not total shipped bytes, which the post concedes went up as the template gained charts, locales and seven pages. The general prescription against manualChunks also rests on one app's measurement, presented as a broadly applicable trap, though the closing caveat about grouping only when the analyzer shows real duplication pulls that back toward the evidence.
Maintainer promoting own free template, with self-critical framing
The author maintains the subject project and the post doubles as distribution for it, closing with hosted demo sign-in credentials and a feature tour of 2.2's role-based access control. That is a clear promotional interest in the release being noticed. Offsetting it, the narrative's spine is an admission of two of the maintainer's own mistakes - shipping an undeclared dependency that broke the install path his README recommended, and configuring a bundler regression - which is a costly signal that cuts against pure marketing. There is no vendor sponsorship, paid tier, funding or competing-product disparagement in the supplied text.
Mechanism solid, breadth and verification unknown
Confidence is moderate. The two mechanisms - hoisting-dependent resolution of an undeclared import, and manualChunks forcing grouped vendor code into the eager graph - are specific, self-consistent and match well-known package manager and bundler behaviour, so the account of what happened in this repo is credible. Confidence is capped by a single publisher and a single self-interested author with no independent reproduction, by the absence of any adoption or impact measurement, and by the fact that the generalized advice against vendor splitting is extrapolated from one application's build.
build
Flue 2 bets that agents are a rendering problem, not an orchestration one1 distinct publisher
build
A file-copy Allure adapter for Katalon, and the history IDs that make retries useful1 distinct publisher
build
FFmpeg.wasm ships, but budget for a watchdog: one in ten heavy jobs deadlocked in silence1 distinct publisher
build
Block's Berd makes a duller argument than its mascots: show the agent's context as product state1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 15, 2026