Multi-app Monorepo? #462
-
Hello, I have use case that I think is common, but has been described from various angles and maybe not given a name. I'd like to propose Multi-app Monorepo to describe my use case, and maybe even be so bold as to suggest a solution in the form of a flag to pass to A Monorepo with Two AppsMy monorepo has two apps, "a" and "b". They're in an {
"name": "@my/monorepo",
"private": "true",
"workspaces": [
"apps/*",
"packages/*"
],
// etc. ... and the tree looks (roughly) like this: $ tree . --dirsfirst
.
├── apps
│ ├── a
│ │ ├── src
│ │ └── package.json
│ └── b
│ ├── src
│ └── package.json
├── packages
│ └── c
│ ├── src
│ └── package.json
├── package-lock.json
└── package.json Where Things Get DiceyFor any number of reasons apps "a" and "b" are deployed to two different locations. They could be built as separate Docker containers, or two AWS Lambdas, or anything else. Also for reasons package "c" is not (maybe cannot be) published to a registry, either private or public. In the interest of following best practices, and in the pursuit of an absolute minimum of build tooling, I'd like to deploy an unbundled Node app to my targets. My goal here is an app structure that looks something like this (whether there's a $ tree apps/a --dirsfirst
apps/a
├── dist
├── node_modules
└── package.json This structure might be The problem is really the fact that my package "c" is not published to a registry. So why not just publish to a private registry? I think even if package "c" were published, I'd still be in a weird situation when I want to create a pull request in my monorepo that affects one or both apps and package "c". In this case I'd need to be sure that as part of my CI/CD setup I publish a pre-release of package "c", then installed that into my app(s), and then deployed staging/integration versions of the app(s), and then if all that works and tests pass etc. publish a "real" release of package "c" (only to be consumed by my own apps "a" and "b") and then I guess re-release the final versions of my apps? Seems like a lot of extra work. Maybe there are other, simpler ways around this, but I think if installing from a local/sibling workspace could be supported "natively" by npm it'd make the workflow a lot clearer. I also have an inkling that there are other use cases that could take advantage of this functionality. A Flag to the Rescue?Okay, so what'd be really great (imo) is if I could prompt {
"name": "@my/monorepo",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@my/monorepo",
"workspaces": [
"apps/*",
"packages/*"
]
},
"apps/a": {
"name": "@my/a",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@my/c": "^1.0.0"
}
},
"apps/b": {
"name": "@my/b",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@my/c": "^1.0.0"
}
},
"node_modules/@my/a": {
"resolved": "apps/a",
"link": true
},
"node_modules/@my/b": {
"resolved": "apps/b",
"link": true
},
"node_modules/@my/c": {
"resolved": "packages/c",
"link": true
},
"packages/c": {
"name": "@my/c",
"version": "1.0.0",
"license": "ISC"
}
},
"dependencies": {
"@my/a": {
"version": "file:apps/a",
"requires": {
"@my/c": "^1.0.0"
}
},
"@my/b": {
"version": "file:apps/b",
"requires": {
"@my/c": "^1.0.0"
}
},
"@my/c": {
"version": "file:packages/c"
}
}
} What'd be different is that when npm finds a local match, instead of reaching out to a registry it'd "serve" the result of calling For example, if I were to call I guess there'd be some potentially exotic configurations of transitive local dependencies, but in that case I think a kind of ephemeral local npm registry'd be able to handle serving the results of I've offered A thought I just had while writing this is that maybe this functionality could piggyback on npm config's registry option. This'd mean no new config, and maybe add the option to specify it in a monorepo-root-level .npmrc file, but would also depend on something like In ConclusionI am sleepy. It's late where I am and I took a melatonin, so I'm going to finish this up tomorrow. I've tried a bunch of other ways of approaching this use case and will try to document several of them and call out their pitfalls. I hope this message finds you well, and that I haven't missed anything glaringly obvious (though if I have, thank goodness! I can't wait to hear about how my use case is already well solved). Thank you and good night. EditFixed a couple silly typos before shutting my eyes. |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 2 replies
-
If the shared package is not published and will always be there, why not a local dependency? {
"name": "a",
"dependencies": {
"c": "file:../packages/c"
}
} |
Beta Was this translation helpful? Give feedback.
-
Other Things I Have Tried: LernaLerna has a concept of Git Hosted Dependencies that sort of does what I'm proposing, but it requires additional setup that I kind of hate (even the Git docs on using Lerna's |
Beta Was this translation helpful? Give feedback.
-
Hey all, since this discussion looks a bit more like a scoped feature request I've transferred this discussion to the RFC repo. As a next step you might want to open an issue to gather feedback. |
Beta Was this translation helpful? Give feedback.
-
Created #463 |
Beta Was this translation helpful? Give feedback.
Created #463