npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ricsam/isolate-module-loader

v0.1.8

Published

Utilities for isolated-vm - run JavaScript in a sandboxed V8 environment with web-standard APIs

Downloads

1,045

Readme

@ricsam/isolate-module-loader

A batteries-included module loader for @ricsam/isolate-runtime and @ricsam/isolate-client. Maps host filesystem paths to virtual isolate paths, bundles npm packages with Rollup, resolves TypeScript files, and probes extensions automatically.

Installation

npm add @ricsam/isolate-module-loader

Usage

import { createRuntime } from "@ricsam/isolate-runtime";
import { defaultModuleLoader } from "@ricsam/isolate-module-loader";

const loader = defaultModuleLoader(
  // Map host directories to virtual paths in the isolate
  { from: "/home/user/project/src/**/*", to: "/app" },
  { from: "/home/user/project/node_modules", to: "/node_modules" },
);

const runtime = await createRuntime({
  moduleLoader: loader,
  console: {
    onEntry: (entry) => {
      if (entry.type === "output") console.log(entry.stdout);
    },
  },
});

// Imports resolve through the loader automatically
await runtime.eval(
  `
  import { helper } from "./utils";   // reads /home/user/project/src/utils.ts
  import ms from "ms";                // bundles ms from node_modules via Rollup
  console.log(helper(), ms("1 day"));
  `,
  "/app/entry.ts",
);

Path Mappings

Each mapping is a { from, to } pair that maps a host path to a virtual path inside the isolate:

defaultModuleLoader(
  // Glob: maps an entire directory tree
  { from: "/host/project/src/**/*", to: "/app" },

  // Direct file: maps a single file
  { from: "/host/project/config.ts", to: "/app/config.ts" },

  // Node modules: enables bare specifier resolution (npm packages)
  { from: "/host/project/node_modules", to: "/node_modules" },
);

Glob mappings (contain *) act as prefix mappings — any virtual path under the to prefix resolves to the corresponding host path under the from base directory.

Direct mappings (no *) are 1:1 file mappings.

Node modules mapping — when a mapping's host base ends with node_modules, bare specifiers like "lodash" or "@aws-sdk/client-s3" are bundled with Rollup using browser conditions, CommonJS conversion, and JSON support. Each package subpath is bundled independently and cached.

Module Aliases

Map a host file to a bare-specifier import. If a mapping's to doesn't start with /, it's treated as a module alias:

defaultModuleLoader(
  // Module alias: import { thing } from "@/custom-module" resolves to the host file
  { from: "/host/project/custom_entry.ts", to: "@/custom-module" },

  // Regular filesystem mapping
  { from: "/host/project/src/**/*", to: "/app" },

  // npm packages
  { from: "/host/project/node_modules", to: "/node_modules" },
);

When an import matches a module alias, the host file is bundled with Rollup — relative imports within it are inlined, while npm package imports are left as external import statements (resolved by subsequent loader calls). TypeScript files are automatically processed.

Module aliases cannot use glob patterns in from — each alias maps a single host file entry point.

Features

TypeScript Support

TypeScript files (.ts, .tsx, .mts, .cts) are automatically processed:

  • Types are stripped using Node.js's native stripTypeScriptTypes
  • Unused imports (type-only) are elided
  • Type-only exports get placeholder values so other modules can import them
  • The filename extension is rewritten to .js for V8

Extension Probing

When a specifier has no extension, the loader probes in order: .tsx, .jsx, .ts, .mjs, .js, .cjs, .json. It also tries index.* when the path resolves to a directory.

Browser Variants

For each probe, browser variants are tried first (e.g., utils.browser.ts before utils.ts, index.browser.js before index.js).

npm Package Bundling

Bare specifiers are bundled with Rollup using:

  • @rollup/plugin-node-resolve with browser conditions
  • @rollup/plugin-commonjs for CJS-to-ESM conversion
  • @rollup/plugin-json for JSON imports
  • @rollup/plugin-replace for process.env.NODE_ENV

Dependencies of the target package are left as external imports (resolved by subsequent loader calls). Bare specifiers are resolved using Node's importer-based algorithm, and importer symlinks are followed by default (Node-style realpath behavior), which keeps transitive resolution working in symlinked layouts such as Bun workspaces.

Bundle results are cached by specifier + resolution context.

Static vs Dynamic Modules

npm package bundles are returned with static: true, meaning the isolate caches the compiled module and won't re-request it. User files are non-static by default, allowing hot reload between evaluations.

API

defaultModuleLoader(...paths): ModuleLoaderCallback

Creates a module loader callback compatible with createRuntime({ moduleLoader }).

function defaultModuleLoader(...paths: MappingConfig[]): ModuleLoaderCallback;

interface MappingConfig {
  from: string; // Host filesystem path (supports globs)
  to: string;   // Virtual path in the isolate
}

Utility Exports

// Path mapping utilities
parseMappings(configs: MappingConfig[]): PathMapping[];
virtualToHost(virtualPath: string, mappings: PathMapping[]): string | null;
findNodeModulesMapping(mappings: PathMapping[]): PathMapping | undefined;
findModuleAlias(specifier: string, mappings: PathMapping[]): PathMapping | undefined;

// File resolution
resolveFilePath(basePath: string): string | null;
detectFormat(filePath: string, code: string): "cjs" | "esm" | "json";
parseSpecifier(specifier: string): { packageName: string; subpath: string };
isBareSpecifier(specifier: string): boolean;

// Bundling
bundleSpecifier(specifier: string, rootDir: string): Promise<{ code: string }>;
bundleHostFile(hostFilePath: string): Promise<{ code: string }>;
clearBundleCache(): void;

// TypeScript processing
isTypeScriptFile(filePath: string): boolean;
processTypeScript(code: string, filename: string): string;