0.1.0 • Published 3 years ago

ts-esm-resolve v0.1.0

Weekly downloads
-
License
MIT
Repository
github
Last release
3 years ago

ts-esm-resolve

npm version CI Coverage Status code style: prettier types MIT license GitHub Discussions

Resolve typescript ES modules

Overview

This package will resolve typescript ES modules. It includes support for the new exports and imports sections of package.json.

For relative and absolute paths it is easy to resolve typescript files, just change the file extension to .ts or .tsx. However for bare specifiers it is a bit more tricky. Most of the time a bare specifier will resolve to a package installed into node_modules that is not part of your source code. But if you are using project references and yarn/npm workspaces then bare specifiers may point to a package that is part of your project.

The aim of this package is to resolve all cases including:

  • Relative and absolute paths
  • Bare specifiers for packages specified as project references in a npm/yarn workspace
  • Bare specifiers resolved by the path key in tsconfig.json.

How to install

yarn add --dev ts-esm-resolve

How to use

You can use this package as a part of build a transpiling node loader for typescript. Here is an example using esbuild for the transpile:

// file loader.mjs
import { fileURLToPath } from "url";
import { transformSync } from "esbuild";
import { tsResolve } from "../../lib/ts-resolve.js";

export function resolve(specifier, context, defaultResolve) {
  const entryTsConfig = process.env["TS_NODE_PROJECT"];
  if (entryTsConfig === undefined || entryTsConfig === null || entryTsConfig === "") {
    throw new Error("Entry tsconfig file must be present in TS_NODE_PROJECT.");
  }
  const resolved = tsResolve(specifier, context, entryTsConfig);
  if (resolved !== undefined) {
    const { fileUrl, tsConfigUrl } = resolved;
    return { url: fileUrl, format: tsConfigUrl };
  }
  return defaultResolve(specifier, context, defaultResolve);
}

export async function load(url, context, defaultLoad) {
  // Return transpiled source if typescript file
  if (isTypescriptFile(url)) {
    // Call defaultLoad to get the source
    const format = "module";
    const { source: rawSource } = await defaultLoad(url, { format }, defaultLoad);
    const source = transpileTypescript(url, rawSource, "esm");
    return { format, source };
  }
  // Let Node.js load it
  return defaultLoad(url, context);
}

function isTypescriptFile(url) {
  const extensionsRegex = /\.ts$/;
  return extensionsRegex.test(url);
}

const isWindows = process.platform === "win32";

function transpileTypescript(url, source, outputFormat) {
  let filename = url;
  if (!isWindows) filename = fileURLToPath(url);

  const {
    code: js,
    warnings,
    map: jsSourceMap,
  } = transformSync(source.toString(), {
    sourcefile: filename,
    sourcemap: "both",
    loader: "ts",
    target: "esnext",
    // This sets the output format for the generated JavaScript files
    // format: format === "module" ? "esm" : "cjs",
    format: outputFormat,
  });

  if (warnings && warnings.length > 0) {
    for (const warning of warnings) {
      console.log(warning.location);
      console.log(warning.text);
    }
  }

  return js;
}

Then you can use it like this:

node --loader loader.mjs myfile.ts
0.1.0

3 years ago