Skip to content

elbywan/zap

Repository files navigation

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 (~npm), isolated (~pnpm) or plug'n'play (~yarn) install strategies
# 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:

  • npm is the de facto standard for JavaScript package management. It is reliable and has a huge community. But it is also super slow and lack features introduced by other package managers over time even though it is trying to catch up.

  • yarn is a great alternative to npm, it was a pioneer initially in terms of speed and it introduced many improvements and innovations along the years. Yarn is also impressively reliable which is paramount. I never used yarn berry in a significant project but the PnP approach is very interesting - unfortunately the downside is that does not seem to be compatible out of the box with a lot of packages from the ecosystem.

  • pnpm is an impressive package manager which introduced the concept of isolated installs. It handles workspaces very well with a lot of options to customize the behavior. Speed is mostly fine even with big monorepos. I experienced some reliability issues using it over the years though (peer dependencies handling, lockfile inconsistencies, very high memory consumption, need to manually delete the node modules folder…).

  • bun was a great source of inspiration for this project, but it comes with tradeoffs. While tremendously fast, it did not support some critical features when I started working on zap (and it still is very feature-limited), cannot be considered reliable as of today and is not as flexible as I would like it to be.

  • newer contenders (orogene, cotton, ultra…) are kind of interesting but they are clearly lacking in terms of features and/or reliability and/or speed.

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

About

Another [insert blazing fast synonyms] JavaScript package manager

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages