or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

dynamic-imports.mdindex.mdlazy-loading.mdmodule-metadata.mdmodule-names.mdmodule-transformation.md
tile.json

lazy-loading.mddocs/

Lazy Loading

Support for lazy module loading with configurable lazy loading strategies. This functionality helps optimize bundle size and loading performance by deferring module initialization until first access.

Note: The lazy loading utilities are internal to the package and not directly exported. They are used through the lazy option in rewriteModuleStatementsAndPrepareHeader and related configuration functions.

Capabilities

Lazy Configuration Types

Configure which modules should be loaded lazily.

/**
 * Configuration for lazy module loading.
 * - boolean: true = lazy load external modules, false = eager load all
 * - string[]: array of module names to load lazily
 * - function: custom function to determine lazy loading per module
 */
type Lazy = boolean | string[] | ((source: string) => boolean);

Wrapper Payload Generation

Convert lazy configuration into a function that determines wrapper payloads.

/**
 * Convert lazy configuration to a wrapper payload getter function.
 * Returns a function that determines if a module should be lazy loaded.
 */
function toGetWrapperPayload(
  lazy: Lazy
): (source: string, metadata: SourceModuleMetadata) => null | "lazy";

Usage Examples:

// Note: These functions are internal utilities and not directly exported.
// They are used internally by rewriteModuleStatementsAndPrepareHeader
// when the lazy option is provided.

// Example of how lazy loading is configured (conceptually):
const lazyConfig: Lazy = true; // Boolean configuration - lazy load external modules only
console.log(booleanPayload("./local-file.js", metadata)); // null (eager)
console.log(booleanPayload("lodash", metadata)); // "lazy"

// Array configuration - specific modules to lazy load
const arrayPayload = Lazy.toGetWrapperPayload(["lodash", "moment"]);
console.log(arrayPayload("lodash", metadata)); // "lazy"
console.log(arrayPayload("react", metadata)); // null (eager)

// Function configuration - custom logic
const fnPayload = Lazy.toGetWrapperPayload((source) => {
  return source.startsWith("@babel/") || source.includes("heavy-lib");
});
console.log(fnPayload("@babel/core", metadata)); // "lazy"
console.log(fnPayload("react", metadata)); // null (eager)

// Disabled lazy loading
const eagerPayload = Lazy.toGetWrapperPayload(false);
console.log(eagerPayload("any-module", metadata)); // null (all eager)

Reference Wrapping

Wrap module references with lazy loading call expressions.

/**
 * Wrap reference with lazy loading call if the payload indicates lazy loading.
 * Returns null if no wrapping is needed (eager loading).
 */
function wrapReference(
  ref: Identifier,
  payload: unknown
): Expression | null;

Usage Examples:

// Note: These functions are internal utilities and not directly exported.
// They are used internally by the module transformation system.

import { types as t } from "@babel/core";

const moduleRef = t.identifier("_lodash");

// Lazy loading behavior (conceptually):
// - When payload is "lazy": converts reference to function call like _lodash()
// - When payload is null: uses original reference directly

Lazy Loading Behavior

Boolean Configuration

When lazy is a boolean:

  • true - Lazy load external dependencies (those without . in the name), eager load relative imports
  • false - Eager load all modules
// true: External modules are lazy, local files are eager
import lodash from "lodash";        // → lazy
import utils from "./utils.js";    // → eager
import api from "../api/client.js"; // → eager

// false: All modules are eager
import lodash from "lodash";        // → eager
import utils from "./utils.js";    // → eager

Array Configuration

When lazy is a string array, only modules in the array are lazy loaded:

const lazyModules = ["lodash", "moment", "heavy-computation"];

import lodash from "lodash";              // → lazy (in array)
import moment from "moment";              // → lazy (in array)  
import react from "react";                // → eager (not in array)
import compute from "heavy-computation";  // → lazy (in array)

Function Configuration

When lazy is a function, it's called for each module to determine lazy loading:

const lazyFn = (source: string) => {
  // Lazy load all Babel packages
  if (source.startsWith("@babel/")) return true;
  
  // Lazy load specific heavy libraries
  if (["lodash", "moment", "three"].includes(source)) return true;
  
  // Eager load everything else
  return false;
};

import core from "@babel/core";     // → lazy (starts with @babel/)
import lodash from "lodash";        // → lazy (in heavy libraries list)
import react from "react";          // → eager (function returns false)

Side Effect Import Handling

Side effect imports and re-export-all statements are never lazy loaded, regardless of configuration:

// These are always eager, even with lazy: true
import "./polyfills.js";           // Side effect import
export * from "some-module";       // Re-export all

Implementation Details

Module Reference Transformation

Lazy loaded modules are wrapped in function calls that initialize the module on first access:

// Original code
import { debounce } from "lodash";
console.log(debounce);

// Transformed with lazy loading  
const _lodash = () => require("lodash");
console.log(_lodash().debounce);

Function Call Generation

The wrapReference function converts identifier references into function calls:

// Input: identifier reference to lazy module
const ref = t.identifier("_lodash");

// Output: function call expression  
const wrapped = Lazy.wrapReference(ref, "lazy");
// AST equivalent of: _lodash()

Performance Considerations

Lazy loading provides benefits for:

  • Large dependencies - Heavy libraries like Lodash, Moment.js
  • Conditional code paths - Modules only used in specific branches
  • Development tools - Build-time utilities not needed in production

However, it adds overhead for:

  • Small modules - Function call overhead may exceed benefits
  • Frequently accessed modules - Repeated function calls vs direct access
  • Critical path modules - Modules needed immediately at startup