CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-metro-transform-plugins

Transform plugins for Metro bundler that provide code optimization and platform-specific transformations for React Native applications

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

require-optimization.mddocs/

Require Optimization

Inlines top-level require() calls to enable lazy loading and reduce bundle overhead by replacing variable assignments with direct require() calls at usage sites.

Capabilities

Inline Requires Plugin

Transforms top-level require() assignments into inline require() calls for improved lazy loading and bundle performance.

/**
 * Creates a Babel plugin that inlines require() calls
 * @returns Babel plugin object that processes require() assignments
 */
function inlineRequiresPlugin(): PluginObj<State>;

interface InlineRequiresPluginOptions {
  /** Array of require calls to ignore (e.g., ['fs', 'path']) */
  ignoredRequires?: ReadonlyArray<string>;
  /** Function names that can be inlined (default: ['require']) */
  inlineableCalls?: ReadonlyArray<string>;
  /** Modules that should not be memoized even when memoizeCalls is true */
  nonMemoizedModules?: ReadonlyArray<string>;
  /** Whether to memoize repeated require() calls (default: false) */
  memoizeCalls?: boolean;
}

interface State {
  opts?: InlineRequiresPluginOptions;
  ignoredRequires: Set<string>;
  inlineableCalls: Set<string>;
  membersAssigned: Map<string, Set<string>>;
}

Usage Examples:

const babel = require("@babel/core");
const { inlineRequiresPlugin } = require("metro-transform-plugins");

const code = `
var fs = require('fs');
var path = require('path');
var lodash = require('lodash');

function readConfig() {
  return fs.readFileSync('./config.json', 'utf8');
}

function processPath(inputPath) {
  return path.join(inputPath, 'processed');
}

console.log(lodash.map([1, 2, 3], x => x * 2));
`;

const transformed = babel.transformSync(code, {
  plugins: [
    [inlineRequiresPlugin, {
      ignoredRequires: ['fs'], // Don't inline fs module
      memoizeCalls: true
    }]
  ]
});

// Result:
// var fs = require('fs'); // Not inlined (in ignoredRequires)
// var _path;
// var _lodash;
//
// function readConfig() {
//   return fs.readFileSync('./config.json', 'utf8');
// }
//
// function processPath(inputPath) {
//   return (_path || (_path = require('path'))).join(inputPath, 'processed');
// }
//
// console.log((_lodash || (_lodash = require('lodash'))).map([1, 2, 3], x => x * 2));

Simple Variable Inlining

Handles basic require() variable assignments:

/**
 * Simple require assignment inlining
 * var module = require('module-name');
 * module.method() → require('module-name').method()
 */

// Before transformation
var React = require('react');
var Component = React.Component;
function render() {
  return React.createElement('div');
}

// After transformation  
var Component = require('react').Component;
function render() {
  return require('react').createElement('div');
}

Member Expression Inlining

Inlines require() calls with property access:

/**
 * Member expression require inlining
 * var member = require('module').property;
 * member.method() → require('module').property.method()
 */

// Before transformation
var createElement = require('react').createElement;
var Fragment = require('react').Fragment;

function component() {
  return createElement(Fragment, null, 'Hello');
}

// After transformation
function component() {
  return require('react').createElement(require('react').Fragment, null, 'Hello');
}

Destructuring Assignment Inlining

Handles ES6 destructuring patterns:

/**
 * Destructuring assignment inlining
 * const {method} = require('module');
 * method() → require('module').method()
 */

// Before transformation  
const { useState, useEffect } = require('react');
const { join, resolve } = require('path');

function component() {
  const [state, setState] = useState(0);
  const configPath = join(__dirname, 'config.json');
  return state;
}

// After transformation
function component() {
  const [state, setState] = require('react').useState(0);
  const configPath = require('path').join(__dirname, 'config.json');
  return state;
}

Memoized Require Calls

Optional memoization to avoid repeated module loading:

/**
 * Memoized require pattern (when memoizeCalls: true)
 * Creates memoization variables for frequently used modules
 */

// Before transformation (with memoizeCalls: true)
var utils = require('./utils');
function a() { return utils.helper1(); }
function b() { return utils.helper2(); }
function c() { return utils.helper3(); }

// After transformation
var _utils;
function a() { return (_utils || (_utils = require('./utils'))).helper1(); }
function b() { return (_utils || (_utils = require('./utils'))).helper2(); }
function c() { return (_utils || (_utils = require('./utils'))).helper3(); }

Require.resolve Support

Handles require.resolve() patterns for module resolution:

/**
 * require.resolve() call inlining
 * var module = require(require.resolve('module-name'));
 */

// Before transformation
var config = require(require.resolve('./config'));
config.setting = 'value';

// After transformation  
require(require.resolve('./config')).setting = 'value';

Safety Checks and Exclusions

Implements safety mechanisms to prevent breaking transformations:

/**
 * Safety exclusions prevent incorrect inlining
 */

// Excluded: Modules with member assignments
var utils = require('./utils');
utils.cache = {}; // Member assignment detected - won't inline utils

// Excluded: Non-constant violations
var fs = require('fs'); 
fs = mockFs; // Reassignment - won't inline fs

// Excluded: Babel runtime modules (automatically)
var helper = require('@babel/runtime/helpers/something'); // Never inlined

// Excluded: Modules in ignoredRequires option
var path = require('path'); // Won't inline if 'path' in ignoredRequires

Block-Level Optimization

Optimizes memoization based on code block structure:

/**
 * Block-level memoization optimization
 * Uses different patterns based on code structure
 */

// Within same block - uses memoization variable
function sameBlock() {
  const a = (_utils || (_utils = require('./utils'))).methodA();
  const b = _utils.methodB(); // Reuses memoized variable
}

// Across different blocks - uses full memoization expression  
function differentBlocks() {
  if (condition) {
    return (_utils || (_utils = require('./utils'))).methodA();
  } else {
    return (_utils || (_utils = require('./utils'))).methodB();
  }
}

Source Location Preservation

Maintains original source locations for debugging and error reporting:

/**
 * Source location tracking
 * Preserves original require() call location information
 */

// Adds METRO_INLINE_REQUIRES_INIT_LOC metadata to inlined expressions
// This helps with:
// - Source map accuracy
// - Error stack trace precision  
// - Debugging experience

Custom Inlineable Calls

Supports custom function names beyond 'require':

/**
 * Custom inlineable function support
 * @param inlineableCalls - Array of function names to inline
 */

// Configuration: inlineableCalls: ['require', 'load', 'import']
var module1 = require('module1');    // Inlined
var module2 = load('module2');       // Inlined  
var module3 = import('module3');     // Inlined
var module4 = customLoader('module4'); // Not inlined

Non-Memoized Modules

Prevents memoization for specific modules that should always be fresh:

/**
 * Non-memoized module handling
 * @param nonMemoizedModules - Modules to never memoize
 */

// Configuration: nonMemoizedModules: ['./config', 'dotenv']
var config = require('./config');     // Always fresh, never memoized
var dotenv = require('dotenv');       // Always fresh, never memoized
var utils = require('./utils');       // Can be memoized (if memoizeCalls: true)

Error Recovery

Graceful handling of transformation failures:

/**
 * Error recovery mechanism
 * If replacement fails, keeps original require() assignment
 */

// If inlining fails (e.g., due to complex AST structure):
// - Logs the error internally
// - Preserves original require() assignment
// - Continues processing other requires
// - Prevents build failures from transformation issues

docs

code-generation.md

code-optimization.md

index.md

module-system.md

platform-inlining.md

require-optimization.md

tile.json