How to use Capacitor inside of an Nx monorepo
If you’re adding Capacitor to your Nx monorepo, there’s a nice tool called
Nx Extensions that lets you add Capacitor and then
it generates new nx run
commands for you.
It works fine in general, but due to how Capacitor looks for plugins, it made you install your
capacitor plugins in the application level package.json
file (as shown in the image below),
which defeats one of the purposes of the monorepo, to have and maintain only 1 node_modules folder
for all my apps and libraries.
For my personal project it was an inconvenience, because if I wanted to install packages I needed to jump between the 2 folders depending on what I needed to install.
For my work monorepo, it was more of a pain, imagine 200+ developers working on a monorepo, and every time a package changed in our app (for our 5 developer team) we had a lot of messages in the general chat asking why linter was failing for our app.
And we had to go and tell them, “oh, just cd into the app folder and run npm ci
” 😅.
We started looking for a solution to this, and found something that works, we still have the 2
package.json files, but now we maintain only one node_modules/
folder, and I’m happy to say, that
since I implemented that change, there hasn’t been a single incident where devs from other teams
have failed linters or processes because of us 🙌🏽.
The implementation was actually simpler than I expected, first, I removed all the version numbers
from my application’s package.json, so in this example, my app is called Smart Checklists, so in my
monorepo it’s path is apps/smart-checklists
.
So in my apps/smart-checklists/package.json
I replaced all the version numbers for *
.
{
"name": "smart-checklists",
"dependencies": {
"@capacitor/filesystem": "*",
"@capacitor/camera": "*"
},
"devDependencies": {
"@capacitor/cli": "*"
}
}
Then, I removed both the apps/smart-checklists/package-lock.json
file and the
apps/smart-checklists/node_modules
folder.
Then, I installed my 2 plugins in the root package.json
file, you do this by opening the terminal
in the root of the project and running npm install
for the plugins, so in my case it was:
npm install @capacitor/filesystem @capacitor/camera
For my app it worked out of the box, I was able to generate both Android and iOS platforms and versions without issues, for my work application I had to do an extra step.
I needed to go into my Podfile: apps/smart-checklists/ios/App/Podfile
And change the first line from:
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
to
require_relative '../../../../node_modules/@capacitor/ios/scripts/pods_helpers'
This is because it was generated with an older version of capacitor, so it wasn’t updated, and it
was trying to find the helpers inside the app level node_modules
which no longer existed.
And that was it, a lot of research, a bit of work, and a happy ending 🙌🏽