Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/elbywan/zap

Another [insert blazing fast synonyms] JavaScript package manager
https://github.com/elbywan/zap

crystal javascript npm package-manager pnpm yarn

Last synced: 7 days ago
JSON representation

Another [insert blazing fast synonyms] JavaScript package manager

Awesome Lists containing this project

README

        



Logo created by Freepik - Flaticon

Another [insert blazing fast synonyms] JavaScript package manager


Build Status
GitHub tag (latest SemVer)
GitHub

---

![demo](assets/demo.gif)

**`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

```bash
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](https://github.com/users/elbywan/projects/1/views/1) 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**

```bash
# 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:_

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

- **[Workspaces](https://docs.npmjs.com/cli/v9/using-npm/workspaces?v=true#defining-workspaces)**

```json
"workspaces": [
"core/*",
"packages/*"
]
// package.json
```

_or to prevent hoisting:_

```json
"workspaces": {
"packages": [
"packages/**"
],
"nohoist": [
"react",
"react-dom",
"*babel*"
]
}
// package.json
```

```bash
# 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
```

- **[Private registries](https://docs.npmjs.com/cli/v10/configuring-npm/npmrc#auth-related-configuration)**

```ini
; .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](https://docs.npmjs.com/cli/v9/configuring-npm/package-json?v=true#overrides) / [Package Extensions](https://pnpm.io/package_json#pnpmpackageextensions)**

```json
"overrides": {
"foo": {
".": "1.0.0",
"bar": "1.0.0"
}
},
"zap": {
"package_extensions": {
"react-redux@1": {
"peerDependencies": {
"react-dom": "*"
}
}
}
}
// package.json
```

- **[Aliases](https://github.com/npm/rfcs/blob/main/implemented/0001-package-aliases.md)**

```bash
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**](https://create-react-app.dev/) in various scenarii, with postinstall scripts disabled.

**See:** [https://github.com/elbywan/zap/tree/main/bench](/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**](https://github.com/sharkdp/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](bench/cold.png)
![only-cache](bench/only-cache.png)
![without-lockfile](bench/without-lockfile.png)
![without-node-modules](bench/without-node-modules.png)

## 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](https://crystal-lang.org/) 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](https://www.npmjs.com/) 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](https://yarnpkg.com/) 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](https://pnpm.io/) 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](https://bun.sh/) 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](https://github.com/orogene/orogene), [cotton](https://github.com/danielhuang/cotton), [ultra](https://github.com/nachoaldamav/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](https://crystal-lang.org/) 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](https://www.manpagez.com/man/2/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](https://msgpack.org/).

## Development

### Prerequisites

- [Install crystal](https://crystal-lang.org/install/)
- _(optional)_ Install the [vscode extension](https://marketplace.visualstudio.com/items?itemName=crystal-lang-tools.crystal-lang) and [crystalline](https://github.com/elbywan/crystalline)

### Setup

```bash
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 ()
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

- [Julien Elbaz](https://github.com/your-github-user) - creator and maintainer

## Related

- [pnpm](https://pnpm.io/)
- [bun](https://bun.sh/)
- [npm](https://www.npmjs.com/)
- [yarn](https://yarnpkg.com/)