npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@digitak/tsc-esm

v3.1.4

Published

A cli utility that compile using tsc then add .js extension to esm import names

Downloads

13,834

Readme

I don't recommend anymore to use this package.

Since TS 4.7 it is now possible to set the moduleResolution field to node16 or nodeNext which enforces the use of the .js extension at the end of the imports.

Previously, Typescript allowed to not add the imported file extension if it was a Typescript or Javascript file. This behavior was opposed to the recent developments of Ecmascript. Browsers, Node and Deno all needed the .js extension.

I first developped tsc-esm as a patch to the tsc compiler that would add the .js extension. But this technique has drawbacks. For example, it cannot deal with Typescript aliases. I strongly encourage to follow the Ecmascript guidelines and the recent Typescript extension, that is to use Typescript@^4.7 and to set the moduleResolution field to node16 or nodeNext in tsconfig.json.

tsc-esm is a small wrapper library can be used to replace Typescript's tsc compilation command when generating modern Javascript with ES6 modules.

The problem

In order to use ES6 modules either in a browser, a Node (with "type": "module") or a Deno environment, a ".js" extension is mandatory at the end of each import statement.

For example, you can do:

import foo from './foo.js'

but you cannot do:

import foo from './foo'

However Typescript compiler do understand the latter case and it's even recommended to use it. Some linters will complain if you add the unnecessary ".js" or ".ts" extension.

In the same way, Typescript can understant when you a /foo/index.ts directory structure, you can do

import foo from '/foo'

and Typescript will understand you need to import the index.ts file.

That's actually great... Until you want to compile your Typescript code to modern Javascript with ES6 modules. As it is explained well enough in this long issue: provide a way to add the '.js' file extension to the end of module specifiers, the Typescript team considers that since users can manually add themselves a ".js" extension to all their imports, this is not an issue.

In my opinion it is still an issue because:

  1. valid Typescript code can be compiled with no errors and still generate invalid Javascript (and all platforms disagree it is invalid: Browser, Node and Deno),
  2. even if it works, it is semantically incorrect to write import foo from "/foo/index.js" when your directory structure is /foo/index.ts, because you are explicitly importing to a file that does not exist yet (it will exist after compilation).

The solution

Use tsc-esm instead of tsc.

tsc-esm works in two simple steps:

  1. it calls tsc,
  2. it uses the grubber library to safely parse the generated javascript files and patch the import expressions.

It is highly recommended that you have a tsconfig.json configuration file in your root project with either compilerOptions.outDir or include option set ; otherwise all .js files in your project will be scanned and transformed.

CLI

Global installation
npm i -g @digitak/tsc-esm
tsc-esm
Local installation
npm i -g @digitak/tsc-esm

Then add a script in your package.json:

{
   "scripts": {
      "build": "tsc-esm"
   }
}

Then you can run:

npm run build

API

import { build } from '@digitak/tsc-esm'

build()

Or:

import { compile, patch } from '@digitak/tsc-esm'

compile()
patch()
Aliases

You can pass aliases to the build or the patch functions to control how some paths should be transformed or not:

function build(aliases?: Array<AliasResolver>): void
function patch(aliases?: Array<AliasResolver>): void

type AliasResolver = {
   find: RegExp; // the path to match
   replacement: string | null; // the replacement value
};

The function String::replace is used internally so you can replace your path using special patterns like $1or $&.

If the replacement value is null, the path will be left untransformed.

It can be useful when working when libraries that don't have clean type definitions.

If you have a chokidar dependency for example you might need to tell tsc-esc to not patch this specific import:

build([
   { find: /^chokidar$/, replacement: null },
])

Then all import chokidar from 'chokidar' statements will be left unchanged, otherwise it would have been transformed into import chokidar from 'chokidar/index.js' which is not typed.