or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdcore-api.mddynamic-imports.mdember-addon.mdindex.md
tile.json

dynamic-imports.mddocs/

Dynamic Imports

Babel plugin enabling dynamic imports with code splitting for lazy loading of dependencies. Transforms import() calls to enable runtime loading of NPM packages and app modules.

Capabilities

Babel Plugin Setup

Enable dynamic import support by adding the babel plugin to your build configuration:

// In ember-cli-build.js
let app = new EmberApp(defaults, {
  babel: {
    plugins: [require.resolve('ember-auto-import/babel-plugin')]
  }
});

For addon authors, configure in index.js:

// In addon's index.js
module.exports = {
  name: 'my-addon',
  options: {
    babel: {
      plugins: [require.resolve('ember-auto-import/babel-plugin')]
    }
  }
};

Babel Plugin Function

The main babel plugin function that transforms dynamic imports:

/**
 * Babel plugin for transforming dynamic imports
 * Transforms import() calls for NPM packages to use webpack dynamic imports
 * @param babel - Babel instance with types and utilities
 * @returns Babel plugin configuration object
 */
function emberAutoImport(babel: typeof Babel): BabelPlugin;

interface BabelPlugin {
  /** Inherits from babel-plugin-syntax-dynamic-import for syntax support */
  inherits: any;
  
  /** Babel visitor methods for transforming AST nodes */
  visitor: {
    /** Transform import() calls for dynamic imports */
    Import(path: NodePath<t.Import>, state: any): void;
    
    /** Transform CallExpression nodes for importSync handling */
    CallExpression(path: any): void;
  };
}

Usage Example:

// The plugin automatically transforms these patterns:

// NPM package dynamic import
import('chart.js').then(Chart => {
  // Becomes: emberAutoImportDynamic('chart.js')
});

// Template literal dynamic import  
const libName = 'lodash';
import(`${libName}/get`).then(get => {
  // Becomes: emberAutoImportDynamic('${e}', libName)
});

// importSync transformation
import { importSync } from '@embroider/macros';
const lodash = importSync('lodash');
// Becomes: require('lodash')

Dynamic Import Transformation

Transform import() calls for NPM packages and local modules:

/**
 * Transforms import() calls based on the imported path type
 * Handles static strings, template literals, and relative paths
 */
visitor: {
  Import(path: NodePath, state: BabelState): void;
}

The transformation process:

  1. Identifies the type of import (NPM package, local module, URL)
  2. For NPM packages: transforms to emberAutoImportDynamic()
  3. For template literals: preserves expressions and transforms the pattern
  4. For relative paths: resolves using module-resolver plugin

Static String Imports:

// Original
import('lodash').then(module => module.default);

// Transformed
emberAutoImportDynamic('lodash').then(module => module.default);

Template Literal Imports:

// Original  
const lib = 'chart';
import(`${lib}.js`).then(module => module.default);

// Transformed
emberAutoImportDynamic('${e}', lib).then(module => module.default);

ImportSync Transformation

Transform importSync() calls from @embroider/macros to regular require() calls:

/**
 * Transforms importSync() calls to require() or emberAutoImportSync()
 * Handles both static strings and template literals
 */
visitor: {
  CallExpression(path: NodePath): void;
}

Static ImportSync:

import { importSync } from '@embroider/macros';

// Original
const lodash = importSync('lodash');

// Transformed  
const lodash = require('lodash');

Template Literal ImportSync:

// Original
const libName = 'lodash';
const lib = importSync(`${libName}/get`);

// Transformed
const lib = emberAutoImportSync('${e}', libName);

Runtime Dynamic Import

The runtime functions created by the transformation:

/**
 * Runtime function for dynamic imports created by the babel plugin
 * Handles lazy loading of NPM packages with webpack code splitting
 */
function emberAutoImportDynamic(specifier: string, ...expressions: any[]): Promise<any>;

/**
 * Runtime function for synchronous imports created by the babel plugin  
 * Handles template literal imports with variable substitution
 */
function emberAutoImportSync(pattern: string, ...expressions: any[]): any;

These functions are automatically available in your runtime environment and handle:

  • NPM package resolution and loading
  • Code splitting and chunk creation
  • Template literal variable substitution
  • Module caching and deduplication

Usage Examples:

// Dynamic import with code splitting
export default Route.extend({
  async model() {
    // This creates a separate bundle for chart.js
    const Chart = await import('chart.js');
    const data = await fetch('/api/chart-data').then(r => r.json());
    
    return { Chart: Chart.default, data };
  }
});

// Dynamic import with variables
async loadUtility(utilityName) {
  // Template literal allows dynamic selection
  const utility = await import(`lodash/${utilityName}`);
  return utility.default;
}

// Loading multiple chunks
Promise.all([
  import('d3'),
  import('topojson'),
  import('lodash')
]).then(([d3, topojson, lodash]) => {
  // All three libraries loaded as separate chunks
});

Error Handling

The babel plugin includes error handling for common issues:

/**
 * Error cases handled by the babel plugin:
 * - Missing module-resolver plugin for relative imports
 * - URL imports with importSync (not supported)
 * - Invalid template literal patterns
 */

Common Errors:

// Error: URL imports not supported with importSync
import { importSync } from '@embroider/macros';
const lib = importSync('https://cdn.example.com/lib.js'); // Throws error

// Error: Missing module-resolver plugin
import(`./relative-${path}`).then(module => {
  // Requires babel-plugin-module-resolver to be configured
});

Development vs Production

Dynamic imports behave differently in development and production:

Development:

  • Uses eval sourcemaps for fast rebuilds (unless forbidEval: true)
  • Chunks are served from the development server
  • Hot reloading works with dynamic imports

Production:

  • Creates optimized webpack chunks with hashes
  • Chunks are fingerprinted for caching
  • Tree shaking removes unused exports from dynamic imports

Deployment Considerations:

// Ensure your deployment includes all generated chunks
// Default location: dist/assets/chunk.*.js and dist/assets/chunk.*.css

// Configure custom public path if deploying to CDN
autoImport: {
  publicAssetURL: 'https://cdn.example.com/assets/'
}

Types

/**
 * Babel AST node path for traversal
 */
interface NodePath {
  node: Node;
  parent: Node;
  parentPath: NodePath;
  replaceWith(node: Node): void;
}

/**
 * Babel transformation state
 */
interface BabelState {
  file: {
    opts: {
      filename: string;
      plugins: PluginEntry[];
    };
  };
  opts: any;
}

/**
 * Babel plugin entry configuration
 */
interface PluginEntry {
  key: string;
  options: any;
}