chore(app): src/* path alias + migrate all relative imports#8520
Conversation
- Add prettier + eslint-config-prettier (formatting, run separately from ESLint) - Add eslint-plugin-perfectionist (sorted imports with semantic groups) and eslint-plugin-unused-imports - Replace ~60 hand-maintained browser globals in eslint.config.js with the globals package; disable no-undef for TS files (tsc covers it) - Add tsconfig.test.json so test files are finally type-checked - Add vite-plugin-checker: TS + ESLint overlay during yarn dev (addresses the latent-tsc-error-breaks-Cloud-Build failure mode) - New scripts: lint:fix, fm:check, fm:fix, fix:all; type-check now covers tests - CI: test-frontend job now runs lint, fm:check, and type-check before tests Part 1 of the frontend modernization roadmap (Minimal-template-inspired structure; patterns only, no template code). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pure formatting commit, no logic changes: sorted imports (perfectionist groups) and Prettier formatting across app/ sources. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PR #8499 (MUI 9.1.0) was merged with the frontend test check red: MUI's internal/Transition.mjs imports react-transition-group/TransitionGroupContext as a directory import, which Node's native ESM loader rejects, failing 11 test files on main. Inlining @mui/* lets Vite's resolver handle it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Test files were never type-checked and had drifted from the real types (63 errors across 12 files): mocks missing the required language property (added with the JS-libraries expansion), global.fetch instead of globalThis.fetch, untyped vi.fn() mocks, a never-returning throw component, and Array.prototype.at not in the lib target. All fixed without weakening any test assertions; 536 tests still pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot review finding: the mock exposed a nonexistent cache field and omitted getCode/isLoading, hiding contract drift from the test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- tsconfig.json: paths { "src/*": ["./src/*"] } (no baseUrl — deprecated in TS 6)
- vite.config.ts + vitest.config.ts: matching resolve.alias
- Rewrite all 429 relative specifiers (imports, dynamic import(), vi.mock)
across 118 files to absolute src/ paths; purely mechanical
Part 2 of the frontend modernization roadmap.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a consistent src/* path alias to the frontend build/test toolchain and migrates the app codebase away from relative import specifiers, aligning with the import-grouping conventions introduced in #8519.
Changes:
- Added
src/*path mapping intsconfig.jsonand matchingresolve.aliasin both Vite and Vitest configs. - Mechanically migrated frontend source + test imports (including dynamic
import()andvi.mock()specifiers) tosrc/...absolute specifiers. - Updated barrel exports (
src/hooks,src/utils) to re-export viasrc/...paths.
Reviewed changes
Copilot reviewed 145 out of 148 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| app/vitest.config.ts | Add resolve.alias for src so Vitest can resolve src/... specifiers. |
| app/vite.config.ts | Add resolve.alias for src so Vite can resolve src/... specifiers. |
| app/tsconfig.json | Add TS paths mapping for src/*. |
| app/src/utils/tooltip.test.ts | Migrate imports to src/.... |
| app/src/utils/themedPreview.ts | Migrate imports to src/.... |
| app/src/utils/shuffle.test.ts | Migrate imports to src/.... |
| app/src/utils/responsiveImage.ts | Migrate imports to src/.... |
| app/src/utils/responsiveImage.test.ts | Migrate imports to src/.... |
| app/src/utils/index.ts | Re-export via src/... specifiers. |
| app/src/utils/fuzzySearch.test.ts | Migrate imports to src/.... |
| app/src/utils/filters.ts | Migrate imports to src/.... |
| app/src/utils/filters.test.ts | Migrate imports to src/.... |
| app/src/utils/filters-extended.test.ts | Migrate imports to src/.... |
| app/src/utils/claudePrompt.test.ts | Migrate imports to src/.... |
| app/src/router.tsx | Migrate imports + lazy route dynamic imports to src/.... |
| app/src/pages/StatsPage.tsx | Migrate imports to src/.... |
| app/src/pages/StatsPage.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/pages/SpecsListPage.tsx | Migrate imports to src/.... |
| app/src/pages/SpecsListPage.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/pages/SpecPage.tsx | Migrate imports and component lazy imports to src/.... |
| app/src/pages/SpecPage.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/pages/PlotsPage.tsx | Migrate imports to src/.... |
| app/src/pages/PlotsPage.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/pages/PalettePage.tsx | Migrate imports (incl. JSON import) to src/.... |
| app/src/pages/PalettePage.snippet.test.ts | Migrate imports to src/.... |
| app/src/pages/NotFoundPage.tsx | Migrate imports to src/.... |
| app/src/pages/NotFoundPage.test.tsx | Migrate imports to src/.... |
| app/src/pages/McpPage.tsx | Migrate imports to src/.... |
| app/src/pages/McpPage.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/pages/MapPage.tsx | Migrate imports (incl. helpers) to src/.... |
| app/src/pages/MapPage.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/pages/MapPage.helpers.ts | Migrate imports to src/.... |
| app/src/pages/MapPage.helpers.test.ts | Migrate imports to src/.... |
| app/src/pages/LibrariesPage.tsx | Migrate imports to src/.... |
| app/src/pages/LibrariesPage.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/pages/LegalPage.tsx | Migrate imports to src/.... |
| app/src/pages/LegalPage.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/pages/LandingPage.tsx | Migrate imports to src/.... |
| app/src/pages/LandingPage.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/pages/DebugPage.tsx | Migrate imports to src/.... |
| app/src/pages/DebugPage.test.tsx | Migrate imports to src/.... |
| app/src/pages/AboutPage.tsx | Migrate imports to src/.... |
| app/src/main.tsx | Migrate style and module imports to src/.... |
| app/src/hooks/useUrlSync.ts | Migrate imports to src/.... |
| app/src/hooks/useUrlSync.test.ts | Migrate imports to src/.... |
| app/src/hooks/useThemeMode.test.ts | Migrate imports to src/.... |
| app/src/hooks/usePlotOfTheDay.ts | Migrate imports to src/.... |
| app/src/hooks/useLocalStorage.test.ts | Migrate imports to src/.... |
| app/src/hooks/useLayoutContext.ts | Migrate type-only imports to src/.... |
| app/src/hooks/useLayoutContext.test.ts | Migrate imports to src/.... |
| app/src/hooks/useLatestRelease.test.ts | Migrate imports to src/.... |
| app/src/hooks/useInfiniteScroll.ts | Migrate imports to src/.... |
| app/src/hooks/useInfiniteScroll.test.ts | Migrate imports to src/.... |
| app/src/hooks/useFilterState.ts | Migrate imports to src/.... |
| app/src/hooks/useFilterState.test.ts | Migrate imports to src/.... |
| app/src/hooks/useFilterState-imagesKey.test.ts | Migrate imports to src/.... |
| app/src/hooks/useFilterState-extended.test.ts | Migrate imports to src/.... |
| app/src/hooks/useFilterFetch.ts | Migrate imports to src/.... |
| app/src/hooks/useFilterFetch.test.ts | Migrate imports to src/.... |
| app/src/hooks/useFeaturedSpecs.ts | Migrate imports to src/.... |
| app/src/hooks/useCopyCode.test.ts | Migrate imports to src/.... |
| app/src/hooks/useCodeFetch.ts | Migrate imports to src/.... |
| app/src/hooks/useCodeFetch.test.ts | Migrate imports to src/.... |
| app/src/hooks/useAnalytics.ts | Migrate imports to src/.... |
| app/src/hooks/useAnalytics.test.ts | Migrate imports to src/.... |
| app/src/hooks/index.ts | Re-export hooks via src/... specifiers. |
| app/src/components/TypewriterText.tsx | Migrate imports to src/.... |
| app/src/components/ToolbarActions.tsx | Migrate imports to src/.... |
| app/src/components/ToolbarActions.test.tsx | Migrate imports to src/.... |
| app/src/components/ThemeToggle.tsx | Migrate imports to src/.... |
| app/src/components/SpecTabs.tsx | Migrate imports + lazy import to src/.... |
| app/src/components/SpecTabs.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/SpecOverview.tsx | Migrate imports to src/.... |
| app/src/components/SpecOverview.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/SpecDetailView.tsx | Migrate imports to src/.... |
| app/src/components/SpecDetailView.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/SectionHeader.tsx | Migrate imports to src/.... |
| app/src/components/SectionHeader.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/ScienceNote.tsx | Migrate imports to src/.... |
| app/src/components/RouteErrorBoundary.tsx | Migrate imports to src/.... |
| app/src/components/RouteErrorBoundary.test.tsx | Migrate imports to src/.... |
| app/src/components/RootLayout.tsx | Migrate imports to src/.... |
| app/src/components/RootLayout.test.tsx | Migrate vi.mock() specifiers to src/.... |
| app/src/components/RelatedSpecs.tsx | Migrate imports to src/.... |
| app/src/components/RelatedSpecs.test.tsx | Migrate imports (incl. dynamic import) to src/.... |
| app/src/components/PlotOfTheDayTerminal.tsx | Migrate imports to src/.... |
| app/src/components/PlotOfTheDayTerminal.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/PlotOfTheDay.tsx | Migrate imports to src/.... |
| app/src/components/PlotOfTheDay.test.tsx | Migrate imports (incl. dynamic import) and vi.mock() specifiers to src/.... |
| app/src/components/NumbersStrip.tsx | Migrate imports to src/.... |
| app/src/components/NavBar.tsx | Migrate imports to src/.... |
| app/src/components/NavBar.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/MastheadRule.tsx | Migrate imports to src/.... |
| app/src/components/MastheadRule.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/LoaderSpinner.tsx | Migrate imports to src/.... |
| app/src/components/LoaderSpinner.test.tsx | Migrate imports to src/.... |
| app/src/components/LibraryPills.tsx | Migrate imports to src/.... |
| app/src/components/LibraryPills.test.tsx | Migrate imports to src/.... |
| app/src/components/LibraryCard.tsx | Migrate imports to src/.... |
| app/src/components/LibraryCard.test.tsx | Migrate imports to src/.... |
| app/src/components/LibrariesSection.tsx | Migrate imports to src/.... |
| app/src/components/Layout.tsx | Migrate imports to src/.... |
| app/src/components/Layout.test.tsx | Migrate imports to src/.... |
| app/src/components/ImagesGrid.tsx | Migrate imports to src/.... |
| app/src/components/ImagesGrid.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/ImageCard.tsx | Migrate imports to src/.... |
| app/src/components/ImageCard.test.tsx | Migrate imports (incl. dynamic import) and vi.mock() specifiers to src/.... |
| app/src/components/HeroSection.tsx | Migrate imports to src/.... |
| app/src/components/HeroSection.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/Footer.tsx | Migrate imports to src/.... |
| app/src/components/Footer.test.tsx | Migrate imports to src/.... |
| app/src/components/FilterBar.tsx | Migrate imports to src/.... |
| app/src/components/FilterBar.test.tsx | Migrate imports and vi.mock() specifiers to src/.... |
| app/src/components/FeedbackWidget.tsx | Migrate imports to src/.... |
| app/src/components/FeedbackWidget.test.tsx | Migrate imports to src/.... |
| app/src/components/ErrorBoundary.test.tsx | Migrate imports to src/.... |
| app/src/components/CodeShowcase.tsx | Migrate imports to src/.... |
| app/src/components/CodeHighlighter.tsx | Migrate imports to src/.... |
| app/src/components/CodeHighlighter.test.tsx | Migrate imports to src/.... |
| app/src/analytics/reportWebVitals.ts | Migrate imports to src/.... |
| app/src/analytics/reportWebVitals.test.ts | Migrate imports to src/.... |
|
|
||
| import { beforeEach, describe, expect, it, vi } from 'vitest'; | ||
|
|
||
| // Must import after test-utils to get jest-dom matchers |
There was a problem hiding this comment.
Applied — all vi.importActual specifiers (13 across 9 test files) now use the src/ alias, matching their vi.mock counterparts; the stale jest-dom import-order comment is removed. See latest commit.
| const actual = | ||
| await vi.importActual<typeof import('src/hooks/useAnalytics')>('../hooks/useAnalytics'); |
There was a problem hiding this comment.
Applied — all vi.importActual specifiers (13 across 9 test files) now use the src/ alias, matching their vi.mock counterparts; the stale jest-dom import-order comment is removed. See latest commit.
| const actual = await vi.importActual<typeof import('src/hooks/useLayoutContext')>( | ||
| '../hooks/useLayoutContext' | ||
| ); |
There was a problem hiding this comment.
Applied — all vi.importActual specifiers (13 across 9 test files) now use the src/ alias, matching their vi.mock counterparts; the stale jest-dom import-order comment is removed. See latest commit.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…rite
Copilot review findings: vi.importActual<typeof import('src/...')>('../...')
calls kept relative runtime specifiers because the type parameter sat between
the function name and the call paren; aligned all 13 to the src/ alias so
mock and importActual reference the same module ID. Also dropped a stale
import-order comment in ErrorBoundary.test.tsx (jest-dom loads via
setupTests.ts).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| import { specPath } from 'src/utils/paths'; | ||
|
|
||
| const SpecTabs = lazy(() => import('src/components/SpecTabs').then(m => ({ default: m.SpecTabs }))); | ||
| const SpecOverview = lazy(() => | ||
| import('../components/SpecOverview').then(m => ({ default: m.SpecOverview })) | ||
| import('src/components/SpecOverview').then(m => ({ default: m.SpecOverview })) | ||
| ); | ||
| const SpecDetailView = lazy(() => | ||
| import('../components/SpecDetailView').then(m => ({ default: m.SpecDetailView })) | ||
| import('src/components/SpecDetailView').then(m => ({ default: m.SpecDetailView })) | ||
| ); | ||
| import type { Implementation } from '../types'; | ||
| import type { Implementation } from 'src/types'; |
| const CodeHighlighter = lazy(() => import('src/components/CodeHighlighter')); | ||
| import { API_URL } from 'src/constants'; | ||
| import { colors, fontSize, semanticColors, typography } from 'src/theme'; |
…tion (#8596) ## Summary Part 11 (final) of the frontend modernization roadmap. - **`app/ARCHITECTURE.md`**: directory layout (routes/layouts/pages/sections/components/hooks/lib/theme), conventions (`src/` alias imports, `paths.*` URL registry, `lib/api` client, theme tokens, feature folders), data flow, testing pattern, quality gates, and how-to-add recipes for pages/sections/hooks/endpoints - **`agentic/docs/project-guide.md`**: frontend section now lists the full gate (`lint`, `fm:check`, `type-check` incl. tests, `test`), mentions the dev-time checker overlay, and links the new architecture doc With this, the roadmap is complete: tooling baseline (#8519), src/ aliases (#8520), theme split (#8525), global-config (#8529), API client (#8531), routes registry (#8546), structure split (#8547), FilterBar (#8559), SpecTabs (#8564), MapPage hook (#8581). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
Part 2 of the frontend modernization roadmap — stacked on #8519 (base =
chore/frontend-tooling-baseline; GitHub will auto-retarget this PR tomainonce #8519 merges and its branch is deleted).tsconfig.json:paths: { "src/*": ["./src/*"] }— nobaseUrl(deprecated in TS 6; paths resolve relative to the tsconfig since TS 4.1)vite.config.tsandvitest.config.ts: matchingresolve.alias(vitest does not inherit vite's)src/…imports — coversimport … from, side-effect imports, dynamicimport()(lazy routes), andvi.mock()specifiers. Purely mechanical, no logic changes.Template-style
src/prefix chosen over@/: unambiguous (no npm-scope confusion) and groups cleanly under the perfectionistinternalimport group introduced in #8519.Verification
yarn lint(0 errors) ·yarn fm:check✓ ·yarn type-check(app + tests) ✓ ·yarn test536/536 ✓ ·yarn build✓ ·grepconfirms 0 remaining relative imports inapp/src🤖 Generated with Claude Code