Automatically declare NodeJS built-in modules and npm dependencies as 'external' in Rollup/Vite config
npx @tessl/cli install tessl/npm-rollup-plugin-node-externals@8.1.0A Rollup/Vite plugin that automatically declares NodeJS built-in modules as external, preventing bundlers from trying to include them in the output bundle. Also handles npm dependencies by automatically marking dependencies, peerDependencies, and optionalDependencies as external while allowing devDependencies to be bundled.
npm install --save-dev rollup-plugin-node-externalsimport nodeExternals from "rollup-plugin-node-externals";Named export:
import { nodeExternals } from "rollup-plugin-node-externals";Type imports:
import type { ExternalsOptions } from "rollup-plugin-node-externals";// rollup.config.js
import nodeExternals from "rollup-plugin-node-externals";
export default {
input: "src/index.js",
output: {
file: "dist/bundle.js",
format: "cjs"
},
plugins: [
nodeExternals() // Uses default settings
]
};For Vite:
// vite.config.js
import { defineConfig } from "vite";
import nodeExternals from "rollup-plugin-node-externals";
export default defineConfig({
plugins: [
nodeExternals()
]
});The plugin operates during Rollup's module resolution phase:
Creates a Rollup/Vite plugin instance with the specified configuration options.
/**
* A Rollup/Vite plugin that automatically declares NodeJS built-in modules,
* and optionally npm dependencies, as 'external'.
*/
function nodeExternals(options?: ExternalsOptions): Plugin;
interface ExternalsOptions {
/**
* Mark node built-in modules like `path`, `fs`... as external.
* Defaults to `true`.
*/
builtins?: boolean;
/**
* node: prefix handing for importing Node builtins:
* - `'add'` turns `'path'` to `'node:path'`
* - `'strip'` turns `'node:path'` to `'path'`
* - `'ignore'` leaves Node builtin names as-is
* Defaults to `add`.
*/
builtinsPrefix?: 'add' | 'strip' | 'ignore';
/**
* Path/to/your/package.json file (or array of paths).
* Defaults to all package.json files found in parent directories recursively.
* Won't go outside of a git repository.
*/
packagePath?: string | string[];
/**
* Mark dependencies as external.
* Defaults to `true`.
*/
deps?: boolean;
/**
* Mark devDependencies as external.
* Defaults to `false`.
*/
devDeps?: boolean;
/**
* Mark peerDependencies as external.
* Defaults to `true`.
*/
peerDeps?: boolean;
/**
* Mark optionalDependencies as external.
* Defaults to `true`.
*/
optDeps?: boolean;
/**
* Force include these deps in the list of externals, regardless of other settings.
* Defaults to `[]` (force include nothing).
*/
include?: MaybeArray<MaybeFalsy<string | RegExp>>;
/**
* Force exclude these deps from the list of externals, regardless of other settings.
* Defaults to `[]` (force exclude nothing).
*/
exclude?: MaybeArray<MaybeFalsy<string | RegExp>>;
}Configuration Examples:
// Include specific modules as external
nodeExternals({
deps: false, // Don't externalize dependencies
include: 'fsevents' // But force fsevents to be external
});
// Exclude specific modules from being external
nodeExternals({
deps: true, // Externalize dependencies
exclude: 'electron-reload' // But bundle electron-reload
});
// Complex filtering with regex
nodeExternals({
include: [/^lodash/, 'chalk'], // Externalize lodash/* and chalk
exclude: /test-/ // Bundle anything starting with 'test-'
});
// Custom package.json paths for monorepos
nodeExternals({
packagePath: [
'./package.json',
'./packages/core/package.json'
]
});
// Node.js built-in prefix handling
nodeExternals({
builtinsPrefix: 'strip' // 'node:path' becomes 'path'
});The plugin automatically detects and manages Node.js built-in modules (like fs, path, os) with configurable prefix handling.
/**
* Built-in module prefix handling options
*/
type BuiltinsPrefix = 'add' | 'strip' | 'ignore';'add' (default): Ensures node: prefix is always present ('path' → 'node:path')'strip': Removes node: prefix when possible ('node:path' → 'path')'ignore': Leaves imports exactly as written in source codeThe plugin scans package.json files to determine which modules should be treated as external based on dependency type configuration.
/**
* Dependency type configuration options
*/
interface DependencyOptions {
deps?: boolean; // Runtime dependencies (default: true)
devDeps?: boolean; // Development dependencies (default: false)
peerDeps?: boolean; // Peer dependencies (default: true)
optDeps?: boolean; // Optional dependencies (default: true)
}Fine-grained control over which modules are treated as external using string or regex patterns.
/**
* Module filtering configuration
*/
interface FilterOptions {
include?: MaybeArray<MaybeFalsy<string | RegExp>>;
exclude?: MaybeArray<MaybeFalsy<string | RegExp>>;
}Pattern Matching:
lodash matches lodash/map)The plugin automatically discovers package.json files for dependency scanning, with support for monorepos and custom paths.
/**
* Package path configuration for dependency scanning
*/
interface PackagePathOptions {
packagePath?: string | string[];
}Default behavior (when packagePath is not specified):
Workspace root detection looks for:
pnpm-workspace.yaml (pnpm)lerna.json (Lerna)rush.json (Rush)/**
* Utility type for nullable/falsy values
*/
type MaybeFalsy<T> = T | undefined | null | false;
/**
* Utility type for single value or array
*/
type MaybeArray<T> = T | T[];
/**
* Vite-compatible plugin interface extending Rollup's Plugin
*/
interface ViteCompatiblePlugin extends Plugin {
apply?: 'build' | 'serve';
enforce?: 'pre' | 'post';
}
/**
* Package.json structure used for dependency scanning
*/
interface PackageJson {
name: string;
version: string;
workspaces?: string[];
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
peerDependencies?: Record<string, string>;
optionalDependencies?: Record<string, string>;
}This plugin should be placed first in the plugins array to ensure proper module resolution:
export default {
plugins: [
nodeExternals(), // First
nodeResolve(), // After
// other plugins...
]
};The plugin automatically handles monorepos by:
The plugin includes Vite-specific properties:
apply: 'build' - Only runs during build phaseenforce: 'pre' - Runs early in the resolution processThe plugin provides clear error messages for: