Frontend-base development with yalc
As an alternative to the npm pack => npm install *.tgz development flow, one can use the yalc command to automate the process. The end result is the same - dependency resolution that is as similar to production-use as possible - but with little cognitive load and optimized system resource consumption.
Start by installing this fork of yalc locally, as the original doesn’t have the --peer feature we need (plus, it hasn’t been maintained in a while):
npm i -g @arbrandes/yalcThe frontend-base repo
Publish the version of frontend-base you’re developing to the local “npm” repository:
cd frontend-base
yalc publishApp repositories
In app repos, yalc-add the local version of frontend-base before running npm i. This is so any updated frontend-base dependencies are properly installed. We also use the --peer flag because @openedx/frontend-base is a peer dependency in app packages (remember, we want to keep this as close to production as possible):
cd ../frontend-app-authn
yalc add --peer @openedx/frontend-base
rm -fr package-lock.json node_modules
npm iIf you’re just developing this app, go ahead and run it in dev mode:
npm run devPublishing apps you’re also developing
If instead of running the app in dev mode you want to develop it against a frontend-template-site fork, there’s more to consider:
Running yalc add is much like npm-installing a tarball: both package.json and package-lock.json are modified to point to a local directory. This is a good thing, as it’s what allows npm i to install the added package’s latest dependency requirements.
However, if you’re also publishing the app for downstream development, you don’t want to have a file: dependency in the app’s package.json, as this will break npm resolution (and deduplication) in consumers. Which is to say, after running npm i you’ll want to revert the package-*.json files to a pristine state. Luckily, you can do so while still benefitting from subsequent yalc publish --pushes by:
git checkout package-*.json
yalc link @openedx/frontend-baseThis way, running yalc update locally - or a yalc publish --push from frontend-base - will still update the app accordingly, including binary files. And, of course, you’re also free to publish the app itself at any time:
yalc publishSite repository
To develop the site (presumably a fork of frontend-template-site) we can also yalc add the libraries. But since we're not concerned about changes to package.json files (we won’t be publishing the site as a library!), we don't bother yalc-linking them afterwards. We also don’t need to --peer them, as they’re straight dependencies:
cd ../frontend-template-site
yalc add \
@openeds/frontend-base \
@openedx/frontend-app-authn \
@openedx/frontend-app-learner-dashboard #...
rm -fr package-lock.json node_modules
npm i
npm run devPropagating changes
Whenever you make a change to one of the yalc-published libraries, run yalc publish --push from their corresponding repositories. This will automagically update all repos that npm-added that library, so that if they’re running npm run dev, Webpack will pick up the changes without a manual reload.
Having to do that manually is not very productive, though. Here's a oneliner that does the publishing automatically when source files are changed in frontend-base. It overrides the exec line from the existing nodemon.pack.json configuration. Run this from a terminal window inside the frontend-base directory:
npm run pack:watch -- --exec yalc publish --pushAnd one for apps. It’s longer because apps don’t yet ship a pack:watch script:
npx nodemon --delay 1 --watch src -e js,ts,jsx,tsx,scss --exec yalc publish --pushTo paint a clear picture: if you’re developing frontend-base, two apps, and using a frontend site to view changes, you’re going to need four terminal windows. Three running nodemon watchers as described above, and the last one regular npm run dev:
frontend-base:
npm run pack:watch …frontend-app-authn:
npx nodemon …frontend-app-learner-dashboard:
npx nodemon …frontend-template-site:
npm run dev