ยท hands on

Write a simple TypeScript script with ESM

I recently wrote a small TypeScript script to generate a Markdown file with a sluggified filename. Since we're now in the era of modern ECMAScript Modules (ESM), I wanted to use this new module system in my TypeScript code. Here's how I did it.

I installed ts-node so I could run my script in a Node.js environment from the command line. The great thing about ts-node is that it works well with ESM. It comes with a binary called ts-node-esm that supports loading ECMAScript modules when you run TypeScript code.

Contents

Making TypeScript Work with ESM

Once you've installed ts-node with npm install, you can immediately direct it to your script by:

npx ts-node-esm src/main.ts

This ensures that an ECMAScript loader is ready when your code is executed.

Handling File and Folder Paths

In the world of ESM, the usual __filename and __dirname constants are not available. So, I found a way to mimic this by using the import.meta property:

import path from 'node:path';
import url from 'node:url';
 
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

Using New File Extensions

TypeScript lets you pick different file extensions to tell whether you're using ES modules (.mts) or CommonJS modules (.cts).

If you only need to run a single script with the ES module syntax, I recommend using the .mts extension. It's great in scenarios where you don't want to set up your whole project to use ES modules.

Demo Code

Here's the complete script I developed:

src/new-post.mts
import GithubSlugger from 'github-slugger';
import fs from 'node:fs';
import path from 'node:path';
import url from 'node:url';
 
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
 
const args = process.argv.slice(2);
const title = args[0];
const slugger = new GithubSlugger();
const slug = slugger.slug(title);
const filePath = path.join(__dirname, 'content', 'blog', `${slug}.md`);
 
console.log(`Creating file "${filePath}"...`);
fs.writeFileSync(filePath, '', 'utf8');
console.log(`Created file "${filePath}".`);

It can be ran as follows:

npx ts-node-esm src/new-post.mts "My Post Title"
Back to Blog