Skip to content

Refactor project to monorepo structure#192

Merged
xavi160 merged 15 commits into
mainfrom
monorepo
Mar 9, 2026
Merged

Refactor project to monorepo structure#192
xavi160 merged 15 commits into
mainfrom
monorepo

Conversation

@xavi160

@xavi160 xavi160 commented Feb 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR refactors the repository into an npm workspaces + Turborepo monorepo. The previous single-package layout is split into focused packages and a demo app, with the root acting only as the workspace orchestrator.


1. Root as workspace root

  • package.json: Root is now a private workspace root ("name": "root", "private": true) with workspaces: ["apps/*", "packages/*"]. Scripts delegate to Turborepo: start, build, and test run via turbo. Publishable package metadata, dependencies, and tooling were moved into the individual packages.
  • turbo.json: Added Turborepo config with tasks for build, test, and start; build/test use dependency order (dependsOn: ["^build"]) and define outputs for caching (e.g. ./dist, ./lib, ./coverage). start is persistent and not cached.
  • .gitignore: Added .turbo to ignore Turborepo logs.
  • tsconfig.json: Formatting-only change (e.g. lib and exclude on single lines).

2. New package layout

  • packages/core (@noriginmedia/norigin-spatial-navigation-core)
    Core spatial navigation logic: SpatialNavigation, VisualDebugger, WritingDirection, measureLayout, and their tests. Same code as before, moved from repo root src/ into packages/core/src/. Build and test scripts (webpack, jest) live in this package.

  • packages/react (@noriginmedia/norigin-spatial-navigation-react)
    React bindings: useFocusable, useFocusContext, and FocusContext. Depends on @noriginmedia/norigin-spatial-navigation-core. Imports from the core package instead of local paths; API unchanged.

  • packages/legacy (@noriginmedia/norigin-spatial-navigation)
    Umbrella package for backward compatibility. Re-exports core and React: export * from '@noriginmedia/norigin-spatial-navigation-core' and ...react. Consumers that depend on @noriginmedia/norigin-spatial-navigation can keep the same import and get both core and React APIs.

  • apps/react-demo (@noriginmedia/norigin-spatial-navigation-react-demo, private)
    Demo app moved from repo root into apps/react-demo. Uses the legacy package: import { useFocusable, init, FocusContext, ... } from '@noriginmedia/norigin-spatial-navigation'. Behavior and UI are unchanged (menu, content rows, assets, progress bar, etc.).

3. Changesets for versioning and releases

  • Root package.json: Changesets are wired at the workspace root. Scripts: changeset (create a new changeset), changeset:version (bump versions from changesets), and changeset:publish (publish to npm). Dev dependencies: @changesets/cli and @changesets/changelog-github.
  • .changeset/config.json: Config uses baseBranch: "main", commit: false (releases are committed by CI or manually, not by the CLI), and updateInternalDependencies: "patch" so dependents (e.g. norigin-spatial-navigation-react and the legacy package) get patch bumps when core changes. Changelog is generated with @changesets/cli/changelog; packages are published with access: "public".
  • Release workflow: The existing GitHub Actions release workflow (.github/workflows/release.yml) runs on push to main. It uses changesets/action to run changeset:version (update versions and CHANGELOGs from .changeset/*.md files) and changeset:publish (publish updated packages to npm). So the monorepo keeps a single, changeset-driven release process for the three publishable packages (core, react, and the legacy umbrella).

@xavi160 xavi160 self-assigned this Feb 9, 2026
@oleksii-pylypenko-noriginmedia

Copy link
Copy Markdown

Hey! Nice work on the monorepo split.

One thing I noticed: packages/core/package.json still has "react": ">=16.8.0" in peerDependencies, but none of the core source files actually import React (the only mentions are in comments). Looks like it was carried over from the original single-package setup.

It's not causing issues today since core is consumed through the react/legacy packages where React is already present. But once non-React adapters (Vue, Svelte, vanilla) are added down the line, their users would get React auto-installed by npm 7+ or peer warnings -- which would be confusing.

Since the goal of the split is to keep core framework-agnostic, would it make sense to drop the react peerDependency from core?

@oleksii-pylypenko-noriginmedia

Copy link
Copy Markdown

Small concern about cross-package dependencies using "*" (e.g. in packages/react/package.json, packages/legacy/package.json).

Locally this works fine because npm workspaces resolves "*" to the local symlinked package. But when published to npm, "*" goes to the registry as-is, meaning it resolves to whatever version is currently latest. If packages are published out of order or at different times, consumers could end up with mismatched versions.

Since the root already specifies "packageManager": "npm@10.9.3", you could use "workspace:*" instead. npm will automatically replace it with the real version (e.g. "^2.3.0") at publish time. No manual coordination needed.

Alternatively, if you'd prefer to keep "*", it would be good to document the required publishing order (core -> react -> legacy) somewhere so it's not easy to get wrong.

@xavi160

xavi160 commented Feb 11, 2026

Copy link
Copy Markdown
Collaborator Author

Hey! Nice work on the monorepo split.

One thing I noticed: packages/core/package.json still has "react": ">=16.8.0" in peerDependencies, but none of the core source files actually import React (the only mentions are in comments). Looks like it was carried over from the original single-package setup.

It's not causing issues today since core is consumed through the react/legacy packages where React is already present. But once non-React adapters (Vue, Svelte, vanilla) are added down the line, their users would get React auto-installed by npm 7+ or peer warnings -- which would be confusing.

Since the goal of the split is to keep core framework-agnostic, would it make sense to drop the react peerDependency from core?

yes, totally. My bad!

@xavi160

xavi160 commented Feb 11, 2026

Copy link
Copy Markdown
Collaborator Author

Small concern about cross-package dependencies using "*" (e.g. in packages/react/package.json, packages/legacy/package.json).

Locally this works fine because npm workspaces resolves "*" to the local symlinked package. But when published to npm, "*" goes to the registry as-is, meaning it resolves to whatever version is currently latest. If packages are published out of order or at different times, consumers could end up with mismatched versions.

Since the root already specifies "packageManager": "npm@10.9.3", you could use "workspace:*" instead. npm will automatically replace it with the real version (e.g. "^2.3.0") at publish time. No manual coordination needed.

Alternatively, if you'd prefer to keep "*", it would be good to document the required publishing order (core -> react -> legacy) somewhere so it's not easy to get wrong.

Tried workspace:* and it failed, not sure why. But true, I want to align this once we pick a tool to manage publishing

@changeset-bot

changeset-bot Bot commented Feb 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 160ac21

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@noriginmedia/norigin-spatial-navigation Major
@noriginmedia/norigin-spatial-navigation-react Major
@noriginmedia/norigin-spatial-navigation-core Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@xavi160
xavi160 force-pushed the monorepo branch 2 times, most recently from 714cb8e to 2af50df Compare February 13, 2026 09:55
@xavi160
xavi160 marked this pull request as ready for review February 13, 2026 11:19
predikament
predikament previously approved these changes Feb 18, 2026
@oleksii-pylypenko-noriginmedia

Copy link
Copy Markdown

packages/legacy/package.json seems to be missing webpack-cli in devDependencies. Core and react both have it. I think the build may work by accident via hoisting but could break in isolation.

@oleksii-pylypenko-noriginmedia

Copy link
Copy Markdown

release.yml uses actions/checkout@v3 and actions/setup-node@v3 which run on Node 16 (EOL). I think these should be @v4.

Comment thread packages/core/package.json Outdated
@xavi160
xavi160 requested a review from predikament March 2, 2026 14:06
predikament
predikament previously approved these changes Mar 2, 2026

@predikament predikament left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

guilleccc
guilleccc previously approved these changes Mar 4, 2026
@xavi160
xavi160 dismissed stale reviews from guilleccc and predikament via 299f88f March 9, 2026 09:41
@xavi160
xavi160 requested review from guilleccc and predikament March 9, 2026 09:42
predikament
predikament previously approved these changes Mar 9, 2026
@xavi160
xavi160 merged commit 2b25d2a into main Mar 9, 2026
1 check passed
@xavi160
xavi160 deleted the monorepo branch March 9, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants