Skip to content

Instantly share code, notes, and snippets.

@guest271314
Last active October 27, 2024 06:48
Show Gist options
  • Save guest271314/b835352777dba6267628b155692487ae to your computer and use it in GitHub Desktop.
Save guest271314/b835352777dba6267628b155692487ae to your computer and use it in GitHub Desktop.
Transpile TypeScript to JavaScript using Deno built-ins
// Transpile TypeScript to JavaScript using Deno built-ins
// Usage: deno -A deno-ts-js-cache.js nm_typescript.ts
// Write Deno's generated cache .ts.js file to stdout and current directory
// ts: Path to .ts script
const [ts] = Deno.args;
const url = new URL(import.meta.resolve(ts));
const { pathname } = url;
const filename = pathname.split("/").at(-1);
const decoder = new TextDecoder();
// Path to generated cache .ts.js script
const jsCache = `file${pathname}.js`;
// info: Get Deno cache and TypeScript cache subdirectories
const info = new Deno.Command(Deno.execPath(), {
args: [
"info",
"--json",
],
});
// Deno cache directory and generated TypeScript subdirectory
const { denoDir, typescriptCache } = JSON.parse(
decoder.decode((await info.output()).stdout),
);
// Cache
// https://docs.deno.com/runtime/fundamentals/modules/#vendoring-remote-modules
const command = await new Deno.Command(Deno.execPath(), {
args: ["install", "--entrypoint", "-r", ts],
}).output();
// Generated cache .ts.js file
const js = (await Deno.readTextFile(`${typescriptCache}/${jsCache}`))
.replace(/\/\/#\ssourceMappingURL=.+\n\/\/.+$/img, "");
console.log(js);
await Deno.writeTextFile(`${filename}.js`, js);
Deno.exit(0);

It was once possible to transpile TypeScript to JavaScript, to an appreciable degree, with deno bundle. There was also an --unstable-byonm command line switch that could be used in part to bundle Node.js modules.

deno bundle is deprecated in Deno 2. See Deprecate "deno bundle" #11073, Proposal: deprecate deno bundle, add deno pack #15463, Transpiling deno-flavored-typescript #20011.

Since deno is a TypeScript/JavaScript runtine, it should/might be possible to get the JavaScript that Deno generates for TypeScript input.

Let's try.

We'll execute the TypeScript .ts source, wait for generated JavaScript to be created in Deno's cache directory, then get the .js file.

There's probably some parts of this that won't work as intended, because we'll be using deno's built-in for purposes they were not intended for.

Some context. I'm just using a single .ts file for testing nm_typescript.ts. In fact the only .ts file that I use, though didn't write because, with all due respect, I'm not that interested in learning TypeScript syntax or philosophy.

I am interested in learning the peculiarities of JavaScript engines, runtimes, and programming languages in general. So I took an algorithm I've written in JavaScript nm_host.js and other programming language and used an online code converter Online TypeScript to JavaScript Converter to create the TypeScript version from the working JavaScript version.

I used the online tool because Microsoft Typescript (tsc) does not have the capability to convert JavaScript to TypeScript.

Long test spin of TypeScript short, I wound up right back to the working JavaScript file I started with!

I could just use bun build --no-bundle to convert TypeScript to JavaScript. I've done that many times.

However, I have a sense I can massage a .js file out of deno, by some means built in to the executable, without using any libraries such as deno_bundle, which depends on esbuild. bun build differs from esbuild is some regards, described by Bun folks here vs esbuild.

Alright, enough context and the sin of not being enthusiastic or feigning enthusiasm about the glory of TypeScript.

Back to some code tooling. Or, more precisely, writing some JavaScript code to convert TypeScript to JavaScript without any libraries, using Deno built-ins.

What I have noticed so far is

import { x } from "./exports.ts";

doesn't wind up in the generated .ts.js file

const x = await import("./exports.ts");

does.

I took the liberty of replacing the generated source map and Deno build ID in the generated file with nothing.

For the rest, if you are interested in breaking the little contraption I cobbled together, you'll have to throw some TypeScript code at it to see what you notice, what breaks, how far you can go with this internal Deno "transpiler", that really is just picking up the cache that Deno generates when running .ts files.

Happy hacking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment