- 
                Notifications
    You must be signed in to change notification settings 
- Fork 3.8k
Description
What / Why
Currently it's possible to install packages from a folder, which is quite nice for quickly prototyping of monorepos, but becomes problematic with linking dependencies and binaries when things progressively grow and build processes are required in between.
The request to have a protocol file+pack would be pretty much the same, except it triggers npm pack on the directory prior to linking it to the parent.
This would allow hooking in with a prepack script to build/bundle the package before creating tar file.
As an example, we could have a repository like:
- app
- client
- shared
--- config (@app/config)
--- core (@app/core)
--- http (@app/http)
- tools
--- eslint (@app-tools/eslint)
--- tsconfig (@app-tools/tsconfig)
With a dependency graph similar to this:
- app
--- @app/config
--- @app/core
--- @app/http
----- @app/core (deduped)
--- @app-tools/eslint (dev)
--- @app-tools/tsconfig (dev)
- client
--- @app/config
--- @app/core
--- @app-tools/eslint (dev)
--- @app-tools/tsconfig (dev)
- @app/http
--- @app/core
--- @app-tools/eslint (dev)
--- @app-tools/tsconfig (dev)
- @app/core
--- @app-tools/eslint (dev)
--- @app-tools/tsconfig (dev)
Being able to pack @app/core before it being installed in app, client or @app/http would compile sources to generate dist folder while also allowing the tgz package to be installed in app, client or @app/http with just runtime dependencies as usual in npm install flow.
This may trigger multiple builds on packages which are repeated/shared between other dependencies. This could be solved by creating a dependency graph, keeping track of which packages were already built and building from leafs up.
It also means every single package is installable in isolation by default! No need for lerna bootstrap nor installing and hoisting all packages dependencies when just a few are required, which potentially improves CI times and splitting of builds.
How
Not sure how the exact implementation for this would be, but given the following packages:
{
  "name": "package-a",
  "version": "1.0.0",
  "dependencies": {
    "package-b": "file+pack:../package-b"
  }
}
{
  "name": "package-b",
  "version": "1.0.0",
  "main": "./index.js",
  "scripts": {
    "prepack": "tsc"
  },
  "devDependencies": {
    "typescript": "^3"
  }
}
When resolving file+pack the following will happen:
package-b has prepack script?
    npm install on package-b directory (dependencies + devDependencies)
npm pack
install generated package-b-1.0.0.tgz on package-a
- Sample implementation (wrapping npm): https://github.com/RecuencoJones/npm-filepack
- Sample repository: https://github.com/RecuencoJones/filepack-example
Related issues
Possible caveats
- Packages using file+packare usually intended for local usage / fixed versioning as part of monorepos and usually not meant to be published nor shared around
- How to keep integrity with package-locks? Maybe packages using this protocol should use a different strategy.