In newer versions of Node.js you can register your own loader and resolvers.
This is an example of automatically transpiling .ts
files.
Usage:
> node --import ./ts-loader.mjs ./my-app.ts
import { transform } from 'esbuild'; | |
import { existsSync } from 'node:fs'; | |
import { fileURLToPath } from 'node:url'; | |
const isRelativeJs = /^\.{1,2}\/.+\.js$/; | |
/** | |
* In TypeScript you can use .js extension in import statements, even though the actual file uses .ts | |
* @see https://nodejs.org/api/module.html#resolvespecifier-context-nextresolve | |
* @param {string} specifier | |
* @param {Object} context | |
* @param {Function} nextResolve | |
*/ | |
export async function resolve(specifier, context, nextResolve) { | |
if (isRelativeJs.test(specifier) && !existsSync(fileURLToPath(new URL(specifier, context.parentURL)))) { | |
return nextResolve(specifier.replace(/\.js$/, '.ts'), context); | |
} | |
return nextResolve(specifier, context); | |
} | |
/** | |
* Transpile .ts files using esbuild. | |
* @see https://nodejs.org/api/module.html#loadurl-context-nextload | |
* @param {string} url | |
* @param {Object} context | |
* @param {Function} nextLoad | |
*/ | |
export async function load(url, context, nextLoad) { | |
if (!url.endsWith('.ts')) return nextLoad(url, context); | |
const { source, format } = await nextLoad(url, { ...context, format: 'module' }); | |
const { code } = await transform(source, { loader: 'ts' }); | |
return { source: code, format }; | |
} |
import { register } from 'node:module'; | |
register(new URL('ts-loader-hooks.mjs', import.meta.url)); |