Deno alternatives to popular Node projects – LogRocket Blog

I am a Software Developer with over three years of experience working with JavaScript and its frameworks. I currently work as a remote software developer for a tech agency.

Deno is a simple modern secure runtime for writing applications using JavaScript and TypeScript that uses the V8 engine built in Rust.

This is not an article that explains what Deno is. However, I can help if you need to know more about Deno. Check out this article: What’s Deno, and how it is different from Node.js?

And you can also check out the Deno repository if you are interested in future developments.

Now, Node has grown powerful and popular in the past few years. There are also a few popular Node projects that have cropped up, which are called dependencies. Since the birth of Deno, there have been a lot of doubts about how to do the same things we do in Node in Deno.

I will go over a few of the most popular ones in Node and show you its alternatives in Deno.

Next.js/Aleph.js

Aleph.js is a React Framework in Deno. Yeah, that’s it. Just as Next.js is in Node. Next.js for Node provides all the features you need for production using React. It lets you build server-side rendering, automatic code-splitting, static exporting options, easy production builds, and also static web applications.

Unlike Next.js, Aleph.js doesn’t use or need a bundler since it uses the ESM(ECMAScript Module) import syntax. Each module imported is just compiled once and cached:

import React from "https://esm.sh/[email protected]"
import Logo from "../components/logo.tsx"

export default function Home() {
    return (
      <div>
        <Logo />
        <h1>Hello World!</h1>
      </div>
    )
}

Other advanced features Aleph.js provides are Asynchronous Import, Custom 404 Page, Custom Loading Page, useDeno Hook, and more.

Express.js/Opine

Express.js is very popular for its open, free, or liberal minimalist web framework for Node. Its philosophy is to deliver a small, fast tooling for HTTP servers, making it an awesome option for SPAs, websites, hybrid, or public HTTP APIs. You can just craft your own framework using Express.js anyway. Another great thing is its robust routing system, which efficiently responds to clients requests, and few selection of HTTP helpers.

Unlike Express.js, Opine is focused on high performance, content negotiation (which is awesome when returning responses based on a type of request), robust routing, and support for HTTP proxy middleware (which is useful in Authorization, Load balancing, Logging, etc). The future is bright for Opine!

import opine from "../../mod.ts";

const app = opine();

app.get("/", function (req, res) {
  res.send("Hello Deno!");
});

const server = app.listen();
const address = server.listener.addr as Deno.NetAddr;
console.log(`Server started on ${address.hostname}:${address.port}`);

I really love how content negotiation is handled in Opine, making you deal with each type of formatting at a glance:

import { opine } from "../../mod.ts";
import { users } from "./db.ts";
import type { Request, Response } from "../../src/types.ts";

const app = opine();

app.get("/", (req, res) => {
  res.format({
    html() {
      res.send(
        `<ul>${users.map((user) => `<li>${user.name}</li>`).join("")}</ul>`,
      );
    },

    text() {
      res.send(users.map((user) => ` - ${user.name}\n`).join(""));
    },

    json() {
      res.json(users);
    },
  });
});

Passport.js/Onyx

Passport.js simply helps in handling authentication in your Node server. It serves as a middleware, extremely pliable and modular. It is widely used in any Express.js-based web application. It provides support for a set of authentication strategies(username and password, Facebook, Twitter, etc).

Unlike Passport.js, the main focus of Onyx is keeping code clean and systematic. It helps you streamline your authentication strategies without importing, as you would do in Passport.js.

Just as you would apply Passport.js as a middleware, the same goes for Onyx:

import { Router } from '../deps.ts';
import { onyx } from '../deps.ts';
import User from './models/userModels.ts';

const router = new Router();

// invoke onyx.authenticate with the name of the strategy, invoke the result with context
router.post('/login', async (ctx) => {
  await (await onyx.authenticate('local'))(ctx);

  if (await ctx.state.isAuthenticated()) {
    const { username } = await ctx.state.getUser();
    ctx.response.body = {
      success: true,
      username,
      isAuth: true,
    };
  } else {
    const message = ctx.state.onyx.errorMessage || 'login unsuccessful';
    ctx.response.body = {
      success: false,
      message,
      isAuth: false,
    };
  }
});

Pretty straightforward to setup in your server file. It’s the same process you would do in Node:

import { Application, send, join, log } from '../deps.ts';
import { Session } from '../deps.ts';

// Import in onyx and setup
import { onyx } from '../deps.ts';
import './onyx-setup.ts';

// Server Middlewares
import router from './routes.ts';

// SSR
import { html, browserBundlePath, js } from './ssrConstants.tsx';

const port: number = Number(Deno.env.get('PORT')) || 4000;
const app: Application = new Application();

// session with Server Memory
// const session = new Session({ framework: 'oak' });

// session with Redis Database
const session = new Session({
  framework: 'oak',
  store: 'redis',
  hostname: '127.0.0.1',
  port: 6379,
});

// Initialize Session
await session.init();
app.use(session.use()(session));

// Initialize onyx after session
app.use(onyx.initialize());

NodeRedis/DenoRedis

Redis is a popular in-memory data structure server often known and used for caching, as well as database and message brokering. It is super fast with amazingly high throughput.

In Node, node-redis has been a high performant Redis client, which is entirely asynchronous.

deno-redis is the implementation of Redis client for Deno:

import { connect } from "https://deno.land/x/redis/mod.ts";
const redis = await connect({
  hostname: "127.0.0.1",
  port: 6379
});
const ok = await redis.set("hoge", "fuga");
const fuga = await redis.get("hoge");

Nodemon/Denon

Nodemon is a command-line interface (CLI) that watches the file system for any changes in your Node project and automatically restarts the process/server. This helps to avoid manually restarting your server to see changes already made.

In Deno, we have Denon. No difference to nodemon. All you have to do is replace deno with the word denon.

denon run app.ts

WebSocket

The Websocket API opens a two-way interactive communication between the client and the server. Basically, there is a persistent connection between a client and a server so that both can send data at any time. The ws library was built as a client and server implementation for your Node project.

Fortunately, we have deno websocket — a library that’s the same as ws but for Deno.

Usage on the server side is quite similar to what would happen with any Node project:

import { WebSocket, WebSocketServer } from "https://deno.land/x/[email protected]/mod.ts";

const wss = new WebSocketServer(8080);
wss.on("connection", function (ws: WebSocket) {
  ws.on("message", function (message: string) {
    console.log(message);
    ws.send(message)
  });
});

Same for the client side:

import { WebSocket } from "https://deno.land/x/[email protected]/mod.ts";
const endpoint = "ws://127.0.0.1:8080";
const ws: WebSocket = new WebSocket(endpoint);
ws.on("open", function() {
  console.log("ws connected!");
});
ws.on("message", function (message: string) {
  console.log(message);
});
ws.send("something");

CORS

Next we have cors, a Node package providing support as a middleware which can be used to enable CORS with a variety of options.

A simple usage to enable all cors requests in an Express.js application can be seen below:

var express = require('express')
var cors = require('cors')
var app = express()

app.use(cors())

app.get('/products/:id', function (req, res, next) {
  res.json({msg: 'This is CORS-enabled for all origins!'})
})

app.listen(80, function () {
  console.log('CORS-enabled web server listening on port 80')
})

In Deno, we would do same in Opine. For example:

import { opine, serveStatic } from "https://deno.land/x/opine/mod.ts";
import { opineCors } from "../../mod.ts";

const app = opine();

app.use(opineCors()); // Enable CORS for All Routes

app
  .use(serveStatic(`${Deno.cwd()}/examples/opine/static`))
  .get("/products/:id", (_req, res) => {
    res.json({msg: 'This is CORS-enabled for all origins!'});
  })
  .listen(
    { port: 8000 },
    () => console.info("CORS-enabled web server listening on port 8000"),
  );

Bcrypt/BCrypt

Both are similar libraries used in hashing passwords. Bcrypt, designed by Niel Provos, is a password-hashing function that is mostly used on passwords. What it basically does is generate a hash from the password and save it.

While we have had Bcrypt for Node, we now have BCrypt, but for Deno. Usage in Deno is still almost as it is done in Node:

import * as bcrypt from "https://deno.land/x/bcrypt/mod.ts";

const hash = await bcrypt.hash("test");

// To check a password
const result = await bcrypt.compare("test", hash);

Electron/WebView

In Node, you can create cross-platform desktop applications using Electron. In Deno, we now have WebView. It is also used to create GUIs for cross platform desktop applications:

import { WebView } from "https://deno.land/x/webview/mod.ts";

const html = `
  <html>
  <body>
    <h1>Hello from deno</h1>
  </body>
  </html>
`;

await new WebView({
  title: "Local webview_deno example",
  url: `data:text/html,${encodeURIComponent(html)}`,
  height: 600,
  resizable: true,
  debug: true,
  frameless: false,
}).run();

MongoDB

MongoDB is popular, scalable, and flexible. It is a document-based database mostly and widely used in the JavaScript ecosystem.

And yes, it is now possible to have MongoDB in Deno:

import { MongoClient } from "https://deno.land/x/[email protected]/mod.ts";

const client = new MongoClient();
client.connectWithUri("mongodb://localhost:27017");

// Defining schema interface
interface UserSchema {
  _id: { $oid: string };
  username: string;
  password: string;
}

const db = client.database("test");
const users = db.collection<UserSchema>("users");

// insert
const insertId = await users.insertOne({
  username: "user1",
  password: "pass1",
});

// insertMany
const insertIds = await users.insertMany([
  {
    username: "user1",
    password: "pass1",
  },
  {
    username: "user2",
    password: "pass2",
  },
]);

// findOne
const user1 = await users.findOne({ _id: insertId });

// find
const all_users = await users.find({ username: { $ne: null } });

// find by ObjectId
const user1_id = await users.findOne({ _id: "idxxx" });

SMTP

SMTP serves as the main transport in Nodemailer for sending messages. Now available in Deno as Deno SMTP:

import { SmtpClient } from "https://deno.land/x/smtp/mod.ts";

const client = new SmtpClient();

await client.connect({
  hostname: "smtp.163.com",
  port: 25,
  username: "username",
  password: "password",
});

await client.send({
  from: "[email protected]",
  to: "[email protected]",
  subject: "Mail Title",
  content: "Mail Content,maybe HTML",
});

await client.close();

NPM/Trex

npm in Node is the popular package management tool that has been in existence for a long time now, and it is awesome that we have an alternative to it in Deno with Trex. It comes with a lot of options, much like npm. Never forget that packages are cached and only one file is generated.

There are a lot of these Deno alternatives, which are currently still in development. We still have:

  • dinoenv – to manage environment variables
  • denodb – ORM for MySQL, MongoDB, SQLite
  • csv – a CSV parser
  • deno-mysql – MySQL driver
  • cac – framework for building command-line applications.

Conclusion

In this article, we’ve gone over some of the Deno alternatives to popular Node projects used during development. We believe Deno is still growing, and it’ll be great to know the current alternatives already available if you will be venturing further into the Deno world.

If you feel I skipped a popular Node alternative, you can drop them as a reply.

200’s only Monitor failed and slow network requests in production

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, LogRocket Network Request MonitoringLogRocket Network Request Monitoringhttps://logrocket.com/signup/

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, try LogRocket

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free

Share this: