Skip to content

Commit ef15240

Browse files
committed
feat: multiple package paths and automatic find
1 parent 92f36ed commit ef15240

File tree

2 files changed

+49
-44
lines changed

2 files changed

+49
-44
lines changed

src/dependencies.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { dirname, relative, isAbsolute } from 'path'
2-
import { readFileSync } from 'fs'
3-
import { sync as findUp } from 'find-up'
2+
import { promises as fs } from 'fs'
3+
import findUp from 'find-up'
44

55
/**
66
* Determines if the `child` path is under the `parent` path.
@@ -15,9 +15,9 @@ function isInDirectory(parent: string, child: string): boolean {
1515
* current working directory. If the current working directory is in a git repository, then package.json
1616
* files outside of the git repository will not be yielded.
1717
*/
18-
export function* findPackagePaths(): Generator<string> {
18+
export async function* findPackagePaths(): AsyncGenerator<string> {
1919
// Find git root if in git repository
20-
const gitDirectoryPath: string | undefined = findUp('.git', { type: 'directory' })
20+
const gitDirectoryPath: string | undefined = await findUp('.git', { type: 'directory' })
2121
const gitRootPath: string | undefined = gitDirectoryPath === undefined
2222
? undefined
2323
: dirname(gitDirectoryPath)
@@ -26,30 +26,30 @@ export function* findPackagePaths(): Generator<string> {
2626
return gitRootPath === undefined || isInDirectory(gitRootPath, path)
2727
}
2828

29-
let cwd = process.cwd()
30-
let packagePath
29+
let cwd: string = process.cwd()
30+
let packagePath: string | undefined
3131

3232
while (
33-
(packagePath = findUp('package.json', { type: 'file', cwd })) &&
33+
(packagePath = await findUp('package.json', { type: 'file', cwd })) &&
3434
isInGitDirectory(packagePath)
3535
) {
3636
yield packagePath
37-
cwd = dirname(packagePath)
37+
cwd = dirname(dirname(packagePath))
3838
}
3939
}
4040

41-
export function findDependencies(
41+
export async function findDependencies(
4242
{ packagePaths, keys, warnings }: {
43-
packagePaths: Iterable<string>,
43+
packagePaths: AsyncIterable<string> | Iterable<string>,
4444
keys: string[],
4545
warnings: string[]
4646
}
47-
): string[] {
47+
): Promise<string[]> {
4848
const dependencies: Set<string> = new Set()
4949

50-
for (const packagePath of packagePaths) {
50+
for await (const packagePath of packagePaths) {
5151
try {
52-
const pkg: { [key in PropertyKey]: any } = JSON.parse((readFileSync(packagePath)).toString()) ?? {}
52+
const pkg: { [key in PropertyKey]: any } = JSON.parse((await fs.readFile(packagePath)).toString()) ?? {}
5353

5454
for (const key of keys) {
5555
const dependenciesToVersions: { [key in PropertyKey]: any } = pkg[key] ?? {}

src/index.ts

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@
55
* Useful when bundling a NodeJS or an Electron app and you don't want to bundle
66
* node/npm modules with your own code but rather require() them at runtime.
77
*/
8-
import { resolve } from 'path'
98
import { Plugin } from 'rollup'
109
import builtinModules from 'builtin-modules'
10+
import { findPackagePaths, findDependencies } from './dependencies'
1111

1212
export interface ExternalsOptions {
13-
/** Path/to/your/package.json file. Defaults to the one in `process.cwd()`. */
14-
packagePath?: string
13+
/**
14+
* Path/to/your/package.json file (or array of paths).
15+
* Defaults to all package.json files found in parent directories recursively.
16+
* Won't got outside of a git repository.
17+
*/
18+
packagePath?: string | string[]
1519
/** Mark node built-in modules like `path`, `fs`... as external. Defaults to `true`. */
1620
builtins?: boolean
1721
/** Mark dependencies as external. Defaults to `false`. */
@@ -41,7 +45,7 @@ export default function externals(options: ExternalsOptions = {}): Plugin {
4145

4246
// Consolidate options
4347
const opts: Required<ExternalsOptions> = {
44-
packagePath: resolve(process.cwd(), 'package.json'),
48+
packagePath: [],
4549
builtins: true,
4650
deps: false,
4751
devDeps: true,
@@ -83,33 +87,11 @@ export default function externals(options: ExternalsOptions = {}): Plugin {
8387
// Filter NodeJS builtins
8488
const builtins = (opts.builtins ? builtinModules : []).filter(f)
8589

86-
// Filter deps from package.json
87-
let pkg
88-
try {
89-
pkg = require(opts.packagePath)
90-
}
91-
catch {
92-
warnings.push("couldn't read package.json, please make sure it exists in the same directory as rollup.config.js or use the 'packagePath' option.")
93-
pkg = Object.create(null)
94-
}
95-
const dependencies: string[] = [
96-
...(opts.deps ? Object.keys(pkg.dependencies || {}) : []),
97-
...(opts.devDeps ? Object.keys(pkg.devDependencies || {}) : []),
98-
...(opts.peerDeps ? Object.keys(pkg.peerDependencies || {}) : []),
99-
...(opts.optDeps ? Object.keys(pkg.optionalDependencies || {}) : [])
100-
].filter(f)
101-
102-
// Build the final regexes, include potential import from a sub directory (e.g. 'lodash/map')
90+
// Normalize package paths
91+
let packagePaths: string[] = ([] as string[]).concat(opts.packagePath)
92+
93+
// Array of the final regexes, include potential import from a sub directory (e.g. 'lodash/map')
10394
const externals: RegExp[] = []
104-
if (builtins.length > 0) {
105-
externals.push(new RegExp('^(?:' + builtins.join('|') + ')(\/.+)?$'))
106-
}
107-
if (dependencies.length > 0) {
108-
externals.push(new RegExp('^(?:' + dependencies.join('|') + ')(\/.+)?$'))
109-
}
110-
if (include.length > 0) {
111-
externals.push(...include)
112-
}
11395

11496
return {
11597
name: 'node-externals',
@@ -120,11 +102,34 @@ export default function externals(options: ExternalsOptions = {}): Plugin {
120102
return importer && !/\0/.test(source) && externals.some(deps => deps.test(source)) ? false : null
121103
},
122104

123-
buildStart() {
105+
async buildStart() {
124106
let msg: string | undefined
125107
while (msg = warnings.shift()) {
126108
this.warn(msg)
127109
}
110+
111+
// Find and filter dependencies
112+
const dependencies = (await findDependencies({
113+
packagePaths: packagePaths.length > 0 ? packagePaths : findPackagePaths(),
114+
keys: [
115+
opts.deps && 'dependencies',
116+
opts.devDeps && 'devDependencies',
117+
opts.peerDeps && 'peerDependencies',
118+
opts.optDeps && 'optionalDependencies'
119+
].filter(Boolean) as string[],
120+
warnings
121+
})).filter(f)
122+
123+
// Build regexes
124+
if (builtins.length > 0) {
125+
externals.push(new RegExp('^(?:' + builtins.join('|') + ')(\/.+)?$'))
126+
}
127+
if (dependencies.length > 0) {
128+
externals.push(new RegExp('^(?:' + dependencies.join('|') + ')(\/.+)?$'))
129+
}
130+
if (include.length > 0) {
131+
externals.push(...include)
132+
}
128133
}
129134
}
130135
}

0 commit comments

Comments
 (0)