How to convert from NPM/Node to Deno

May 16, 2020

There are some key differences between Deno and Node. The most significant for the purposes of speaking about converting to Deno are:

  • No NPM, no package.json.
  • no require(), only ES modules (import X from Y) are supported.
  • Imports support full urls (import * as SomePackage from 'https://example.com/script.ts') (local/relative imports work too!)
  • There is no node_modules directory (it is cached automatically)
  • All imports must have a file extension - so you can't do import Package from './someFile', it would have to be import Package from './someFile.ts' (or .js)

How to convert an existing project to work on Deno:

To convert an existing project, you will have to do the following:

Add file extensions to all imports

Node does not require a file extension to an import. If you have two files in the same directory (fileA.js and fileB.js) you can import fileB into fileA by doing import * as b from './fileB.js'.

To make this work in Deno you must add the file extension to those imports (changing it to import * as b from './fileB.js')

Remove require() imports and use only ES module imports

A lot of existing code written for node will use require() to import files. This is not supported in Deno.

Replace uses of require() with ES module import statements.

// Old node way:
// const package = require('./file.ts');

// New deno way:
import package from './file.ts';

Replace dependencies in package.json with a self contained dependency list (deps.ts)

Deno does not use NPM, Yarn or package.json. Instead all third party dependencies are imported via a full URL.

To keep these organised it is heavily recommended that you create a self contained dependency list, which is often named deps.ts.

// deps.ts - the self contained dependency list
// List all of your dependencies here, and export them:

export {
  assert,
  assertEquals,
  assertStrContains,
} from "https://deno.land/std/testing/asserts.ts";

// ...

Then you can import deps.ts in files which need to use those exported functions:

// someTest.ts (which uses the self contained dependency list)
import { assertEquals, assertStrContains } from "./deps.ts";

If some of your dependencies are not supported on Deno because they use require() imports then you can use the Pika CDN for your imports. You can also use the createRequire() helper provided at https://deno.land/std/node/module.ts. An example of how to use it:

import { createRequire } from "https://deno.land/std/node/module.ts";

const require = createRequire(import.meta.url);
// Loads native module polyfill.
const path = require("path");
// Loads extensionless module.
const cjsModule = require("./my_mod");
// Visits node_modules.
const leftPad = require("left-pad");

Rename index.ts or index.js to mod.ts

This is completely optional but is part of the Deno style guide. If you have an index file as the entry point, rename it to mod.ts (and update all uses of it).

index.ts or index.js has no significance in Deno. The recommend way to have a main file is to name it mod.ts (mod, short for module). This follows the Rust language convention.

(To be continued/WIP)

Further reading

  • Check the list of Node compatibility here