A new JavaScript registry?

Tags:
  • javascript
  • registry
  • tooling
  • esm
  • cjs

Finding the right JavaScript tools can be tricky. JavaScript Registry (JSR) enters as a game-changer in the JavaScript ecosystem. This blog post will guide you through JSR's benefits and how it simplifies your development work.

Key Takeaways (TL;DR)

  • JSR is a modern package registry for JavaScript and TypeScript.
  • It works with many runtimes (Node.js, Deno, browsers, and Bun).
  • It is backwards compatible with npm.
  • It is ESM first, you only need to publish your package in ESM format.
  • It is financially and operationally backed by Deno
  • It is open source and partially community-driven.

What is JSR - The JavaScript Registry?

The JavaScript Registry (JSR) is a modern package registry for JavaScript and TypeScript. JSR works with many runtimes (Node.js, Deno, browsers, and more) and is backwards compatible with npm.

// What do you mean backwards compatible with npm?
// Source: https://jsr.io/docs/publishing-packages#importing-npm-packages

// We can import npm packages that **exist** within our package.json
import * as chalk from 'chalk';

// We can import npm packages that **do not exist** within our package.json like so
import * as express from 'npm:express@4';

I know what you're thinking: "Another package registry? Why do we need that?" and you're right to ask. After all, JSR is not here to replace NPM, but to provide a better alternative for people who want to use ESM modules in their projects.

The problems with NPM

The NPM registry was created in 2009 and has been the default package registry for JavaScript for over a decade. Back in that time, JavaScript was not as popular as it is today, and the ecosystem was not as big as it is today. CommonJS was the module system of choice, and the registry was designed to work with CommonJS modules. Then, ES modules (ESM) came along, and the registry became a place where people were mixing CommonJS and ESM modules.

Unfortunately, CommonJS modules do not support loading ES modules except (in Node.js) by using the import() function (which is a bit painful and not a great solution).

In order to support CommonJS in this case, your best bet is to transpile your package into a CommonJS module, and ship both CommonJS and ESM versions of your package.

Fast forward to today, ESM is the module system of choice for modern JavaScript development. People are using ESM in Node.js, Deno, and even in web browsers. NPM works fine with ESM, but you have to set up your package.json correctly, meaning you have to specify the type field in your package.json to be module and you have to publish your package in ESM format. You can also support both CommonJS and ESM as said previously by using the exports field in your package.json, but it's not as straightforward as it could be. To read more about conditional exports, check out the official documentation.

Getting help from a bundler

If you're using a bundler, you can use ESM for your project and let the bundler take care of the rest. Basically you can produce a CommonJS bundle and an ESM bundle and ship both of them in the same package.

The JSR solution

You can spend your time setting up your package.json correctly, or you can use JSR, which is ESM first and only requires you to publish your package in ESM format. By chosing this option, your package will be shipped in other runtimes as well like Deno. In the next chapters of this blog post, we will delve deeper into JSR and its benefits.

Why JSR?

The team has written an excellent document on why JSR that you should definitely check out.

Yeah... I totally skipped the part where I explained "why JSR" in my blog post. I'm sorry, but I'm not going to copy-paste the same content here. The JSR team has done a great job explaining why JSR is needed, and I think you should read it from the source.

Consuming JSR packages

Utilizing modules from JSR is simple and opens up a world of possibilities. You can use these modules in various environments like Deno, Node.js, and even in web browsers.

  1. First, decide which module you need. Search through JSR to find it. Unfortunately, not every NPM package is available on JSR yet, but the team is working hard to make it happen.
  2. Look at the module's documentation. It tells you how to use the module.
  3. Install the module for your project. If using npm, run a command like deno add @luca/cases for deno or npx jsr add @luca/cases for NPM (use any of npx, yarn dlx, pnpm dlx, or bunx).

After adding the package, you can import and use it in ESM like so:

import { camelCase } from '@luca/cases';
camelCase('hello world'); // "helloWorld"

Publishing packages to JSR

First, write your code starting from a file called index.ts. JSR packages are written in JavaScript or TypeScript, and are published as ES modules.

/**
 * A module providing a function to add n numbers together.
 * @module
 */

/**
 * Add numbers together.
 * @param {number[]} numbers - The numbers to add together.
 * @returns {number} The sum of the numbers.
 */
export function add(...numbers: number[]): number {
  return numbers.reduce((acc, curr) => acc + curr, 0);
}

Then, add a config file jsr.json (or deno.json if you're using Deno) to your package. This file contains package metadata like the name, version, and entrypoint(s). The exports field tells JSR which modules should be importable by users of your package.

{
  "name": "@yourname/add",
  "version": "1.0.0",
  "exports": "./index.ts"
}

Finally, run npx jsr publish, or deno publish to publish your package. You will be prompted to authenticate with JSR, and then your package will be published

My two personal favorite JSR features

  1. You have the ability to ship beautiful documentation with your package. You can write your documentation in Markdown and include it in your package. Take a look at this package documentation https://jsr.io/@daemon/[email protected]/doc/~/WFC isn't it beautiful?

  2. There is a scoring mechanism for packages. Take a look at this link https://jsr.io/@daemon/wfc-tiles/score, you can see that the package is being scored based on various factors like - Has a readme or module doc - Has examples in the readme or module doc - Has module docs in all entrypoints - Has docs for most symbols - No slow types are used what are slow types? - Has a description - At least one runtime is marked as compatible - At least two runtimes are marked as compatible - Has provenance

Disclaimer, this package was randomly chosen and I have no affiliation with the author.

Conclusion

I don't think the goal of this project is to replace NPM. I think the goal is to provide a better alternative for people who want to use ESM modules in their projects. It also helps you ship your modules to Deno easier and provides developers a place to host beautiful documentation for their packages. CommonJS is dying slowly, and ESM is the future. I will definitely be using JSR for my next open source project.

Thank you for reading this blog post. I hope you learned something new today. For questions or feedback, feel free to reach out to me via email at [email protected].

Further reading