Logo created by Freepik - Flaticon

Another [insert blazing fast synonyms] JavaScript package manager

Build Status GitHub tag (latest SemVer) GitHub

demo

Zap is a JavaScript package manager (think npm/pnpm/yarn) that aims to be quick, reliable, memory efficient and developer friendly.


Disclaimer

Zap is a hobby project that I am currently working on in my free time. Documentation is sparse, Windows support is partial at best and the code is not yet ready for production.

I am not looking for contributors at the moment, but feel free to open an issue if you have any question or suggestion.

[!WARNING] Use it at your own risk.

Installation

npm i -g @zap.org/zap
zap --help

Commands

| Command | Aliases | Description | Status | | ------------- | --------------------- | ------------------------------------------------------ | ------- | | zap install | i add | Install dependencies | ✅ | | zap remove | rm uninstall un | Remove dependencies | ✅ | | zap init | create | Create a new project or initialize a package.json file | ✅ | | zap dlx | x | Execute a command in a temporary environment | ✅ | | zap store | s | Manage the store | ✅ | | zap run | r | Run a script defined in package.json | ✅ | | zap rebuild | rb | Rebuild installed native node addons | ✅ | | zap exec | e | Execute a shell command in the scope of the project | ✅ | | zap update | up upgrade | Update the lockfile with the newest package versions | ⏳ WIP | | zap why | y | Show information about why a package is installed | ✅ |

Check the project board for the current status of the project.

Features

Here is a non exhaustive list of features that are currently implemented:

# Classic install by default
zap i # or zap i --classic
# Isolated install
zap i --isolated
# Plug'n'play (experimental - no zero-installs yet)
zap i --pnp

or:

"zap": {
  "strategy": "isolated",
  "hoist_patterns": [
    "react*"
  ],
  "public_hoist_patterns": [
    "*eslint*", "*prettier*"
  ]
}
// package.json
"workspaces": [
  "core/*",
  "packages/*"
]
// package.json

or to prevent hoisting:

"workspaces": {
  "packages": [
    "packages/**"
  ],
  "nohoist": [
    "react",
    "react-dom",
    "*babel*"
  ]
}
// package.json
# Install all workspaces
zap i
# Using pnpm-flavored filters (see: https://pnpm.io/filtering)
zap i -F "./libs/**" -F ...@my/package...[origin/develop]
zap i -w add pkg

## Scripts can be scoped too

# Run a single script in the current workspace.
zap run my-script
# Run scripts in all workspaces in parallel.
# Will use topological ordering by default - dependencies will run first…
zap -r run test
# …or omit the "run" argument.
zap -r test
# Scope to the dependencies of a specific workspace, and pack the output.
zap -F "my_app^..." --deferred-output run build
# Disregard the topological ordering and run the scripts in parallel.
zap run --parallel -r build
; .npmrc file

; default registry:
registry=https://registry.yarnpkg.com/
; scoped registries:
@myorg:registry=https://somewhere-else.com/myorg
@another:registry=https://somewhere-else.com/another
; scoped authentication: (supported fields -> _auth, _authToken, certfile, keyfile)
//registry.org/:_auth=BASICAUTHTOKEN
//registry.npmjs.org/:_authToken=BEARERTOKEN
; disable strict ssl peers checking: (default is true)
strict_ssl=false
; use a custom certificate authority file:
cafile=/certs/rootCA.crt
"overrides": {
  "foo": {
    ".": "1.0.0",
    "bar": "1.0.0"
  }
},
"zap": {
  "package_extensions": {
    "react-redux@1": {
      "peerDependencies": {
        "react-dom": "*"
      }
    }
  }
}
// package.json
zap i my-react@npm:react
zap i jquery2@npm:jquery@2
zap i jquery3@npm:jquery@3

Benchmarks

a.k.a is it fast?

Methodology

Benchmarks consist on installing a fresh create-react-app in various scenarii, with postinstall scripts disabled.

See: https://github.com/elbywan/zap/tree/main/bench

They are performed on my own personal laptop (macbook pro 16" 2019, 2,3 GHz Intel Core i9, 16 Go 2667 MHz DDR4) with 5G wifi and 1 Gb/s fiber.

The benchmarking tool is hyperfine and to make sure that the results are consistent I re-ran unfavorable results (high error delta).

I am aware that this is not a very scientific approach, but it should give rough good idea about what zap is capable of.

Results

cold only-cache without-lockfile without-node-modules

Why?

This is a legitimate question. There are already a lot of package managers out there, and they all have their own pros and cons. So why another one?

First, I thought that it would be a good and fun challenge to build a package manager from scratch. I also really like the Crystal language and I have been using it for a couple of years now. So it would be a good opportunity to put my knowledge to the test.

I also experimented with a lot of package managers over the years, and I have a few praise and gripes with the existing ones:

So I decided to build a package manager that would be fast, flexible and easy to use. For my own personal use, but also for the community (in the long run).

How?

Zap is written in Crystal which is a compiled language, which means that it should be faster than JavaScript. It can easily tap into system calls and use the fastest ones depending on the platform (for instance clonefile). It is also an excellent fit when dealing with concurrent tasks.

Crystal also has experimental support for parallelism and can dispatch fibers to a pool of worker threads, which means that zap can take advantage of multiple cores. This is especially useful when dealing with CPU-bound tasks.

On top of that, zap will also try to cache package manifests in order to avoid unnecessary network calls in a performant way using messagepack.

Development

Prerequisites

Setup

git clone https://github.com/elbywan/zap
shards install
# Run the specs
crystal spec
# Build locally (-Dpreview_mt might not work on some os/arch)
shards build --progress -Dpreview_mt --release

Contributing

  1. Fork it (https://github.com/elbywan/zap/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

Related