281 lines
13 KiB
Markdown
281 lines
13 KiB
Markdown
# Vue Refactor Plan
|
|
|
|
## Purpose
|
|
|
|
Refactor the map renderer from a large vanilla JavaScript application into a Vue application while preserving its two deployment modes:
|
|
|
|
- Static mode for GitHub Pages and other read-only deployments
|
|
- Dynamic local mode for catalog editing and local data updates
|
|
|
|
The refactor should reduce the size and complexity of the current `src/public/app.js` entrypoint without breaking the existing viewer behavior, static export workflow, or catalog editing workflow.
|
|
|
|
## Current Baseline
|
|
|
|
The renderer already has a useful split between source files and deployment artifacts:
|
|
|
|
- `src/public/app.js` currently orchestrates most of the browser app.
|
|
- `src/public/map-catalog-ui.js`, `src/lib/catalog.js`, and related modules already isolate some catalog logic.
|
|
- `site/` contains the committed static bundle used for GitHub Pages.
|
|
- `package.json` already exposes separate static and dynamic scripts.
|
|
- The root README already documents static versus dynamic usage.
|
|
|
|
That means the migration should be an incremental extraction, not a from-scratch rewrite.
|
|
|
|
## Non-Negotiable Requirements
|
|
|
|
1. Keep a static deployable build that can run from committed artifacts with no file-system write capability.
|
|
2. Keep a dynamic local build that can edit the Catalog and write changes back to disk.
|
|
3. Preserve the existing viewer workflow during migration so the app remains usable at every step.
|
|
4. Keep catalog editing opt-in and unavailable in static deployments.
|
|
5. Avoid coupling the UI framework change to data format changes unless a boundary must move for architectural reasons.
|
|
|
|
## Target Architecture
|
|
|
|
The Vue refactor should split the app into four layers:
|
|
|
|
1. App shell and routing-like mode selection
|
|
- Owns top-level mode detection: static versus dynamic.
|
|
- Chooses the correct feature set, status messages, and edit affordances.
|
|
- Remains thin and delegates real work to feature components and composables.
|
|
|
|
2. View components
|
|
- Replace the current procedural DOM wiring with Vue components for the map controls, viewport, catalog panel, tooltips, modal editor, and export actions.
|
|
- Keep components small and purpose-specific.
|
|
- Prefer composition over a single mega component.
|
|
|
|
3. Composables and state services
|
|
- Move map selection, build triggers, UI flags, and interaction state into composables or store-like modules.
|
|
- Keep business rules out of templates.
|
|
- Preserve existing helper modules where they already work.
|
|
|
|
4. Data access adapters
|
|
- Introduce a strict boundary between read-only data access and writable catalog access.
|
|
- Static mode uses read-only adapters only.
|
|
- Dynamic mode uses writable adapters for catalog updates and local server APIs.
|
|
|
|
## Mode Model
|
|
|
|
The app should continue to behave as one codebase with two runtime modes.
|
|
|
|
### Static Mode
|
|
|
|
- Serves prebuilt assets from `site/` or equivalent deployed output.
|
|
- Allows viewing, filtering, inspecting, and downloading data.
|
|
- Does not expose any actions that would write to disk or call write-enabled server endpoints.
|
|
- Can still show the Catalog UI if the data is available, but all editing controls must be removed or disabled.
|
|
|
|
### Dynamic Mode
|
|
|
|
- Runs against the local Node server.
|
|
- Can edit Catalog data through the UI.
|
|
- Can write CSV updates to disk.
|
|
- Can refresh or rebuild derived data as needed after edits.
|
|
- Must preserve the same viewer experience as static mode wherever the data model overlaps.
|
|
|
|
## Proposed Migration Phases
|
|
|
|
### Phase 0: Freeze the boundary
|
|
|
|
Goal: identify the stable interfaces before moving UI code.
|
|
|
|
- Inventory the current `app.js` responsibilities.
|
|
- Group code into categories: rendering, state mutation, map loading, catalog updates, overlays, modals, downloads, and notifications.
|
|
- Identify the minimum data contracts between the viewer, catalog, and scene APIs.
|
|
- Decide which existing helper modules stay unchanged and which become composables or services.
|
|
|
|
Deliverable:
|
|
|
|
- A written boundary map for the current app and a component breakdown for Vue.
|
|
|
|
### Phase 1: Scaffold Vue without changing behavior
|
|
|
|
Goal: get Vue running while preserving the current app.
|
|
|
|
- Create a Vue 3 application shell.
|
|
- Move the current page layout into Vue root components.
|
|
- Keep the existing data modules and API helpers in place.
|
|
- Mount the viewer in Vue but continue using the current scene and catalog logic.
|
|
- Add a compatibility layer so existing DOM-driven utilities can be replaced one section at a time.
|
|
|
|
Deliverable:
|
|
|
|
- The app loads through Vue, but functionality remains equivalent to the current version.
|
|
|
|
### Phase 2: Split the UI into feature components
|
|
|
|
Goal: remove the largest chunks of imperative DOM code.
|
|
|
|
- Break the viewer into components such as header/control bar, map selector, viewport, catalog panel, export area, status area, and editor modal.
|
|
- Move local UI state into Vue reactive state or composables.
|
|
- Replace direct DOM updates with props, emits, and computed state.
|
|
- Keep the map rendering and scene logic isolated so the UI migration does not change map semantics.
|
|
|
|
Deliverable:
|
|
|
|
- The main app flow no longer depends on a monolithic procedural entrypoint.
|
|
|
|
### Phase 3: Formalize static and dynamic adapters
|
|
|
|
Goal: separate read-only rendering from writable editing behavior.
|
|
|
|
- Introduce a read-only adapter for static deploys.
|
|
- Introduce a writable adapter for the local Catalog editor.
|
|
- Make the app choose adapters based on mode, not scattered conditionals.
|
|
- Ensure static mode cannot accidentally call writable endpoints.
|
|
- Ensure dynamic mode can still perform all current editor actions.
|
|
|
|
Deliverable:
|
|
|
|
- The same Vue UI can run in both modes without leaking write capability into static builds.
|
|
|
|
### Phase 4: Migrate Catalog editing carefully
|
|
|
|
Goal: preserve catalog edit power while moving to Vue.
|
|
|
|
- Port the current catalog editor interactions into Vue components.
|
|
- Keep edit forms, validation, and confirmation behavior intact.
|
|
- Preserve undo or session history behavior if it exists in the current app.
|
|
- Verify that write operations remain local-only and mode-gated.
|
|
- Confirm that static builds either hide the edit UI or render it inert.
|
|
|
|
Deliverable:
|
|
|
|
- Catalog editing works in dynamic mode and is unreachable in static mode.
|
|
|
|
### Phase 5: Clean up the old entrypoint
|
|
|
|
Goal: remove dead code and simplify maintenance.
|
|
|
|
- Delete or shrink the legacy procedural bootstrap code only after feature parity is reached.
|
|
- Move any remaining helpers into reusable modules or composables.
|
|
- Remove duplicate state management paths.
|
|
- Keep the public API surface stable where external scripts or tests depend on it.
|
|
|
|
Deliverable:
|
|
|
|
- Vue owns the app; the old entrypoint is no longer the main coordination layer.
|
|
|
|
## Suggested Component Breakdown
|
|
|
|
The exact component names can change, but the refactor should likely include:
|
|
|
|
- AppShell: top-level mode detection, configuration, and page layout.
|
|
- MapSelector: map and game selection, navigation, and load triggers.
|
|
- ViewerViewport: canvas or scene host, pointer handling, and zoom state.
|
|
- EditorToolbar: view toggles, overlays, and map display controls.
|
|
- CatalogPanel: catalog browsing, download buttons, and edit affordances.
|
|
- CatalogEditModal: edit form and validation.
|
|
- StatusBar: loading, build, and error feedback.
|
|
- TooltipOverlay: pinned or hover inspection UI.
|
|
- DownloadActions: export buttons and static bundle downloads.
|
|
|
|
## Data and State Boundaries
|
|
|
|
The refactor should make these boundaries explicit:
|
|
|
|
- Scene loading state: selected map, build progress, current assets, and error state.
|
|
- View state: zoom, pan, overlays, tooltip pinning, and selection.
|
|
- Catalog state: active game, catalog entries, edit permissions, and pending writes.
|
|
- Environment state: static versus dynamic mode, feature flags, and API base URLs.
|
|
|
|
Rule of thumb:
|
|
|
|
- If state is shared across multiple UI regions, it belongs in a composable or store.
|
|
- If state only matters inside one panel or modal, keep it local to that component.
|
|
|
|
## Static Build Plan
|
|
|
|
The static build must remain a first-class deployment target.
|
|
|
|
- Keep the committed site output deployable without server writes.
|
|
- Make the Vue build emit a static artifact suitable for GitHub Pages.
|
|
- Ensure all catalog editing UI is absent or disabled in the static bundle.
|
|
- Keep download links and read-only inspection available.
|
|
- Preserve the existing export workflow so the static bundle can be regenerated from local source assets.
|
|
|
|
## Dynamic Build Plan
|
|
|
|
The dynamic build must preserve local editing capability.
|
|
|
|
- Keep the local server as the source of truth for writable catalog changes.
|
|
- Preserve file write paths and validation rules.
|
|
- Continue to support local refresh or rebuild behavior after edits.
|
|
- Keep the editing workflow explicit so the writable mode cannot be mistaken for the static deploy.
|
|
|
|
## Suggested Repo Changes
|
|
|
|
The migration will probably require these changes:
|
|
|
|
- Introduce a Vue source directory under `map_renderer/src` or a sibling frontend directory.
|
|
- Add a Vue build pipeline and update package scripts.
|
|
- Split the current DOM utility modules into composables, services, and small components.
|
|
- Add a mode/config module that clearly states whether the app is static or dynamic.
|
|
- Update export scripts so the static site still writes the correct committed artifacts.
|
|
- Update the README with the new build and deployment flow once the migration is stable.
|
|
|
|
## Risks
|
|
|
|
- The biggest risk is mixing UI migration with behavior changes and losing parity.
|
|
- The second risk is accidentally allowing edit controls into the static bundle.
|
|
- The third risk is over-centralizing state in one large Vue store and recreating the same maintainability problem in a new framework.
|
|
- The fourth risk is changing the export pipeline before the static and dynamic modes are fully separated.
|
|
|
|
## Acceptance Criteria
|
|
|
|
The refactor is complete when all of the following are true:
|
|
|
|
1. The app runs as a Vue application.
|
|
2. The static bundle still deploys and remains read-only.
|
|
3. The dynamic local build still supports Catalog editing and writes to disk.
|
|
4. The main viewer flows match the current behavior closely enough that no feature regression is visible in normal use.
|
|
5. The old procedural entrypoint is no longer the primary app coordinator.
|
|
6. The codebase is easier to extend because UI, state, and data access are separated.
|
|
|
|
## Recommended Order of Work
|
|
|
|
1. Inventory the current app responsibilities and define component boundaries.
|
|
2. Scaffold Vue and mount the existing app behind it.
|
|
3. Extract the largest UI regions into Vue components.
|
|
4. Introduce explicit static and dynamic data adapters.
|
|
5. Port catalog editing into Vue while keeping write capability local-only.
|
|
6. Remove the leftover procedural bootstrap code.
|
|
7. Update the docs and deployment instructions.
|
|
|
|
## Concrete Implementation Checklist
|
|
|
|
### Phase 1 Checklist
|
|
|
|
1. Add Vue 3 and Vite dependencies to the renderer package.
|
|
2. Add Vite scripts for development and production builds without removing the existing Node server scripts.
|
|
3. Create a new Vue entrypoint that mounts a root app shell into the current page layout.
|
|
4. Keep the existing static HTML usable during the transition by preserving the current shell structure and mount target.
|
|
5. Split the top-level UI into a Vue root component plus a small compatibility layer for existing state and API helpers.
|
|
6. Keep read-only viewer behavior intact during the initial scaffold so the app still loads maps exactly as before.
|
|
7. Confirm that static mode still hides all write-capable catalog controls.
|
|
8. Confirm that dynamic mode still exposes catalog-edit affordances after the Vue shell is in place.
|
|
|
|
### Phase 1 Exit Criteria
|
|
|
|
1. The renderer can be built and served through Vue/Vite.
|
|
2. The current viewer still loads and renders maps.
|
|
3. The static deployment path remains read-only.
|
|
4. The dynamic deployment path remains capable of catalog editing.
|
|
5. The old entrypoint is no longer the only place that owns page-level structure.
|
|
|
|
### Phase 1 Progress
|
|
|
|
- Vue 3 and Vite scripts have been added to the renderer package.
|
|
- A Vue shell now renders the existing viewer DOM structure.
|
|
- The Vue shell loads the legacy browser app after mount so the current viewer logic remains active.
|
|
- The Vue production build completes successfully.
|
|
- The local dev and admin launchers now wait for the Vue build output and then start the server on the Vue-preferred path.
|
|
|
|
### Phase 2 Progress
|
|
|
|
- The Vue shell has been split into separate shell components for the side panel, viewport, and egg editor modal.
|
|
- The root Vue app now composes those feature components instead of keeping the entire shell in one template file.
|
|
- The default local runtime path now serves the Vue build when it exists, so the componentized shell is the main entry for dev and admin modes.
|
|
|
|
## Final Notes
|
|
|
|
The best outcome here is not a perfect one-shot rewrite. It is a controlled migration that keeps the current app working, makes the static and dynamic deployment split explicit, and steadily moves the renderer toward a maintainable Vue architecture.
|