chore(ailab): migrate to vite + vitest + typescript toolchain#73010
Conversation
There was a problem hiding this comment.
A friendly pass over the vite + vitest + typescript migration 👋
Thanks for taking this on — toolchain swaps are fiddly, thankless work, and the overall shape here is really solid. I went through it three times wearing different hats (Vite/bundling, Vitest, TypeScript) and wanted to share notes in the spirit of "here's what I'd polish with you," not a gate. I've left inline comments with concrete, applyable suggestions wherever I could.
Tests — nicely done. I actually ran the suite (vitest --run): 108 passing across 13 files, clean exit, no hangs. I also poked it by injecting a deliberately-failing assertion to confirm the tests genuinely assert (they do). The only changes to the *.test.js files are import reordering — you carried the behavior over faithfully, which is exactly what you want in a migration like this. Lovely and disciplined.
TypeScript — also in good shape. strict is still on, the typecheck is genuinely green, and the papaparse fix is correct: the original error was real (the non-literal download flag matched no overload, and it only compiled before because papaparse was an untyped phantom dep), and your branch split lines up with the real @types/papaparse overloads with no casts. I re-enabled the deferred tsconfig flags in a throwaway copy just to be sure nothing scary was hiding — it's all cosmetic (≈111 import type-style + 16 unused bindings), no real bugs. The deferral-plus-follow-up plan reads as very reasonable.
A few Vite details I'd love to look at together (all inline, with fixes):
- The "five UI images are small" comment isn't quite holding up in practice — about 626 KB of base64 is landing in the bundle. The
oceanspackage has a nice pattern we can borrow. vite buildis exiting 0 even though the dts step logs a couple ofTS6307errors — easy one-line fix, and I left the exact suggestion.- The dev
/datasets/middleware can be walked out of its directory with../— dev-only, but a quick guard closes it. - A tiny stale
lodashmention in a comment (it rode along from oceans).
None of these are a knock on the work — they're exactly the kind of thing that's easy to miss in a big mechanical swap. Happy to pair on any of them!
🤖 Written by Claude Code.
stephenliang
left a comment
There was a problem hiding this comment.
Changes look amazing! Love seeing the old dependencies get replaced with catalog. I had Claude generate some comments, and then I added my own here. They mainly have to do with ensuring we follow up.
| // The migrated ml-playground source predates the shared config. These rules | ||
| // fire on pre-existing patterns: real circular imports between the store | ||
| // singleton and its consumers, unused bindings, a couple of `any`s, and | ||
| // false-positive CJS-default-interop reports on react/papaparse. Relaxed so | ||
| // the toolchain swap stays mechanical; untangling the cycles and tightening | ||
| // the rest is a tracked follow-up cleanup. (`import-x/order` stays on.) |
There was a problem hiding this comment.
Let's flag as a follow up clean up task. I've been putting these on Github Issues under the label "Next Generation Frontend Platform".
| rules: { | ||
| 'import-x/no-cycle': 'off', | ||
| 'import-x/default': 'off', | ||
| 'import-x/no-named-as-default-member': 'off', | ||
| '@typescript-eslint/no-unused-vars': 'off', | ||
| '@typescript-eslint/no-explicit-any': 'off', | ||
| }, |
There was a problem hiding this comment.
Same with these, all fine as follow ups.
| // turns on: `verbatimModuleSyntax` (would require `import type` on ~110 | ||
| // type-only imports) and `noUnusedLocals`/`noUnusedParameters` (~16 | ||
| // pre-existing unused bindings). Relaxed here so the toolchain swap stays | ||
| // mechanical; restoring them is a tracked follow-up cleanup. |
There was a problem hiding this comment.
Let's make sure to track it
Follow-up #1 to the mechanical migration (#72976). Replace the package's webpack + babel + jest toolchain with the monorepo-standard vite + vitest + tsc setup, restoring a green build/typecheck and wiring the package into the turbo pipeline. No consumer rewiring: apps/ still pulls npm @code-dot-org/ml-playground, so nothing in the studio build changes yet. Build: a vite library build emits dist/index.{mjs,cjs,d.ts}. peerDependencies (react, react-dom, redux, react-redux) are externalized so the consumer's single instances are used; everything else is bundled. The five UI images are inlined as data-URIs (no runtime path), and the 132 dataset files are emitted to dist/assets/datasets/ for the host to serve. A dev-only middleware serves them at /datasets/ for the standalone harness (index.html moved to the package root as the vite entry). Deleted the webpack __webpack_public_path__ machinery (setPublicPath.ts): with images inlined, setAssetPath now governs only the runtime dataset URLs. Tests: jest -> vitest, 108 passing. Lint/prettier adopt the shared flat eslint + prettier config; the .test.js suite gets vitest globals. The migrated source predates some shared-config strictness. Relaxed in this package with a documented, tracked cleanup follow-up: tsconfig verbatimModuleSyntax + noUnusedLocals/Parameters off; eslint import-x/no-cycle, no-unused-vars, no-explicit-any, and two react/papaparse CJS-interop false-positives off. The one genuine type error (a papaparse parse() overload) is fixed properly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
94ec264 to
d5b5046
Compare
🖼️ Storybook Visual Comparison Report✅ No Storybook eyes differences detected! |
From Stephen's review on the vite/vitest toolchain PR: - Emit the 5 UI images to dist/assets/images/ and resolve them off setAssetPath at runtime (new imageUrl helper) instead of inlining. Library mode always inlines imported assets as base-64, which put ~626 KB into the entry and lost separate caching; index.mjs drops 1430 KB -> 805 KB. Images now travel like the datasets (oceans pattern): emitted under dist/assets/, copied by the Gruntfile, fetched under the setAssetPath base. - tsconfig.app.json: include the two JSON files imported from outside src (public/datasets-manifest.json, i18n/mlPlayground.json) so vite-plugin-dts stops logging TS6307 (the build exited 0 but the dts step was unhappy). - dev asset middleware: decode + resolve + confirm the path stays under public/ before serving via /@fs (closes a dev-only ../ traversal); generalized to serve /images/ alongside /datasets/. - rename the standalone dev entry indexDev.tsx -> main.tsx for consistency with oceans; drop the now-dead @public alias and trim a stale lodash mention. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Why
Follow-up #1 to the mechanical migration (#72976, landed on
stagingvia the redone #73025ailab-migration-v2), which inlined@code-dot-org/ml-playgroundintofrontend/packages/labs/ailab/but deliberately left its standalone webpack + babel + jest toolchain in place (and therefore out of the turbobuild/typecheckpipeline).This PR swaps that toolchain for the monorepo-standard vite + vitest + tsc setup (mirroring
frontend/packages/labs/oceans), restoring a greenbuildandtypecheckand wiring the package into turbo so CI sees it.What this PR does
dist/index.{mjs,cjs,d.ts}(replacing the old webpack multi-entry output).package.jsongainsexports/main/module/typespointing atdist/, plusbuild/dev/typecheckscripts so the package joins the turbo pipeline.react,react-dom,redux,react-reduxmove topeerDependenciesand are externalized (vite-plugin-externalize-deps), so the consumer's single instances are used at runtime — preserving the redux "one instance per page" invariant the old webpackexternalsdocumented. Everything else (chart.js, ml-knn, papaparse, messageformat, …) is bundled.dist/assets/{datasets,images}/by a small rollup plugin and fetched at runtime from<setAssetPath base>/<dir>/<file>(the host serves them; the Gruntfile copiesdist/assets/**intomedia/skins/ailab/). A dev-only middleware serves both trees for the standalone harness, with a../-traversal guard.index.htmlmoved to the package root (vite's dev entry);main.tsxis the dev harness. (Images were initially inlined as data-URIs; per review they're emitted instead — library mode always inlines imported assets, which added ~626 KB toindex.mjsand lost separate caching. Nowindex.mjsis ~805 KB, down from ~1430 KB.)setAssetPathsimplification — deletedsetPublicPath.tsand the__webpack_public_path__machinery.setAssetPathnow governs the runtime asset base for the emitted datasets and images, and its call-ordering contract relaxes from "before importing the bundle" to "beforeinitAll().".test.jsfiles get vitest globals via the shared config.eslint.config.mjs+ prettier config; deleted.eslintrc.js,babel.config.json, the local prettierindex.mjs,webpack.config.js,src/indexProd.tsx.Decisions worth a look
tsconfig.app.json:verbatimModuleSyntax,noUnusedLocals,noUnusedParametersoff (~110import type+ ~16 unused-binding violations).eslint.config.mjs:import-x/no-cycle(real store↔index↔component cycles),@typescript-eslint/no-unused-vars,@typescript-eslint/no-explicit-any, and twoimport-xCJS-default-interop false positives on react/papaparse.import-x/orderstays on (auto-fixed across the source — most of the source diff is this reordering).papaparseparse()overload mismatch (the source importspapaparsedirectly but onlyreact-papaparsewas declared). Fixed properly: declarepapaparse+@types/papaparse, drop the deadreact-papaparseshim, and split the call by thedownloadflag so each branch matches a real overload.What this PR does NOT do
apps/still imports the npm@code-dot-org/ml-playgroundand the Gruntfile still copies datasets from it. Nothing in the studio build consumes this package yet → near-zero risk. RepointingAilabView.tsx+ the Gruntfile to@code-dot-org/ailab(and sequencing the frontend build before the apps build) is follow-up store sprite.value again, use it properly in setSpriteSize #2.Test plan
turbo run build typecheck test lint prettier --filter=@code-dot-org/ailabgreen (verified locally — 8/8 tasks).yarn workspace @code-dot-org/ailab devserves the standalone harness; datasets load and AI-bot images render (verified locally:/datasets/*.csvand/images/*200 via middleware, traversal blocked).dist/containsindex.{mjs,cjs,d.ts}exportinginitAll/instructionsDismissed/setAssetPath, plusassets/datasets/(132 files).apps/still on npm@code-dot-org/ml-playground.Follow-ups
apps/at the workspace package; ensure the frontendbuildruns before the apps Grunt copy.playwright+@axe-core/playwrightin the catalog, atest:ui:citurbo task). Tracked for a later update.assetPathintoinitAll(...)options to retire theglobalThiswrite entirely (kills the last ordering caveat).🤖 Generated with Claude Code