Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing a typescript library in a monorepo

I'm trying to setup a monorepo with 3 services sharing some library code.

This is the current situation:

repo: web
pdf/
  package.json
    reference to shared-ts using github url
  tsconfig.json
frontend/
  package.json
    reference to shared-ts using github url
  tsconfig.json
repo: mobile (react-native)
  package.json
    reference to shared-ts using github url
  tsconfig.json
repo: shared-ts
  package.json
  tsconfig.json

This works but it's a pain to commit to shared-ts, build, change the hash in package.json and commit again.

This is what I'd like to achieve:

repo: monorepo
pdf/
  package.json
    reference to ../shared-ts
  tsconfig.json
frontend/
  package.json
    reference to ../shared-ts
  tsconfig.json
mobile/
  package.json
    reference to ../shared-ts
  tsconfig.json
shared-ts/
  package.json
  tsconfig.json

So far I've tried:

  • TypeScript project references, but it seems like there is no way to have dependencies in the shared-ts project
  • "shared-ts": "../shared-ts" in package.json but it copies shared-ts into the node_modules of each package so I have to re-run yarn everytime I make a change
  • yarn link in postinstall: error TS2307: Cannot find module 'shared-ts' or its corresponding type declarations.
  • creating a symlink directly in postinstall with ln -s ../shared-ts/ node_modules/shared-ts/ but it seems TypeScript fails to find the module
  • npm link in postinstall seems like the most promising but it's really slow and I'm having trouble running it in CI because of some permissions issues.

Is there a good way of doing this? Any ideas on other things I could try?

like image 634
Corentin S. Avatar asked Nov 17 '21 09:11

Corentin S.


2 Answers

Solution 1:

with Lerna

you can use workspace and Lerna

yarn workspace & lerna

├── README.md
├── lerna.json
├── package.json
├── packages
│   ├── pdf
│   │   ├── package.json   /*  "shared-ts": "^1.0.0" */
│   │   └──  src
│   ├── frontend
│   │   ├── package.json
│   │   └── src
│   ├── mobile
│   │   ├── package.json
│   │   └── src
│   ├── shared-ts
│   │   ├── package.json
│   │   └──  src
├── tsconfig.json
└── yarn.lock

here is an example repo

here you can see x-cli is getting shared x-core

Solution 2:

without Lerna

you can use mtsl package which enables us to make tangible symlinks. you can install this package globally

npm install -g mtsl

then you just need to start to separate these three commands in terminal.

mtsl startwithoutadd -s path_of_project/packages/shared-ts -d path_of_project/packages/pdf/node_modules/shared-ts

mtsl startwithoutadd -s path_of_project/packages/shared-ts -d path_of_project/packages/frontend/node_modules/shared-ts

mtsl startwithoutadd -s path_of_project/packages/shared-ts -d path_of_project/packages/mobile/node_modules/shared-ts

Note don't stop this three watcher. after testing, you can make single command from the package.json script

like image 116
Muhammad Numan Avatar answered Oct 17 '22 15:10

Muhammad Numan


Your use-case can be handled using the npm7 workspaces. In short your new monorepo structure should look like below:

repo: monorepo
package.json // <- here you define the workspaces
pdf/
  package.json
    reference to shared-ts
  tsconfig.json
frontend/
  package.json
    reference to shared-ts
  tsconfig.json
mobile/
  package.json
    reference to shared-ts
  tsconfig.json
shared-ts/
  package.json
  tsconfig.json

You need to list the workspaces in the root package.json which might look something like below:

{
  "name": "awesome-monorepo",
  "workspaces": [
    "pdf",
    "frontend",
    "mobile",
    "shared-ts"
  ]
}

After doing that, wherever in the monorepo you decide to use the shared-ts you can add that to dependencies or devDependencies simply referring by the version number instead of relative path.

All the node modules inclusive the workspaces gets hoisted to the root node_modules which is why the module resolution should work without friction.

like image 2
Sayan Pal Avatar answered Oct 17 '22 16:10

Sayan Pal