Skip to content

Support local workspace development of frontend apps #184

@arbrandes

Description

@arbrandes

Summary

Enable developers to work on frontend apps (e.g., frontend-app-authn, frontend-app-learner-dashboard) and frontend-base itself locally, using npm workspaces. This applies both to site templates like frontend-template-site and to individual apps developing against a local frontend-base.

Note that this method is likely to fit nicely with tutor dev, since it also relies on bind mounts. I actually arrived at this proposal while researching a way to make app forks work with Tutor in production mode: it just so happens that it works for development (and without Tutor) just as well.

Problem

Currently, developing changes to frontend apps requires publishing to npm or using workarounds such as autoinstall, which currently only works for frontend-base, or yalc, which while generic, is unmaintained upstream. Both workarounds also make changes to package.json in target repos, which is painful since they should never be committed. Both are also comparatively slow, and are not particularly suited for Docker-based development.

Thus, there's no simple and efficient workflow for iterating on multiple packages simultaneously in the context of a running site, or for developing an app against a local copy of frontend-base.

Proposed Approach

Use npm workspaces with a packages/ directory (gitignored) to hold local checkouts of packages being developed. These are development-only overrides of the npm-published versions: no dependency-specific changes need to be made to package.json. If a package doesn't have a local checkout in packages/, the regular dependency is used.

This applies at two levels:

  1. Site templatefrontend-template-site can have any combination of frontend-base and frontend apps as workspace packages, with Turborepo orchestrating builds in dependency order.

  2. Individual apps — Apps like frontend-app-learner-dashboard can have frontend-base as a workspace package for independent development, using concurrently for orchestration (sufficient for the simpler dependency tree, but we can always go with Turborepo here too).

Key pieces:

  1. Workspace configuration"workspaces": ["packages/*"] in package.json, with packages/ in .gitignore.

  2. Mounting local checkouts — Since symlinks cause module resolution failures (Node.js/TypeScript resolve to the real path, breaking hoisted dependency resolution), local checkouts should be made available via bind mounts (sudo mount --bind or FUSE's bindfs) or Docker volume mounts, both of which present the directory as a real path within the project tree.

  3. Build orchestration — At the site template level, workspace packages must be built in dependency order (e.g., frontend-base before apps that depend on it). Turborepo handles this via dependsOn: ["^build"] in turbo.json. At the app level, concurrently is sufficient since there's only one dependency (frontend-base). The openedx CLI could eventually provide this natively.

  4. Watch mode without race conditions — The current make build target starts with rm -rf dist, which causes race conditions when watch scripts and the dev server run concurrently. The clean target must be decoupled from build, so that watch rebuilds overwrite in place without wiping dist/. The prepack script should explicitly run clean && build to preserve clean builds for publishing.

Changes Required

In frontend-base:

  • Decouple clean from build in the Makefile
  • Update prepack to explicitly run clean && build
  • Add a watch:build npm script and a generic nodemon.json

In frontend apps (frontend-app-authn, frontend-app-learner-dashboard, etc.):

  • Same Makefile decoupling of clean from build
  • Add workspaces field, packages/ to .gitignore
  • Add concurrently, nodemon as dev dependencies
  • Add workspace-aware scripts (build:packages, dev:packages, watch:build)
  • Add nodemon.json for watch configuration

In frontend-template-site:

  • Add workspaces field, packages/ to .gitignore
  • Add turbo.json for build orchestration
  • Add workspace-aware scripts (build:packages, clean:packages, dev:packages)

PRs

Trying it out

If you have all of the above checked out cleanly as siblings (like many of us often do):

cd frontend-template-site
mkdir -p packages/{frontend-base,frontend-app-authn,frontend-app-learner-dashboard}
cd packages
for i in *; do sudo mount --bind ../../${i} ${i}; done
cd ..
npm install
npm run dev:packages

This should get you a tutor dev-compatible site deployment, in such a way that if you make changes to any of the dependencies, they'll show up automatically on the page.

For the future

If we for some reason start disliking the additional devDependencies (concurrently or turbo), we can consider adding the specific features we want out of them to the openedx CLI.

I don't recommend doing this now - or maybe ever - because more modern package managers (pnpm, etc) may handle our workspace needs without custom code or dependencies. In other words: let's wait and see.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

Status

In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions