PNPM workspace with git submodules
Introduction
We published quite a few open-source packages on NPM.
Developing multiple NPM packages that rely on each other is not easy task. There are a lot of ways that things can go wrong: keeping stuff in sync, publishing etc.
We tried a couple of other tools to solve this problem: git repo npm modules, npm link
and yalc
so far but no of them was as good as pnpm
.
Our go-to method now is a pnpm workspace monorepo with git submodules. Very convenient solution for projects with multiple separate git repositories.
Features
pnpm
makes it convenient to manage and develop multiple separate packages without using any other tools likenpm link
oryalc
- easy to publish and takes care of updating dependencies using
changeset
- recursively remove
node_modules
,dist
, or build your projects
How to use it
Follow this step-by-step guide on to create a pnpm
monorepo with git submodules. All you need is a terminal.
Setup pnpm
1# create a new directory and cd into it 2mkdir mono-repo 3cd mono-repo 4 5# creates a package.json file 6pnpm init 7 8# creates an empty git repository 9git init
- do your usual setup (like add a
.gitignore
file etc.)
Monorepo structure
in this example there will be 2 folders apps
and packages
apps
for acreate-react-app
, which will consume packagespackages
for several git submodules, each of them is a separate git repo, which are reusable packages- this structure can be defined in the
pnpm-workspace.yaml
1# pnpm-workspace.yaml 2packages: 3 # executable/launchable applications 4 - 'apps/*' 5 # all packages in subdirs of packages/ and components/ 6 - 'packages/*'
Git Submodules
add your submodules
1# add your submodules in the packages folder 2cd packages 3git submodule add https://github.com/<user>/rock rock 4 5# this will tell git to download the contents of the submodules, if the folders are empty 6git submodule update --init --recursive
- keep in mind that submodules are still separate GitHub repositories
- review changes, commit and push inside the submodules
- the root of the project is also a git repository which sees each submodule as a particular commit hash
- when a submodule has a new commit, the new commit hash can be staged and committed in the root project, so everyone else sees that the particular submodule now points to a new commit hash
Create react app
the following cra will live in the apps
folder and will be part of the root, not a separate git repository
1cd apps 2npx create-react-app example
- the cool part of pnpm workspace is that the
example
react app can use the submodules as dependencies - if the version numbers match, then the example app will use the built package from the
packages
folder, otherwise pnpm will fetch it from remote npm registry (if it is published), workspace protocol
pnpm import
pnpm import
generates a pnpm-lock.yaml
from another package manager's lockfile
1# cd into a submodule 2rm -rf node_modules 3pnpm import 4# now remove the other package managers lockfile 5 6# go back to the root and install dependencies 7pnpm install
Release workflow
Long story short, pnpm does not version packages so when the time comes to publish a submodule to npm, some other tool needs to be used for that
- luckily changset takes care of it
1# add changeset in the root as devDependencpnpm add -Dw @changesets/cli 2 3# run the init command 4pnpm changeset init 5 6# generate a new changeset 7# the following command will ask which packages should get a new version 8pnpm changeset 9 10# this will bump the versions previously specified with pnpm changeset 11pnpm changeset version 12 13# update lockfile and rebuild dependencies 14pnpm install
- changeset also takes care of the
example
React app, and if any of its dependencies has a new version, it will update thepackage.json
version of that package
Running workspaces
- workspaces can be run separately with the
--filter
command - or all of them at once with the
--recursive
command
1# build only one project 2pnpm --filter <package> run build 3 4# run all of them at once 5pnpm -r run build
Conclusion
- we use
pnpm
workspace in suggestcat-repo,suggestcat
is a set ofProseMirror
plugins, which gives AI suggestions - with
pnpm
workspace we can developsuggestcat
easily, because we have 4 different submodules which depend on each other, and our React app with the ProseMirror editor consumes all of those packages, without a monorepo we would have to publish to npm registry all the time we change something in any of the repos, or usenpm link
locally, which is quite cumbersome, or some other tools likeyalc
which seemed to be working just fine for the first time, but with 4 packages it needed to be restarted all the time