Part of #1578. Depends on #1579. This step is atomic: one PR that removes the old toolchain and installs the new one, buildable and bootable on its own.
Change. Vite config (ui/vite.config.mts) preserving the output contracts (ui/build, static/js, static/css, static/media, sourcemaps, REACT_APP_ prefix, base from ui/scripts/env.js); package.json and lockfile; index.html moved to the ui root; react-scripts, react-app-rewired, customize-cra, config-overrides.js and the other toolchain leftovers removed; process.env reads become import.meta.env and are typed; require() calls become ES imports; the router enumerates page modules with a bounded import.meta.glob instead of an aliased template-literal import that no bundler can analyze; the header.html entry script becomes type="module" crossorigin. Plus the two first-paint fixes: plugin i18n registration made independent of module evaluation order, and the bootstrap-icons font path resolved so the font files are actually emitted. Build-script parity: tsc --noEmit runs in pnpm build; the release workflow's Node and engines match the bundler's floor.
Done when. pnpm install and pnpm build pass on dev plus step 1 plus this change, go build ./..., go vet ./... and TestGetStyleResolvesBuiltAssets pass against the new build, no reference to the removed toolchain remains outside the lockfile, and the built binary boots with the client mounted in a browser.
Behaviour to disclose in the PR. The CDN/CORS consequence of module scripts (documented in apache/answer-plugins#326), the custom stylesheet href derivation, and the two pre-existing dead routes that now fail loudly instead of silently (pages/403 is repointed in step 3).
Part of #1578. Depends on #1579. This step is atomic: one PR that removes the old toolchain and installs the new one, buildable and bootable on its own.
Change. Vite config (
ui/vite.config.mts) preserving the output contracts (ui/build,static/js,static/css,static/media, sourcemaps,REACT_APP_prefix,basefromui/scripts/env.js);package.jsonand lockfile;index.htmlmoved to theuiroot;react-scripts,react-app-rewired,customize-cra,config-overrides.jsand the other toolchain leftovers removed;process.envreads becomeimport.meta.envand are typed;require()calls become ES imports; the router enumerates page modules with a boundedimport.meta.globinstead of an aliased template-literal import that no bundler can analyze; theheader.htmlentry script becomestype="module" crossorigin. Plus the two first-paint fixes: plugin i18n registration made independent of module evaluation order, and the bootstrap-icons font path resolved so the font files are actually emitted. Build-script parity:tsc --noEmitruns inpnpm build; the release workflow's Node andenginesmatch the bundler's floor.Done when.
pnpm installandpnpm buildpass ondevplus step 1 plus this change,go build ./...,go vet ./...andTestGetStyleResolvesBuiltAssetspass against the new build, no reference to the removed toolchain remains outside the lockfile, and the built binary boots with the client mounted in a browser.Behaviour to disclose in the PR. The CDN/CORS consequence of module scripts (documented in apache/answer-plugins#326), the custom stylesheet href derivation, and the two pre-existing dead routes that now fail loudly instead of silently (
pages/403is repointed in step 3).