Skip to content

Make babel transform lazy loading optional #417

@iivvaannxx

Description

@iivvaannxx

Context

Jiti's lazy-loading approach for the Babel transform is the best option for most use cases. Since the Babel transform requires loading a substantial dependency, deferring its load until needed provides meaningful performance benefits when the transform isn't required. However, I think I ran into a use case where it might make sense to eagerly load it.

We work with a runtime environment that only supports CommonJS execution. The workflow involves:

  1. Writing source code in ESM for better developer experience
  2. Using jiti to dynamically load configuration files at runtime
  3. Bundling everything with Webpack into a single CJS file for deployment
import { createJiti } from "jiti";

async function loadConfig(name) {
  const jiti = createJiti(__filename);
  const path = resolve(__dirname, `./config/config.${name}`);

  const config = await jiti.import(path, { default: true });
  return config;
}

Problem

When bundling with Webpack, the ESM version of jiti (dist/lib/jiti.mjs) contains this code:

let _transform;
function lazyTransform(...args) {
  if (!_transform) {
    _transform = createRequire(import.meta.url)("../dist/babel.cjs");
  }
  return _transform(...args);
}

And Webpack's default behavior is to replace import.meta.url with a static file path at build time:

// After Webpack processes it
_transform = createRequire("file:///Users/username/project/node_modules/jiti/lib/jiti.mjs")("../dist/babel.cjs");

This hardcoded absolute path doesn't exist in the production runtime, causing the lazy load to fail:

Error: Cannot find module '../dist/babel.cjs'

Workaround

I managed to workaround it by using the CJS distributed version via require('jiti') as it does not use import.meta.url under the hood:

const { createJiti } = require("jiti");  // Uses lib/jiti.cjs

Webpack can properly handle and bundle this require() call. However, the CommonJS entry point is marked as deprecated, and I'm concerned about future compatibility.

Proposed solutions

Of course, if someone has a better solution please let me know. From my point of view I think either of these two options below could work:

Option 1: Configuration Flag

const jiti = createJiti(__filename, {
  eagerTransform: true  // Loads babel immediately
});

Option 2: Separate Entry Point

import { createJiti } from "jiti/eager";

Additional information

  • Would you be willing to help implement this feature?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions