Runtime TypeScript and ESM support for Node.js with seamless interoperability between ESM and CommonJS.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Global ESM loader registration and native runtime mode for seamless TypeScript support across Node.js applications.
Register jiti as a global ESM loader to automatically handle TypeScript and JSX files across your entire Node.js application.
// Import for automatic global registration
import "jiti/register";Usage Examples:
// Method 1: Import in your entry file
import "jiti/register";
import { config } from "./config.ts"; // Automatically works
console.log(config);# Method 2: Use Node.js --import flag
node --import jiti/register index.js
# Method 3: Use via environment variable
NODE_OPTIONS="--import jiti/register" node index.jsRequirements:
Lightweight mode that uses runtime's native import.meta.resolve and dynamic import() capabilities without transformation.
import { createJiti } from "jiti/native";
/**
* Creates a native jiti instance with limited API surface
* @param parentURL - Parent URL for resolution context
* @param jitiOptions - Limited options for native mode
* @returns Jiti instance with native-only capabilities
*/
function createJiti(parentURL?: string | URL, jitiOptions?: JitiOptions): NativeJiti;
interface NativeJiti {
// ✅ Supported methods
import<T>(id: string, opts?: JitiResolveOptions & { default?: true }): Promise<T>;
esmResolve(id: string, opts?: string | JitiResolveOptions): string;
// ❌ Unsupported methods (throw errors)
(id: string): never; // Throws: "jiti() is not supported in native mode, use jiti.import() instead"
transform(opts: TransformOptions): never; // Throws: "transform() is not supported in native mode"
evalModule(source: string, options?: EvalModuleOptions): never; // Throws: "evalModule() is not supported in native mode"
resolve: never; // Throws: "resolve() is not supported in native mode"
}Usage Examples:
import { createJiti } from "jiti/native";
// Create native jiti instance
const jiti = createJiti(import.meta.url);
// Only import() and esmResolve() work in native mode
const module = await jiti.import("./config.js");
const resolved = jiti.esmResolve("./utils.js");
// These methods throw errors in native mode:
try {
jiti.transform({ source: "code" }); // Throws: not supported in native mode
} catch (error) {
console.error(error.message); // "`transform()` is not supported in native mode"
}
try {
jiti.evalModule("code"); // Throws: not supported in native mode
} catch (error) {
console.error(error.message); // "`evalModule()` is not supported in native mode"
}
try {
jiti("./module"); // Throws: not supported in native mode
} catch (error) {
console.error(error.message); // "`jiti()` is not supported in native mode, use `jiti.import()` instead"
}The global ESM loader provides automatic transformation for TypeScript and other supported file types through Node.js's module loading hooks.
Supported File Types:
.ts - TypeScript files.tsx - TypeScript with JSX.mts - TypeScript ES modules.cts - TypeScript CommonJS modules.js - JavaScript (conditionally transformed).json - JSON modules with proper ESM/CommonJS detectionLoader Features:
// ESM Loader Hooks (internal implementation)
export async function resolve(specifier: string, context: ResolveContext, nextResolve: Function): Promise<ResolveResult>;
export async function load(url: string, context: LoadContext, nextLoad: Function): Promise<LoadResult>;Configure the global loader behavior using environment variables.
Environment Variables:
JITI_DEBUG - Enable debug logging for loader operationsJITI_JSX - Enable JSX transformation globallyJITI_FS_CACHE - Control filesystem caching for loaderJITI_SOURCE_MAPS - Enable source maps in loader transformationsJITI_MODULE_CACHE - Control module caching for loaderJITI_INTEROP_DEFAULT - Control default export interoperabilityJITI_ALIAS - Set module aliases (JSON string)JITI_NATIVE_MODULES - Native modules list (JSON string)JITI_TRANSFORM_MODULES - Modules to transform (JSON string)JITI_TRY_NATIVE - Try native import firstUsage Examples:
# Enable JSX and debug mode globally
JITI_JSX=1 JITI_DEBUG=1 node --import jiti/register app.js
# Disable caching for development
JITI_FS_CACHE=false node --import jiti/register dev-server.jsConditional Registration:
// Only register in development
if (process.env.NODE_ENV === "development") {
await import("jiti/register");
}
// Import your TypeScript modules after registration
const { devUtils } = await import("./dev-utils.ts");Application-Wide TypeScript Support:
// main.ts - Entry point with global registration
import "jiti/register";
// Now all imports in your app automatically support TypeScript
import { config } from "./config/app.ts";
import { routes } from "./routes/index.ts";
import { middleware } from "./middleware/auth.ts";
async function startApp() {
const server = (await import("./server.ts")).default;
server.start();
}
startApp();Library Development:
// Enable TypeScript for your library's development
// lib/index.ts
export { LibraryClass } from "./core.ts";
export type { LibraryOptions } from "./types.ts";
// During development, use jiti for testing
// test/setup.ts
import "jiti/register";
import { test } from "./lib/index.ts"; // Uses TypeScript directlyBenefits of Native Mode:
Limitations:
When to Use Native Mode:
// ✅ Good for native mode - JavaScript only
const jiti = createJiti("jiti/native");
await jiti.import("./config.js");
await jiti.import("./utils.mjs");
// ❌ Not suitable for native mode - needs transformation
await jiti.import("./config.ts"); // TypeScript
await jiti.import("./component.tsx"); // JSXDevelopment vs Production:
// Development: Use global registration for TypeScript
if (process.env.NODE_ENV === "development") {
await import("jiti/register");
const { devConfig } = await import("./config.dev.ts");
} else {
// Production: Use compiled JavaScript
const { prodConfig } = await import("./config.prod.js");
}Testing Setup:
// vitest.config.js or jest.config.js
export default {
setupFilesAfterEnv: ["jiti/register"],
// Now test files can import TypeScript directly
};Development Scripts:
{
"scripts": {
"dev": "node --import jiti/register src/dev-server.ts",
"test": "NODE_OPTIONS='--import jiti/register' vitest",
"debug": "JITI_DEBUG=1 node --import jiti/register --inspect src/index.ts"
}
}Loader Error Handling:
The ESM loader provides detailed error information for transformation failures:
// If a TypeScript file has syntax errors, the loader will provide:
// - File location with line/column numbers
// - Syntax error details
// - Code frame showing the problematic code
try {
await import("./broken-syntax.ts");
} catch (error) {
console.error("TypeScript compilation failed:");
console.error(error.message);
console.error(error.location); // File:line:column
}Debug Mode:
# Enable debug logging to see loader operations
JITI_DEBUG=1 node --import jiti/register app.tsOutput shows:
Node.js Version Requirements:
Runtime Detection:
// jiti automatically detects runtime capabilities
const jiti = createJiti(import.meta.url, {
tryNative: true // Try native import first, fallback to transformation
});
// In Bun, this automatically uses native capabilities
// In Node.js, this uses transformation when needed
const module = await jiti.import("./file.ts");Cross-Platform Support:
// Works across different JavaScript runtimes
import { createJiti } from "jiti/native";
// Deno support
const jiti = createJiti(import.meta.url);
const module = await jiti.import("./config.ts");
// Bun support with enhanced native capabilities
const jiti = createJiti(import.meta.url, {
tryNative: true // Bun has excellent native TypeScript support
});