Skip to content

[FEATURE] new install protocol file+pack #1333

@RecuencoJones

Description

@RecuencoJones

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

Related issues

#529 (comment)

#702

#459 (comment)

Possible caveats

  • Packages using file+pack are 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions