Skip to content

Commit 3cb4ed8

Browse files
committed
Add 'add' option to prefixedBuiltins
1 parent ea20446 commit 3cb4ed8

File tree

1 file changed

+37
-28
lines changed

1 file changed

+37
-28
lines changed

src/index.ts

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import path from 'node:path'
12
import type { Plugin } from 'rollup'
23
import { builtinModules } from 'module'
34
import { findPackagePaths, findDependencies } from './dependencies'
@@ -6,7 +7,7 @@ export interface ExternalsOptions {
67
/** Mark node built-in modules like `path`, `fs`... as external. Defaults to `true`. */
78
builtins?: boolean
89
/** How to treat prefixed builtins. Defaults to `true` (prefixed are considered the same as unprefixed). */
9-
prefixedBuiltins?: boolean | 'strip'
10+
prefixedBuiltins?: boolean | 'strip' | 'add'
1011
/**
1112
* Path/to/your/package.json file (or array of paths).
1213
* Defaults to all package.json files found in parent directories recursively.
@@ -27,7 +28,7 @@ export interface ExternalsOptions {
2728
exclude?: string | RegExp | (string | RegExp)[]
2829
}
2930

30-
type IncludeExclude = Pick<ExternalsOptions, 'include' | 'exclude'>
31+
type IncludeExclude = keyof (ExternalsOptions['include'] | ExternalsOptions['exclude'])
3132

3233
/**
3334
* A Rollup plugin that automatically declares NodeJS built-in modules,
@@ -54,7 +55,7 @@ function externals(options: ExternalsOptions = {}): Plugin {
5455

5556
// Map the include and exclude options to arrays of regexes.
5657
const [ include, exclude ] = [ 'include', 'exclude' ].map(option => new Array<string | RegExp>()
57-
.concat(config[option as keyof IncludeExclude])
58+
.concat(config[option as IncludeExclude])
5859
.map((entry, index) => {
5960
if (entry instanceof RegExp)
6061
return entry
@@ -77,15 +78,27 @@ function externals(options: ExternalsOptions = {}): Plugin {
7778
const externals: RegExp[] = []
7879
const isExternal = (id: string) => externals.some(rx => rx.test(id))
7980

81+
// Support for nodejs: prefix and sub directory.
82+
const nodePrefixRx = /^(?:node(?:js)?:)?/
83+
84+
let builtins: Set<string>
85+
if (config.builtins) {
86+
const filtered = builtinModules.filter(isNotExcluded)
87+
builtins = new Set([
88+
...filtered,
89+
...filtered.map(builtin => builtin.startsWith('node:') ? builtin : 'node:' + builtin)
90+
])
91+
}
92+
else builtins = new Set()
93+
8094
return {
8195
name: 'node-externals',
8296

8397
async buildStart() {
8498

85-
// 1) Filter NodeJS builtins, supporting potential import from a sub directory (e.g. 'fs/promises').
86-
const builtins = (config.builtins ? builtinModules : []).filter(isNotExcluded)
87-
if (builtins.length > 0) {
88-
externals.push(new RegExp(`^(?:${builtins.join('|')})(?:/.+)?$`))
99+
// 1) Add the include option.
100+
if (include.length > 0) {
101+
externals.push(...include)
89102
}
90103

91104
// 2) Find and filter dependencies, supporting potential import from a sub directory (e.g. 'lodash/map').
@@ -102,12 +115,7 @@ function externals(options: ExternalsOptions = {}): Plugin {
102115
})).filter(isNotExcluded)
103116

104117
if (dependencies.length > 0) {
105-
externals.push(new RegExp(`^(?:${dependencies.join('|')})(?:/.+)?$`))
106-
}
107-
108-
// 3) Add the include option.
109-
if (include.length > 0) {
110-
externals.push(...include)
118+
externals.push(new RegExp('^(?:' + dependencies.join('|') + ')(?:/.+)?$'))
111119
}
112120

113121
// All done. Issue the warnings we may have collected.
@@ -117,28 +125,29 @@ function externals(options: ExternalsOptions = {}): Plugin {
117125
}
118126
},
119127

120-
resolveId(importee, importer, { isEntry }) {
128+
resolveId(importee) {
121129

122-
// Ignore entry chunks & don't mess with other plugins.
123-
if (isEntry || !importee.charCodeAt(0) || !importer?.charCodeAt(0)) {
130+
// Ignore already resolved ids and relative imports.
131+
if (path.isAbsolute(importee) || importee.startsWith('.') || importee.charCodeAt(0) === 0) {
124132
return null
125133
}
126134

127-
// Remove node:/nodejs: prefix so builtins resolve to their unprefixed equivalent.
128-
let stripped = importee
129-
if (config.prefixedBuiltins) {
130-
if (importee.startsWith('node:')) {
131-
stripped = importee.slice(5)
132-
}
133-
else if (importee.startsWith('nodejs:')) {
134-
stripped = importee.slice(7)
135+
// Handle builtins.
136+
if (builtins.has(importee)) {
137+
if (config.prefixedBuiltins) {
138+
let stripped = importee.replace(nodePrefixRx, '')
139+
if (config.prefixedBuiltins === 'strip')
140+
importee = stripped
141+
else if (config.prefixedBuiltins === 'add')
142+
importee = 'node:' + stripped
135143
}
144+
145+
return { id: importee, external: true }
136146
}
137147

138-
// Return object if importee should be treated as an external module,
139-
// otherwise return `null` to let Rollup and other plugins handle it.
140-
return isExternal(stripped) && isNotExcluded(stripped)
141-
? { id: config.prefixedBuiltins === 'strip' ? stripped : importee, external: true }
148+
// Handle dependencies.
149+
return isExternal(importee) && isNotExcluded(importee)
150+
? false
142151
: null
143152
}
144153
}

0 commit comments

Comments
 (0)