CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-metro-transform-worker

Transform worker for Metro bundler that handles JavaScript, TypeScript, JSX, JSON, and asset transformations through a comprehensive Babel-based pipeline.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

cache-management.mddocs/

Cache Management

Metro Transform Worker provides comprehensive cache key generation for efficient incremental builds and cache invalidation across the transformation pipeline.

Capabilities

Cache Key Generation

Generates deterministic cache keys based on transformer configuration, file dependencies, and transformation settings to enable efficient caching.

/**
 * Generate cache key for transformer configuration
 * @param config - Transformer configuration object
 * @returns String cache key that changes when configuration affects transformation output
 */
function getCacheKey(config: JsTransformerConfig): string;

Usage Examples:

const { getCacheKey } = require("metro-transform-worker");

const config = {
  babelTransformerPath: require.resolve("@react-native/metro-babel-transformer"),
  minifierPath: require.resolve("metro-minify-terser"),
  assetRegistryPath: "react-native/Libraries/Image/AssetRegistry",
  assetPlugins: [],
  enableBabelRCLookup: true,
  enableBabelRuntime: false,
  globalPrefix: "",
  hermesParser: false,
  minifierConfig: {
    output: { ascii_only: true },
    compress: { reduce_funcs: false },
  },
  optimizationSizeLimit: 150000,
  publicPath: "/assets",
  allowOptionalDependencies: "ignore",
  unstable_disableModuleWrapping: false,
  unstable_compactOutput: false,
  unstable_allowRequireContext: false,
};

// Generate cache key for configuration
const cacheKey = getCacheKey(config);
console.log(cacheKey); // "abc123def456...ghi789$hjk012$lmn345"

// Cache keys change when configuration changes
const modifiedConfig = { ...config, dev: true };
const newCacheKey = getCacheKey(modifiedConfig);
console.log(cacheKey !== newCacheKey); // true

Cache Key Components

The cache key is composed of several components that ensure invalidation when transformation behavior changes:

File Dependencies

  • Transform worker source: Main transformation logic
  • Babel transformer: Configured Babel transformer module
  • Minifier: Configured minifier module
  • Utility modules: Asset transformer, minifier loader, etc.
  • Metro internals: Import name generation, file wrapping, etc.
  • Transform plugins: All Metro transform plugin files

Configuration Hash

  • Transformer config: All configuration options except paths
  • Stable hashing: Deterministic serialization of configuration objects
  • Nested object handling: Deep hashing of complex configuration structures

Babel Transformer Integration

  • Babel cache key: Includes Babel transformer's own cache key if available
  • Plugin dependencies: Babel plugin file dependencies
  • Preset dependencies: Babel preset file dependencies

Cache Key Structure

// Cache key format: "files$config$babel"
interface CacheKeyComponents {
  /** Hash of all file dependencies that affect transformation */
  filesKey: string;
  /** Hash of configuration object (excluding file paths) */
  configHash: string;
  /** Babel transformer's cache key (if available) */
  babelKey: string;
}

The final cache key is constructed by joining these components with $ separators:

const cacheKey = [filesKey, configHash, babelKey].join("$");

Dependency Tracking

The cache system tracks dependencies across multiple layers:

Transform Worker Dependencies

const coreFiles = [
  __filename, // metro-transform-worker/src/index.js
  require.resolve(babelTransformerPath),
  require.resolve(minifierPath),
  require.resolve("./utils/getMinifier"),
  require.resolve("./utils/assetTransformer"),
];

Metro Internal Dependencies

const metroFiles = [
  require.resolve("metro/private/ModuleGraph/worker/generateImportNames"),
  require.resolve("metro/private/ModuleGraph/worker/JsFileWrapping"),
];

Transform Plugin Dependencies

const pluginFiles = metroTransformPlugins.getTransformPluginCacheKeyFiles();

Configuration Hashing

The configuration hash excludes file paths (which are already covered by file dependency tracking) and focuses on options that affect transformation behavior:

interface HashedConfigSubset {
  // Excludes: babelTransformerPath, minifierPath
  assetPlugins: ReadonlyArray<string>;
  assetRegistryPath: string;
  asyncRequireModulePath: string;
  dynamicDepsInPackages: DynamicRequiresBehavior;
  enableBabelRCLookup: boolean;
  enableBabelRuntime: boolean | string;
  globalPrefix: string;
  hermesParser: boolean;
  minifierConfig: MinifierConfig;
  optimizationSizeLimit: number;
  publicPath: string;
  allowOptionalDependencies: AllowOptionalDependencies;
  unstable_dependencyMapReservedName?: string;
  unstable_disableModuleWrapping: boolean;
  unstable_disableNormalizePseudoGlobals: boolean;
  unstable_compactOutput: boolean;
  unstable_allowRequireContext: boolean;
  unstable_memoizeInlineRequires?: boolean;
  unstable_nonMemoizedInlineRequires?: ReadonlyArray<string>;
  unstable_renameRequire?: boolean;
}

Cache Invalidation Scenarios

The cache key changes automatically when any of these conditions occur:

File Changes

  • Transform worker source code modifications
  • Babel transformer implementation changes
  • Minifier implementation changes
  • Metro internal module updates
  • Transform plugin updates

Configuration Changes

  • Any transformer configuration option modification
  • Babel transformer configuration changes
  • Minifier configuration adjustments
  • Asset processing settings updates
  • Experimental feature flag changes

Environment Changes

  • Node.js version changes (affects require.resolve paths)
  • Package installation/updates (affects resolved module paths)
  • Metro version updates

Integration with Metro Caching

Metro Transform Worker's cache keys integrate with Metro's broader caching system:

// Metro uses the cache key for:
// 1. Transformation result caching
// 2. Source map caching
// 3. Dependency graph caching
// 4. Asset processing caching

const metroConfig = {
  transformer: {
    getTransformCacheKeyFn: () => getCacheKey(transformerConfig),
    // ... other transformer options
  },
};

Performance Considerations

Cache Key Generation Performance

  • File stat caching: Module resolution results are cached by Node.js
  • Hash computation: Uses fast hashing algorithm (metro-cache stableHash)
  • Incremental updates: Only recomputes when dependencies change

Cache Hit Optimization

  • Deterministic ordering: Configuration objects are serialized consistently
  • Path normalization: Absolute paths are normalized for cross-platform consistency
  • Version pinning: Dependency versions are included in file-based hashing

Debugging Cache Issues

When experiencing unexpected cache behavior:

// Enable Metro cache debugging
process.env.DEBUG = "Metro:Cache";

// Check cache key components
const cacheKey = getCacheKey(config);
const [filesKey, configHash, babelKey] = cacheKey.split("$");

console.log("Files key:", filesKey);
console.log("Config hash:", configHash);
console.log("Babel key:", babelKey);

// Verify configuration serialization
console.log("Config subset:", JSON.stringify(configSubset, null, 2));

docs

cache-management.md

configuration.md

core-transformation.md

error-handling.md

index.md

tile.json