A Rollup plugin that automatically declares NodeJS built-in modules as external. Also handles npm dependencies, devDependencies, peerDependencies and optionalDependencies.
Works in npm/yarn/pnpm/lerna monorepos too!
(click to expand)
By default, Rollup doesn't know a thing about NodeJS, so trying to bundle simple things like import path from 'node:path' in your code generates an Unresolved dependencies warning.
The solution here is quite simple: you must tell Rollup that the node:path module is in fact external. This way, Rollup won't try to bundle it in and rather leave the import statement as is (or translate it to a require() call if bundling for CommonJS).
However, this must be done for each and every NodeJS built-in you happen to use in your program: node:path, node:os, node:fs, node:url, etc., which can quicky become cumbersome when done manually.
So the primary goal of this plugin is simply to automatically declare all NodeJS built-in modules as external.
As an added bonus, this plugin will also allow you to declare your dependencies (as per your local or monorepo package.json file(s)) as external.
Use your favorite package manager. Mine is npm.
npm install --save-dev rollup-plugin-node-externalsYou generally want to have your runtime dependencies listed under dependencies in package.json, and your development dependencies listed under devDependencies.
If you follow this simple rule, then the defaults are just what you need:
export default {
...
plugins: [
externals(),
]
}This will bundle your devDependencies in while leaving your dependencies, peerDependencies and optionalDependencies external.
All options are, well, optional.
import externals from 'rollup-plugin-node-externals'
export default {
...
plugins: [
externals({
// Make node builtins external. Default: true.
builtins?: boolean
// node: prefix handing for importing Node builtins. Default: 'add'.
builtinsPrefix?: 'add' | 'strip' | 'ignore'
// The path(s) to your package.json. See below for default.
packagePath?: string | string[]
// Make pkg.dependencies external. Default: true.
deps?: boolean
// Make pkg.devDependencies external. Default: false.
devDeps?: boolean
// Make pkg.peerDependencies external. Default: true.
peerDeps?: boolean
// Make pkg.optionalDependencies external. Default: true.
optDeps?: boolean
// Modules to force include in externals. Default: [].
include?: string | RegExp | (string | RegExp)[]
// Modules to force exclude from externals. Default: [].
exclude?: string | RegExp | (string | RegExp)[]
})
]
}Set the builtins option to false if you'd like to use some shims/polyfills for those. You'll most certainly need an other plugin for this.
How to handle the node: scheme used in recent versions of Node (i.e., import path from 'node:path').
- If
add(the default), thenode:prefix is always added. In effect, this homogenizes all your imports of node builtins to their prefixed version. - If
strip(the default), the import is always resolved unprefixed. In effect, this homogenizes all your imports of node builtins to their unprefixed version. ignorewill simply leave all prefixes as written in your code.
Note that prefix handling is independant of the
builtinsoptions being enabled or disabled.
If you're working with monorepos, the packagePath option is made for you. It can take a path, or an array of paths, to your package.json file(s). If not specified, the default is to start with the current directory's package.json then go up scan for all package.json files in parent directories recursively until either the root git directory is reached or until no other package.json can be found.
Set the deps, devDeps, peerDeps and optDeps options to false to prevent the corresponding dependencies from being externalized, therefore letting Rollup bundle them with your code.
Use the include option to force certain dependencies into the list of externals, regardless of other settings:
externals({
deps: false, // Deps will be bundled in
include: /^fsevents/ // Except for fsevents
})Conversely, use the exclude option to remove certain dependencies from the list of externals, regardless of other settings:
externals({
deps: true, // Deps are external
exclude: 'electron-reload' // Yet we want `electron-reload` bundled in
})- Falsy values in
includeandexcludeare silently ignored. This allows for conditional constructs likeexclude: process.env.NODE_ENV === 'production' && 'my-prod-only-dep'. - Subpath imports are supported with regexes, meaning that
include: /^lodash/will externalizelodashand alsolodash/map,lodash/merge, etc.
It uses an exact match against your imports as written in your code, so if your are using some kind of path substitution, eg.:
// In your code, say '@/' is mapped to some directory:
import something from '@/mylib'and you don't want mylib bundled in, then write:
// In rollup.config.js:
externals({
include: '@/mylib'
})If you're also using @rollup/plugin-node-resolve, make sure this plugin comes before it in the plugins array:
import externals from 'rollup-plugin-node-externals'
import resolve from '@rollup/plugin-node-resolve'
export default {
...
plugins: [
externals(),
resolve(),
]
}As a general rule of thumb, you might want to always make this plugin the first one in the plugins array.
Rollup's own external configuration option always takes precedence over this plugin. This is intentional.
- This package is now esm-only and requires NodeJS v16+.
If you need CommonJS or older NodeJS support, please stick to v5. - This plugin now has a peer-dependency on Rollup ^3.0.0.
If you need Rollup 2 support, please stick to v5.
Previous versions -- click to expand
- In previous versions, the
devDepsoption defaulted totrue.
This was practical, but often wrong: devDependencies are meant just for that: being used when developping. Therefore, thedevDepsoption now defaults tofalse, meaning Rollup will include them in your bundle. - As anticipated since v4, the
builtinsPrefixoption now defaults to'add'. - The deprecated
prefixedBuiltinsoption has been removed. UsebuiltinsPrefixinstead. rollup-plugin-node-externalsno longer depends on the Find-Up package (while this is not a breaking change per se, it can be in some edge situations).- The plugin now has a peer dependency on
rollup ^2.60.0 || ^3.0.0.
- In previous versions, the
depsoption defaulted tofalse.
This was practical, but often wrong: when bundling for distribution, you want your own dependencies to be installed by the package manager alongside your package, so they should not be bundled in the code. Therefore, thedepsoption now defaults totrue. - Now requires Node 14 (up from Node 12 for previous versions).
- Now has a peer dependency on
rollup ^2.60.0.
MIT