[WIP] feat: migrate from Next.js 12 to Vite + React Router 7 + Fastify - #1142
Open
DiRaiks wants to merge 8 commits into
Open
[WIP] feat: migrate from Next.js 12 to Vite + React Router 7 + Fastify#1142DiRaiks wants to merge 8 commits into
DiRaiks wants to merge 8 commits into
Conversation
Full stack replacement behind an unchanged product surface (Vite + React SPA + Fastify"). Feature code stays in place — `next/*` imports resolve to thin shims (react-router 7 / react-helmet-async), so app sources are ported, not rewritten. Frontend: - Vite 8 build, SPA via createBrowserRouter (hash router for IPFS — replaces the hand-rolled fragment routing incl. HomePageIpfs) - app/ bootstrap + route table mirroring pages/ (no /referral, no 500) - runtime env keeps the window.__env__ contract; dynamics normalize() handles raw-string values from the nginx entrypoint - SEO: head-only prerender per route + sitemap.xml + robots.txt + JSON-LD; __PUBLIC_ORIGIN__ placeholder resolved per env by nginx sub_filter - getStaticProps data moved to runtime: manifest via react-query (as before), validation blocklist now fetched from /api/validation-file API (server/ workspace, Fastify 5, esbuild bundle): - ports all 8 pages/api routes incl. the security-critical /api/rpc with allowlists derived from getContractAddress() (all supported chains, batch cap 20, usde events) — networks-map decoupled from next/config - earn vaults-apr/tvl compute for real, reusing the frontend fetchers (vault consts split into pure consts-data, standardFetcher unbarreled) - satanizer masking for all logs, eth_stake_widget_ui_ metrics preserved (ABI-decoded eth_call labels, startup checks, build info) - legacy semantics kept: Cache-Control values, 405 + Allow, per-route CORS - new GET /api/validation-file (was FS read in getStaticProps) Infra: - Dockerfile.web (nginx-unprivileged, static) + Dockerfile.api (node) - nginx: security headers via shared include (add_header inheritance fix), CSP assembled from CSP_* env in entrypoint, s-maxage typo fix, manifest.json/token-lists CORS parity, SELF_ORIGIN guardrails Removed: next + plugins, server.mjs, pages/**, utilsApi/**, config/csp, webpack loaders, .babelrc, next-logger (masking moved into the api). Verified: tsc 0 errors (root+api), eslint clean, 410+31 unit tests, web + IPFS + api builds, api smoke (health/metrics/405/rpc allowlist).
One workflow, matrix over both images (staking-widget-web / -api), reusing the org k8s-build-push-harbor workflow with this repo's harbor_dev_release environment. Triggers on pushes to feature/simple; pushes to the same Harbor repos the existing `staking-widget` helm release (PoC stand) watches via ArgoCD Image Updater — no chart changes needed. Align Dockerfile.api runtime layout with the image the chart currently runs (WORKDIR /app/server, `node dist/index.js`, port 3001) so the new image is a drop-in replacement in the same pod.
DiRaiks
had a problem deploying
to
harbor_dev_release
July 21, 2026 15:53 — with
GitHub Actions
Failure
DiRaiks
had a problem deploying
to
harbor_dev_release
July 21, 2026 15:53 — with
GitHub Actions
Failure
DiRaiks
temporarily deployed
to
harbor_dev_release
July 21, 2026 15:57 — with
GitHub Actions
Inactive
DiRaiks
temporarily deployed
to
harbor_dev_release
July 21, 2026 15:57 — with
GitHub Actions
Inactive
FAQ texts move to faq-data.ts — the single source rendered BOTH by the React accordions (faq-list.tsx; internal links upgraded to SPA navigation, data-matomo click tracking preserved) and by the build-time prerender: /withdrawals/request (25 Q&A) and /withdrawals/claim (13) now carry the full FAQ in the served body for crawlers and no-JS readers, plus FAQPage structured data in the head. The body markup is replaced (never hydrated) on mount via createRoot, so the no-hydration invariant holds. The min/max-amounts entry stays a live component (contract-read numbers) and is excluded from statics. Removes the 26 per-question components superseded by the data module.
The newline check used `*"$(printf '\n')"*` — command substitution strips the trailing newline, degrading the pattern to `*""*`, which matches any string, so the container exited on startup with "forbidden characters". Use a literal-newline variable instead; verified the full entrypoint in a sandbox (window-env.js, sub_filter, CSP render, no unsubstituted vars).
DiRaiks
temporarily deployed
to
harbor_dev_release
July 21, 2026 16:47 — with
GitHub Actions
Inactive
DiRaiks
temporarily deployed
to
harbor_dev_release
July 21, 2026 16:47 — with
GitHub Actions
Inactive
Port develop's config-manifest-from-file feature to the Fastify workspace: /api/config-manifest route, CONFIG_MANIFEST_PATH file source with last-known-good fallback, load-error metric, startup check, useConfigManifestFile runtime flag (window.__env__ / nginx entrypoint). Relative CONFIG_MANIFEST_PATH is normalized against the repo root in load-env (parity with develop, where the Next server ran from the repo root; absolute k8s configmap paths pass through). Convert new allocation icon libraries to Vite ?react imports. Drop getStaticProps-era shouldRedirectToRoot (its only consumer was deleted with pages/). Fix double histogram observation per failed manifest fetch attempt.
DiRaiks
had a problem deploying
to
harbor_dev_release
August 4, 2026 15:31 — with
GitHub Actions
Error
DiRaiks
had a problem deploying
to
harbor_dev_release
August 4, 2026 15:31 — with
GitHub Actions
Failure
Preview stand statusDeploying... |
The develop merge switched the repo to a committed Yarn pinned by yarnPath in .yarnrc.yml; the web/api Dockerfiles only copied package.json/yarn.lock/.yarnrc.yml before install, so every yarn invocation died with ENOENT on .yarn/releases/yarn-4.17.1.cjs. Copy .yarn/releases alongside and drop corepack — the node image's stock Yarn 1 delegates to the vendored release (same pattern as develop's Dockerfile.k8s).
DiRaiks
temporarily deployed
to
harbor_dev_release
August 4, 2026 15:34 — with
GitHub Actions
Inactive
DiRaiks
temporarily deployed
to
harbor_dev_release
August 4, 2026 15:34 — with
GitHub Actions
Inactive
Audit fixes: - security: mask viem errors in every server console.* (RPC keys leaked to stdout on upstream failures); JSON-escape all window-env.js values and sed-escape CSP vars in the nginx entrypoint (a quote broke the app, `&` in report-uri corrupted the CSP / crashed the pod) - router semantics vs Next: searchQuery in the router shim (route params leaked into redirect/replace query strings), useMatch-based earn-vault checks (4 dead bracket-pattern sites), basePath from BASE_URL, ScrollRestoration, IPFS tab-active compare, dev:ipfs env sync - parity: 405+Allow on disabled proxy routes; bounded methodEncoded metric labels; SUPPORTED_CHAINS default aligned with env-dynamics (Hoodi only); CoW child-src + media-src none per infra CSP; stale-while-revalidate restored; upstream keepalive for /api/; 17 rpc-route tests - perf: route-level code splitting (only home in the entry chunk); NoSSRWrapper dropped (no SSR exists); reactive useRouterPath - cleanup: dead Next-era files/branches removed (consts/metrics, generate-build-id, revalidation group, next-app shim, isClientSide, 4 next/link sites -> plain anchors) Address validation reworked (three layers): 1. /api/validation: external service, then blocklist-file fallback server-side (broken file fail-closed), X-Validation-Source header; /api/validation-file route removed 2. api pod down (web + wallet RPCs survive a DDoS): SPA falls back to /runtime/validation.json — the same configmap served statically by the web pod nginx, prefetched per session 3. blocklist ships sha256-hashed only (helm hashes at template render, write-window-env.mjs in dev); matcher accepts plain and hashed entries Plus: cached-proxy surfaces undici cause codes in 502 bodies (`error` key only — extractErrorMessage must not leak proxy internals into UI); relative CONFIG_MANIFEST_PATH/VALIDATION_FILE_PATH resolved from repo root; startup RPC metrics silent when checks are disabled.
DiRaiks
temporarily deployed
to
harbor_dev_release
August 5, 2026 12:20 — with
GitHub Actions
Inactive
DiRaiks
temporarily deployed
to
harbor_dev_release
August 5, 2026 12:20 — with
GitHub Actions
Inactive
- centralize all QA localStorage keys in consts/qa-keys.ts (typed registry with groups/descriptors; unit test forbids inline key literals outside the registry) - drawer opens with 5 quick taps on the footer or Ctrl+Shift+8, only when enableQaHelpers is on; sections: feature flags (applied live), QA mocks with per-type input validation, external manifest mock, read-only config / window.__env__ / manifest snapshot - manifest mock is validated with the real zod ManifestEntrySchema and fail-closed to the fetched config; it deliberately does not affect the security-banner kill-switch (reads raw fetchMeta) - extract shared right-drawer shell (shared/components/drawer) from the earn side panel; earn DrawerRight reuses it, markup unchanged - revive rpcSettingsPageOnInfraIsEnabled: gates /settings and the header gear on infra builds, toggleable live from the drawer - drawer ships as a lazy chunk; tests: registry invariants, utils/qa gating, manifest-mock overlay (498 unit tests green)
DiRaiks
temporarily deployed
to
harbor_dev_release
August 6, 2026 10:08 — with
GitHub Actions
Inactive
DiRaiks
temporarily deployed
to
harbor_dev_release
August 6, 2026 10:08 — with
GitHub Actions
Inactive
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Full stack replacement behind an unchanged product surface (Vite + React SPA + Fastify").
Feature code stays in place —
next/*imports resolve to thin shims (react-router 7 / react-helmet-async), so app sources are ported, not rewritten.Frontend:
API (server/ workspace, Fastify 5, esbuild bundle):
Infra:
Removed: next + plugins, server.mjs, pages/, utilsApi/, config/csp, webpack loaders, .babelrc, next-logger (masking moved into the api).
Verified: tsc 0 errors (root+api), eslint clean, 410+31 unit tests, web +
IPFS + api builds, api smoke (health/metrics/405/rpc allowlist).
Demo
Code review notes
Testing notes
Checklist: