PNPM workspace with git submodules
By matejcsok on Thursday, August 3, 2023

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 like npm link or yalc
  • 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 a create-react-app, which will consume packages
  • packages 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

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 the package.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 of ProseMirror plugins, which gives AI suggestions
  • with pnpm workspace we can develop suggestcat 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 use npm link locally, which is quite cumbersome, or some other tools like yalc which seemed to be working just fine for the first time, but with 4 packages it needed to be restarted all the time
Did you like this article? Would you like to learn more?
Write to us at contact@emergence-engineering.com