- SajanTech's
- Posts
- Publishing a JSR Package with Deno
Publishing a JSR Package with Deno
How to Build and Share a Standardized API in TypeScript Using Deno's Simple and Secure Toolkit
Introduction
In today's post, we will explore what JSR is, why it matters, and the benefits of using it, along with a step-by-step guide on how to publish your first TypeScript module to the JSR registry.
Prerequisite
I assume you have Deno installed on your local development machine. If you haven't installed it yet, please refer to the Getting Started with Deno guide for instructions.
What is JSR?
The JavaScript Registry (JSR) is an innovative package registry designed specifically for JavaScript and TypeScript developers. It provides a centralized location for managing and sharing packages, making it easier for developers to access the tools and libraries they need for their projects.
One of the key advantages of JSR is its compatibility with multiple runtimes, including Node.js, Deno, and various web browsers. This means you can use packages from JSR in a wide range of environments without worrying about compatibility issues. Additionally, JSR maintains backward compatibility with npm, the widely used package manager for JavaScript, ensuring a smooth transition for developers familiar with npm.
In essence, JSR streamlines the process of package management, allowing developers to focus on building robust applications while leveraging the extensive ecosystem of JavaScript and TypeScript libraries.
Why JSR?
The success of Node.js is largely due to npm, which has over 2 million packages, making it one of the most successful package managers in history. The JavaScript community should be proud of this achievement.
So, why create JSR when we already have npm? The landscape has changed since npm was introduced:
New Module Standards: ECMAScript modules (ESM) are now the standard for JavaScript. The web has adopted ESM as the preferred format, replacing CommonJS.
More JavaScript Environments: There are now many JavaScript runtimes beyond Node.js, including Deno and Bun. A package registry focused only on Node.js is no longer suitable for the entire JavaScript ecosystem.
TypeScript's Popularity: TypeScript has become a standard choice for many JavaScript projects. A modern registry should support TypeScript effectively.
Improved Developer Experience: JSR aims to enhance the user experience, performance, reliability, and security compared to npm.
Good reasons to consider using JSR
Native TypeScript Support: JSR was built with TypeScript in mind. You can publish TypeScript files directly, and they will work seamlessly in platforms like Deno. For Node.js, JSR will convert your TypeScript code to JavaScript and provide TypeScript definitions, so you don’t need extra setup.
Focus on ECMAScript Modules: JSR only supports ESM, aligning with the modern standard for JavaScript modules.
Cross-Runtime Compatibility: JSR works with various JavaScript environments, including Deno, Node.js, Bun, and more. This makes it easy for different projects to use JSR packages.
Built on npm's Success: JSR is designed to work with npm packages. You can use JSR alongside npm projects, allowing seamless integration.
Excellent Developer Experience: JSR offers features that make it easier for developers to publish modules, such as:
Simple one-command publishing
Automatic documentation generation from code
OIDC-based authentication for publishing packages from GitHub Actions
Automatic inclusion of TypeScript definition files
Guidance on TypeScript best practices
Fast, Secure, and Reliable: JSR prioritizes security and speed:
Uses a global CDN for fast package delivery.
Ensures packages do not change after being uploaded.
Downloads only the files you need.
Provides secure authentication for package publishing.
Read More https://jsr.io/docs/why
Configure our first package
Firstly, you must signup using your GitHub account on the JSR website. After you signed up. You must create a scope. You can create a new scope at JSR New Scope
What is Scope in JSR?
On JSR, all packages are organized into groups called scopes. A scope is managed by one user but can include multiple members. Scopes work like npm organizations and are indicated by an @ symbol.
Scope names must be 2 to 20 characters long, using only lowercase letters, numbers, and hyphens (and cannot start with a hyphen). Each scope name must be unique no two scopes can share the same name.
Lets code!
Open your terminal and run the deno init
command with the --lib
flag to initialize new library project.
deno init --lib
By default, this command will generate three files. The two most important files for our package are deno.json
and mod.ts
.
In the deno.json
file you will see some information about your library.
{
"name": "@<use-your-scope-name-here>/dnt-format",
"version": "0.1.0",
"exports": "./mod.ts",
"tasks": {
"dev": "deno test --watch mod.ts"
},
"license": "MIT",
"imports": {
"@std/assert": "jsr:@std/assert@1"
}
}
In the JSON above, the key field is exports
, which specifies which module can be imported by users of your package.
Read more about package configuration: https://jsr.io/docs/package-configuration
Now, let's create a simple function for formatting dates and times in the mod.ts
file.
type Region = 'US' | 'GB';
export function formatDateTime(date: Date, region: Region): string {
const options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: region === 'US', // Use 12-hour format for US, 24-hour for Europe
};
// Use Intl.DateTimeFormat to format the date based on the region
const formatter = new Intl.DateTimeFormat(region === 'US' ? 'en-US' : 'en-GB', options);
return formatter.format(date);
}
Add tests:
import { assertEquals } from "@std/assert";
import { formatDateTime } from "./mod.ts";
const mockDate = "2024-11-02T10:18:11.367Z";
Deno.test(function formatDateTimeRegionUS() {
assertEquals(formatDateTime(new Date(mockDate), 'US'), '11/02/2024, 11:18:11 AM');
});
Deno.test(function formatDateTimeRegionGB() {
assertEquals(formatDateTime(new Date(mockDate), 'GB'), '02/11/2024, 11:18:11');
});
Next, update the tasks section in the deno.json
file with the following entries:
"tasks": {
"dev": "deno test --watch mod_test.ts"
},
Now, execute the command deno task dev
You should see the following output:
All tests passed.
We now have a solid working codebase, so it’s time to publish.
Publish to JSR
You can publish most JavaScript and TypeScript code using ESM modules as a JSR package on jsr.io. These packages can be imported in Deno, Node.js, and other tools.
JSR supports publishing both package.json and Deno code. It encourages publishing TypeScript source code instead of separate .js and .d.ts files, enabling better auto-generated documentation and improved auto-completion in editors.
There are some rules which is good to know
ESM Modules Only: Packages must use ESM (import/export syntax). CommonJS modules are not allowed.
npm Packages Supported: You can include npm packages in your package.json
dependencies or reference them directly in your code (e.g., import { cloneDeep } from "npm:lodash@4";
).
JSR Packages Supported: JSR packages can also be included in your package.json
or referenced in code (e.g., import { encodeBase64 } from "jsr:@std/encoding@1/base64";
).
Node Built-ins Supported: Use the node:
prefix to import Node.js built-in modules (e.g., import { readFile } from "node:fs";
). If you have a package.json
, bare specifiers can also be used.
Simple File Names: Filenames must be compatible with both Windows and Unix. Avoid special characters like *
, :
, or ?
, and do not use the same name with different casing.
Avoid TypeScript "Slow Types": To enhance performance and compatibility, avoid certain TypeScript types in exported functions, classes, or variables. This is enforced by default but can be opted out of.
Valid Cross-File Imports: All relative imports between your modules must resolve correctly at publish time. Supported specifiers depend on the presence of a package.json
.
Read more: https://jsr.io/docs/publishing-packages
Publish the package
To publish, simply run the command deno publish
. If you prefer using npx
, you can do so as well, for example: npx jsr publish
. Other package managers are also supported.
# yarn
yarn dlx jsr publish
# pnpm
pnpm dlx jsr publish
The next step is to create a package on jsr.io if you haven't done so already. You should see a prompt to guide you through the creation process, which will look like this:
After you click the 'Create' button, the package will be generated, and you will be prompted to approve it.
Once you approve it, your package will be published. You can view it on the jsr.io website.
In this post, I have published the same code on JSR under the scope name @sajanvtech
. You can view it here: @sajanvtech/dnt-format.
Conclusion
In this post, we explored the JavaScript Registry (JSR) and its significance for JavaScript and TypeScript developers. We highlighted the benefits of using JSR, including its support for ECMAScript modules, native TypeScript integration, and cross-runtime compatibility. By guiding you through the process of publishing your first TypeScript module, we demonstrated how easy it is to leverage JSR for package management.
We began by creating a scope on JSR and initializing a new library project using Deno. After setting up the necessary files and writing a function to format dates and times, we added tests to ensure our code was functioning correctly. Finally, we updated our project configuration and successfully published our package.
JSR not only simplifies the publishing process but also enhances the developer experience with features like automatic documentation generation and secure package management. As you continue to develop your projects, consider using JSR to take advantage of its modern approach to package management in the JavaScript ecosystem.
For further information, check out the JSR documentation to explore more about its features and capabilities.
Stay Updated!
If you enjoyed this blog and want to keep up with the latest tips, tutorials, and updates in JavaScript and TypeScript, sign up for our newsletter!
Join my community and be the first to know about new posts, resources, and exclusive content.
Thank you for reading, and I look forward to sharing more with you!
Reply