Skip to content

pnpm

pnpm is a drop-in replacement for npm that is faster and has more features.

  • To migrate code from npm, just delete node_modules and package-lock.json, then do pnpm install (reference).
  • pnpm patch can patch dependencies, e.g. to address a bug in a library without having to wait for them to publish a fix.
  • pnpm add and pnpm install are very similar. In general, when adding a dependency, use pnpm add since it will only handle installs related to the new dependency.

If one of your dependencies has a small issue that you’d like to fix immediately without going through the PR process, then you can just patch that dependency.

Rather than use the official pnpm patch directly (reference), you can use pnpm-patch-i, which is a “better and interactive pnpm patch”. Here are the instructions that I used:

  • npx pnpm-patch-i kysely-migration-cli
    • It’ll ask to install pnpm-patch-i
  • If it fails to open the editor, then you can just manually open the path that it spits out, e.g. node_modules/.patch-edits/patch_edit_your-dep-name_5ccfb173d2
    • In the editor that opens. you’ll have the entire module that you’re patching available to you, so just make any changes to it.
      • After making changes, make sure to press enter and not escape even though the error is what printed last. It should commit your changes.

Getting started:

  • See this repo as an example of how to use workspaces.
  • You need to make packages/YOUR_FIRST_PACKAGE and split your package.json file.
    • Your root-level package.json should contain only tooling related to the whole project, e.g. eslint, prettier, husky, etc.
    • Your package-specific package.json should contain any specific configuration. For example, that’s where your test library should exist, any overrides for linting or tsconfig.json, etc.
  • If linting fails after you’ve set up your packages, try deleting the linting cache in all directories (e.g. .eslintcache)
  • Running tests from the root is not advised unless you’re running them from CI; just run them in the individual packages.
  • You can run a pnpm script on a specific set of workspaces with filtering (reference), e.g. pnpm --filter "abbott-bots" run build
  • Doing pnpm i in the root level will install node_modules for all packages.
  • Once you have multiple packages, you need to set up references between them. See this resource.
    • Note: even packages that don’t depend on other packages yet should get composite set to true. See the documentation for composite. This lets tsc --build skip it if you didn’t change it

Suppose you have a web package that you’re making and it depends on a database package in the same monorepo. By default, pnpm build on the Astro project will not run tsc, so it won’t rebuild the database package. This can be confusing since you may expect changes in the database package to automatically get picked up. It’s easy to fix:

  • Install typescript: pnpm add -D typescript
  • Add tsc --build --force && to the beginning of your build command in web’s package.json
  • Probably make sure that your web package’s tsconfig doesn’t have an include property.

Adding a new package to a monorepo

Section titled Adding a new package to a monorepo

For reference projects that uses a monorepo, take a look at:

Instructions on how to add a new package:

  • Make sure you have a package.json in the new package. You can initialize one with pnpm init. You will probably need build and watch scripts and an exports section, so consider copying contents from an existing package.json to get those fields.
  • Make sure you have a tsconfig.json in the new package. You can typically just copy one from another part of your project.
    • Modify paths and references as mentioned in this blog post so that you’re referring to any dependencies.
  • If you use eslint, copy over .eslintrc.cjs so that linting will work properly.
  • In the new package, you should probably have an index.ts which can be a “barrel”. It should be in your src directory and your tsconfig.json should have a rootDir which contains index.ts.
  • Suppose package-a depends on package-b.
    • You would need to add this to package-a’s package.json’s dependencies:
      • "package-b": "workspace:*"
    • You need to modify package-a’s tsconfig.json to add compilerOptions.paths and references.
  • Run pnpm i to set up the symlinks between packages.
  • If you run into issues where you can’t import a package defined in the workspace, then try restarting VSCode (or just the extension host).

If you get an error like this:

ERR_PNPM_REGISTRIES_MISMATCH  This modules directory was created using the following registries configuration: {"@fortawesome":"https://npm.fontawesome.com/","default":"https://registry.npmjs.org/"}. The current configuration is {"default":"https://registry.npmjs.org/"}. To recreate the modules directory using the new settings, run "pnpm install".

…then just run pnpm i and have it recreate the entire node_modules directory. If the command causing the original error was pnpm add, then make sure to run it again!