Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share module between multiple projects in a monorepo

Tags:

I have a small monorepo with a few projects (they share the same data stores, so it's easier to have them together in a monorepo for development and testing). Each project is in its own folder, with its own package.json. Each project is meant to be deployed on its own (independent of the other projects).

I would like to share some code between the projects. I want to maintain their relative independence, so I'd rather not have to create a "build" step in the root repo folder, as well as having each project's own build step. Ideally deployment of each project would continue to be done in the project's folder, without it needing to know about other projects.

I know I could create an npm module in the repo and npm link to it from each project. This is the solution I'm leaning toward. But I'm wondering if anyone has a better idea.

Here's an example of what the directory structure kinda looks like:

/package.json
/docker-compose.yml
/project-1/package.json
/project-2/package.json

If I went with the npm link solution, I would add something like a project-shared folder and link to it from project-1 and project-2.

like image 800
Cully Avatar asked Oct 02 '19 23:10

Cully


1 Answers

This is the npm link solution I'm using at the moment. It seems like an OK solution, so I thought I'd post it as an answer. I haven't yet implemented the deployment stuff for this project, so I don't know how well deployment will work with this. I'm hoping it will deploy the linked module along with everything else.

The project directory structure looks like:

/package.json
/docker-compose.yml
/project-1/package.json
/project-2/package.json
/project-shared/package.json

In each project's package.json (project-1 and project-2), I added this postinstall script:

"scripts": {
  "postinstall": "npm link ../project-shared"
},

So the link will be created during the normal setup of the project.

NOTE: For some reason this doesn't work using a preinstall script (the link won't be created, though it looks like it's run). postinstall works just fine.

I'm not quite sure how dependency installation works for the shared module (e.g. if the shared module's dependencies will be installed when the projects link to it, or if I'll have to install them independently).

One problem I encountered is that Docker Compose doesn't play well with linked packages (the symlinked folder won't point to the correct location inside the container). I fixed this by mounting the shared folder over the symlink in the node_modules folder. For example, for project-1:

volumes:
  - "./project-1/:/home/node/app:ro"
  - "./project-shared/:/home/node/app/node_modules/project-shared:ro"

EDIT: Sept 4, 2020

Wanted to drop a note that I've been using this in production for a while and it works great. One issue I've noticed in dev, with the shared library mounted in the Docker container, is when you npm install from your host computer it will run postinstall and symlink your shared library folder. This is expected, except in Docker it messes up your mount. The solution I've found is to stop Docker, remove the link, re-create the folder, and start up Docker again. A better solution might be replacing your postinstall script with something like this:

"postinstall": "test -d node_modules/project-shared || npm link ../project-shared"

This will only link the folder if it doesn't already exist. I've only tested this a little bit, so I'm not sure if I'm missing any weird edge cases.

like image 50
Cully Avatar answered Dec 09 '22 16:12

Cully