Skip to content

NUSMods v4 phase 2: extract framework-agnostic core modules #4318

@yangshun

Description

@yangshun

Summary

We want to rewrite website to Next.js while reducing lock-in to the metaframework. This issue tracks extracting framework-agnostic domain logic into standalone modules before / during the rewrite.

Goals

  • Isolate domain logic from routing, rendering, browser APIs, and Next.js runtime concerns.
  • Improve reuse across frontend, server routes, and tooling.
  • Reduce migration risk by moving high-confidence pure logic first.

Proposed module split

1) @nusmods/timetable-core (high priority)

Extract from website/src/utils:

  • timetables.ts
  • timify.ts
  • colors.ts
  • optimiser.ts

Scope:

  • Timetable modeling / validation
  • Lesson arrangement and clash logic
  • Serialization / deserialization
  • Optimiser data transformations

2) @nusmods/planner-core

Extract:

  • website/src/utils/planner.ts
  • Pure planner selectors from website/src/selectors/planner.ts (after decoupling config/state access)

Scope:

  • Prereq/conflict evaluation
  • Planner domain invariants
  • Planner text formatting for conflicts (non-UI)

3) @nusmods/nus-data-client

Extract:

  • website/src/apis/nusmods.js
  • Typed request clients from website/src/apis/{nextbus,weather,optimiser}.ts

Scope:

  • Endpoint builders
  • API request/response typing
  • Transport adapter boundary (fetch/axios injectable)

4) @nusmods/route-schema

Extract:

  • Pure path builders/parsers from website/src/views/routes/paths.ts

Scope:

  • Route generation / parsing
  • Share URL construction

Note:

  • absolutePath() is browser-dependent and should remain as an app runtime helper.

Keep in Next.js app layer (not standalone)

  • React view components (website/src/views/**)
  • App entry/bootstrap (website/src/entry/**, website/src/bootstrapping/**)
  • Redux wiring / persistence setup (configure-store, persistence adapters)
  • Browser-only utilities (insertScript, localStorage wrappers, window/document helpers)
  • Serverless platform wrappers (website/src/serverless/**, Vercel-specific handler wrappers)

Refactor prerequisites

  • Split React/text helpers from domain helpers:
    • website/src/utils/modules.ts and website/src/utils/weekText.ts currently depend on utils/react.tsx
  • Remove side effects from reducers before extraction:
    • reducers/theme.ts and reducers/settings.ts call Matomo tracking; move tracking to middleware/effects.

Implementation plan (incremental)

  1. Extract @nusmods/timetable-core with tests migrated first.
  2. Extract @nusmods/nus-data-client and @nusmods/route-schema.
  3. Extract @nusmods/planner-core.
  4. Replace imports in website with package imports.
  5. Start Next.js app migration with extracted modules as stable dependencies.

Acceptance criteria

  • New packages created under packages/ with clear public APIs.
  • Existing tests for extracted logic pass in package scope.
  • website consumes extracted packages (no duplicated logic).
  • No framework-specific imports in extracted package entrypoints.
  • Migration doc added describing dependency boundaries and ownership.

Out of scope

  • Full React component rewrite
  • Styling system migration
  • Serverless deployment replatforming

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions