feat: Migrate UI from Next.js to Vite + React Router#2100
Merged
Conversation
- Install Vite, React Router, and React Helmet Async - Create Vite configuration with base path support - Create router configuration mapping all existing routes - Update entry point from _app.tsx to main.tsx with RouterProvider - Replace Next.js components: - Link -> react-router-dom Link - useRouter -> useNavigate/useLocation - Image -> native img tags - Head -> react-helmet-async Helmet - dynamic -> React.lazy with Suspense - Update all component imports and navigation - Update Layout component to use Outlet for nested routes - Fix bowser import to use default export - Update Dockerfile to use dist/ instead of out/ - Update turbo.json build outputs - Remove Next.js dependencies and config files - Update package.json scripts for Vite - Retain BASE_PATH feature with __PATH_PREFIX__ placeholder Co-authored-by: benscobie <[email protected]>
- Replace Next.js ESLint config with React/TypeScript config - Add ignores for build directories (dist, .next, out) - Install eslint-plugin-react and eslint-plugin-react-hooks - Disable pre-existing rule violations for compatibility Co-authored-by: benscobie <[email protected]>
- Move LibrariesContextProvider and ToastContainer from main.tsx to Layout component - Wrap <Outlet /> with LibrariesContextProvider to match Next.js structure - Replace all process.env.NEXT_PUBLIC_BASE_PATH with import.meta.env.VITE_BASE_PATH - Fix ApiHandler to use import.meta.env instead of process.env This resolves the "process is not defined" error and ensures proper context availability for all routes. Co-authored-by: benscobie <[email protected]>
- Restructure router to make settings routes nested under /settings parent - Add Outlet to SettingsWrapper to render child routes - All settings sub-pages (plex, sonarr, etc.) are now children of settings route - Settings index route redirects to /settings/main This ensures the settings tabs remain visible when navigating between different settings pages. Co-authored-by: benscobie <[email protected]>
- Remove NextPage type imports from all page files - Remove all 'next' package imports - Delete old Next.js page wrapper files in pages/ directory - Keep only DocsPage.tsx and PlexLoadingPage.tsx which are used by router - Remove pages/_app.tsx, pages/rules, pages/collections, pages/overview, pages/settings, etc. All pages now use standard React function components without Next.js types. Co-authored-by: benscobie <[email protected]>
Replaced all instances of `document.title =` with React Helmet's `<Helmet><title>` component across all pages and settings components: **Pages Updated:** - Overview: Maintainerr - Overview - Rules: Maintainerr - Rules - Collection: Maintainerr - Collections - AddModal: Maintainerr - Overview **Settings Pages Updated:** - Main: Maintainerr - Settings - General - Plex: Maintainerr - Settings - Plex - Sonarr: Maintainerr - Settings - Sonarr - Radarr: Maintainerr - Settings - Radarr - Overseerr: Maintainerr - Settings - Overseerr - Jellyseerr: Maintainerr - Settings - Jellyseerr - Tautulli: Maintainerr - Settings - Tautulli - Notifications: Maintainerr - Settings - Notifications - Jobs: Maintainerr - Settings - Jobs - Logs: Maintainerr - Settings - Logs - About: Maintainerr - Settings - About This provides a more React-compliant way to manage page titles and allows better integration with the existing Helmet setup in the Layout component. All titles are now managed declaratively through JSX rather than imperatively through the DOM API. Result: Zero lint errors, build succeeds in 5.9s Co-authored-by: benscobie <[email protected]>
- Updated .github/copilot-instructions.md to reflect Vite + React Router migration - Changed "Next.js frontend" to "Vite + React Router frontend" - Updated frontend tech stack (Vite, React Router, React Helmet, etc.) - Updated frontend patterns (routing, navigation, code splitting) - Updated UI structure to show router.tsx and main.tsx instead of pages router - Updated performance considerations to mention Vite HMR instead of Next.js SSG - Removed ui/README.md (outdated Next.js documentation) All documentation now accurately reflects the current Vite + React Router architecture. Co-authored-by: benscobie <[email protected]>
… of state-based navigation **Rules Routing:** - /rules - List all rules - /rules/new - Create a new rule - /rules/edit/:id - Edit an existing rule **Collections Routing:** - /collections - List all collections - /collections/:id - View collection (default to Media tab) - /collections/:id/exclusions - View collection exclusions - /collections/:id/info - View collection info **Changes:** - Created RulesListPage.tsx - Rules list with navigation to new/edit - Created RuleFormPage.tsx - Unified form for creating/editing rules (uses :id param) - Created CollectionsListPage.tsx - Collections list with navigation to details - Created CollectionDetailPage.tsx - Collection wrapper with tabs and nested routes - Created CollectionMediaPage.tsx - Media tab content - Created CollectionExclusionsPage.tsx - Exclusions tab content - Created CollectionInfoPage.tsx - Info tab content - Updated router.tsx with nested routes structure - Removed state-based navigation from original components **Navigation Improvements:** - URLs now reflect current page/tab (better for bookmarking, sharing, browser back/forward) - Clicking a collection navigates to /collections/:id instead of showing modal - Collection tabs use URL paths instead of state - Rules create/edit use URL paths instead of modal state - Browser back button works correctly with proper routing Build succeeds in 6.2s, zero lint errors (pre-existing warnings unchanged). Co-authored-by: benscobie <[email protected]>
**Bug Fixes:** 1. **Rule Edit Page Crash** - Fixed "can't access property toString, libraryId is undefined" error: - Added optional chaining in AddModal component when accessing editData.libraryId - Added error handling to RuleFormPage to catch API failures and redirect to rules list - Used editData?.libraryId instead of editData.libraryId to prevent undefined access 2. **Collection Tab Active State** - Fixed tabs not highlighting correctly when navigating: - Changed from using URL params (:tab) to using location.pathname to determine active tab - Added getCurrentTab() function that checks the full path to identify active tab - Media tab: /collections/:id (index route) - Exclusions tab: /collections/:id/exclusions - Info tab: /collections/:id/info - Now correctly highlights the active tab based on current URL **Testing:** - Build succeeds in 7.84s - Zero lint errors (only pre-existing warnings remain) - Rule edit page handles missing data gracefully - Collection tabs now show correct active state when navigating Both bugs are now resolved and the application works correctly. Co-authored-by: benscobie <[email protected]>
Fixed "can't access property 'map', props.editData.rules is undefined" error by adding optional chaining to all editData property accesses: - props.editData?.rules instead of props.editData.rules for the map operation - Added nullish coalescing (?? true) for useRules and isActive to handle undefined - Added optional chaining for collectionId and id properties This ensures the rule edit page handles all cases where editData properties might be undefined, preventing crashes when loading rule data. Build succeeds in 5.89s, zero lint errors. Co-authored-by: benscobie <[email protected]>
Co-authored-by: benscobie <[email protected]>
Contributor
Author
|
/release-pr |
Contributor
|
Released to |
Contributor
Author
|
/release-pr |
Contributor
|
Released to |
Contributor
Author
|
/release-pr |
Contributor
|
Released to |
Contributor
Author
|
/release-pr |
Contributor
|
Released to |
Contributor
Author
|
/release-pr |
Contributor
|
Released to |
Member
|
🎉 This PR is included in version 2.23.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
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.
This PR replaces Next.js with Vite + React Router 7 SPA served statically by the API. This reduced a lot of bloat, and provided a good opportunity to clean a lot of things up. Some things of note:
/rules/new,/rules/edit/2,/collections/1/exclusions. This also makes the sidebar more usable as before you could not navigate back to the overviews (fixes Menu buttons don't go back to their home pages when on a sub page #491). The links will also stay 'active' when going to the deeper pages.Maintainerrnow goes at the end, and every page should now have a good title./settings/plexto do first setup.My reasoning for moving off of Next.js is that we did not take advantage of ANY of the features of the framework, and nor did we need to. Vite fits us a lot more I think. I probably wouldn't have done this had it not been for my excessive usage of Copilot recently. I thought I'd give it a shot on this as I've been pretty impressed. I think it did pretty well, though I wish it went a bit further with code organisation, but that can be fixed later. It saved me having to do a lot of the boring boilerplate changes so that's a nice win too.
AI Summary
Summary
ui/src/router.tsx,ui/src/main.tsx, and new TanStack Query hooks while removing the old Next.js pages and contexts.PATCH /api/settingsfor partial updates..gitignore,.github/copilot-instructions.md) and refreshyarn.lock.Frontend
ui/src/router.tsxwith nestedcreateBrowserRouter, error boundary, andVITE_BASE_PATHhandling; delete all legacy Next artifacts.ui/src/main.tsxusingReactDOM.createRoot,QueryClientProvider, andRouterProvider.ui/src/api/*and deriveAPI_BASE_PATHfromimport.meta.env./rules/newfor new rules,/rules/edit/1for editing rule ID 1) instead of overloading list views, improving deep links and navigation.Backend & Contracts
PlexSetupGuard, register it in the Plex API module, and extendPlexApiServicewith setup helpers.UpdateSettingDto,PATCH /api/settings, and merge logic in the settings service; adjust rules controller/service for new UI flows.Tooling & DevOps
yarn turbo build, injectVITE_BASE_PATH, and serveui/distfromserver/dist/ui.turbo.json, workspace scripts, and.gitignorewith the Vite build output; update.github/copilot-instructions.md.yarn.lockfor new dependencies.