Skip to content

Commit a958739

Browse files
committed
Greatly simplify (and reduce code size) of the buildStart hook
1 parent f5c40e5 commit a958739

File tree

2 files changed

+43
-52
lines changed

2 files changed

+43
-52
lines changed

source/index.ts

Lines changed: 41 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,9 @@ const defaults: Config = {
120120
exclude: []
121121
}
122122

123-
const isString = (str: unknown): str is string =>
124-
typeof str === 'string' && str.length > 0
123+
// Helpers.
124+
const isString = (str: unknown): str is string => typeof str === 'string' && str.length > 0
125+
const fileExists = (name: string) => fs.stat(name).then(stat => stat.isFile()).catch(() => false)
125126

126127
/**
127128
* A Rollup/Vite plugin that automatically declares NodeJS built-in modules,
@@ -131,21 +132,20 @@ function nodeExternals(options: ExternalsOptions = {}): Plugin {
131132

132133
const config: Config = { ...defaults, ...options }
133134

134-
let include: RegExp[] = [], // Initialized to empty arrays as a workaround
135-
exclude: RegExp[] = [] // to https://github.com/Septh/rollup-plugin-node-externals/issues/30
135+
let include: RegExp[] = [], // Initialized to empty arrays
136+
exclude: RegExp[] = [] // as a workaround to issue #30
136137

137138
const isIncluded = (id: string) => include.length > 0 && include.some(rx => rx.test(id)),
138139
isExcluded = (id: string) => exclude.length > 0 && exclude.some(rx => rx.test(id))
139140

140141
// Determine the root of the git repository, if any.
141142
//
142-
// Note: it looks like Vite doesn't support async plugin factories
143-
// (see https://github.com/Septh/rollup-plugin-node-externals/issues/37
144-
// and https://github.com/vitejs/vite/issues/20717), so we don't await
145-
// the result here but rather inside the buildStart hook.
146-
const gitTopLevel = new Promise<string | null>(resolve => {
143+
// Note: we can't await the promise here because this would require our factory function
144+
// to be async and that would break the old Vite compatibility trick
145+
// (see issue #37 and https://github.com/vitejs/vite/issues/20717).
146+
const gitTopLevel = new Promise<string>(resolve => {
147147
cp.execFile('git', [ 'rev-parse', '--show-toplevel' ], (error, stdout) => {
148-
return resolve(error ? null : path.normalize(stdout.trim()))
148+
resolve(error ? '' : path.normalize(stdout.trim()))
149149
})
150150
})
151151

@@ -178,65 +178,56 @@ function nodeExternals(options: ExternalsOptions = {}): Plugin {
178178
.concat(config.packagePath)
179179
.filter(isString)
180180
.map(packagePath => path.resolve(packagePath))
181-
182181
if (packagePaths.length === 0) {
183-
search:
184182
for (let current = process.cwd(), previous = ''; previous !== current; previous = current, current = path.dirname(current)) {
185183

186184
// Gather package.json files.
187-
let name = path.join(current, 'package.json')
188-
if (await fs.stat(name).then(stat => stat.isFile()).catch(() => false))
185+
const name = path.join(current, 'package.json')
186+
if (await fileExists(name))
189187
packagePaths.push(name)
190188

191-
// Break early if we are at the root of a git repo.
192-
if (current === await gitTopLevel)
193-
break
189+
// Break early if we are at the root of the git repo
190+
// or there is a known workspace root file.
191+
const breaks = await Promise.all([
192+
gitTopLevel.then(topLevel => topLevel === current),
193+
...workspaceRootFiles.map(name => fileExists(path.join(current, name)))
194+
])
194195

195-
// Break early is there is a known workspace root file.
196-
for (name of workspaceRootFiles) {
197-
if (await fs.stat(path.join(current, name)).then(stat => stat.isFile()).catch(() => false))
198-
break search
199-
}
196+
if (breaks.some(result => result))
197+
break
200198
}
201199
}
202200

203201
// Gather dependencies names.
204-
const dependencies: Record<string, string> = {}
202+
const externals: Record<string, string> = {}
205203
for (const packagePath of packagePaths) {
206-
const buffer = await fs.readFile(packagePath).catch((err: NodeJS.ErrnoException) => err)
207-
if (buffer instanceof Error) {
208-
return this.error({
209-
message: `Cannot read file ${packagePath}, error: ${buffer.code}.`,
210-
stack: undefined
211-
})
204+
const manifest = await fs.readFile(packagePath)
205+
.then(buffer => JSON.parse(buffer.toString()) as PackageJson)
206+
.catch((err: NodeJS.ErrnoException | SyntaxError) => err)
207+
if (manifest instanceof Error) {
208+
const message = manifest instanceof SyntaxError
209+
? `File ${JSON.stringify(packagePath)} does not look like a valid package.json.`
210+
: `Cannot read ${JSON.stringify(packagePath)}, error: ${manifest.code}.`
211+
return this.error({ message, stack: undefined })
212212
}
213213

214-
try {
215-
const pkg = JSON.parse(buffer.toString()) as PackageJson
216-
Object.assign(dependencies,
217-
config.deps ? pkg.dependencies : undefined,
218-
config.devDeps ? pkg.devDependencies : undefined,
219-
config.peerDeps ? pkg.peerDependencies : undefined,
220-
config.optDeps ? pkg.optionalDependencies : undefined
221-
)
214+
Object.assign(externals,
215+
config.deps ? manifest.dependencies : undefined,
216+
config.devDeps ? manifest.devDependencies : undefined,
217+
config.peerDeps ? manifest.peerDependencies : undefined,
218+
config.optDeps ? manifest.optionalDependencies : undefined
219+
)
222220

223-
// Watch this package.json
224-
this.addWatchFile(packagePath)
221+
// Watch this package.json.
222+
this.addWatchFile(packagePath)
225223

226-
// Break early if this is an npm/yarn workspace root.
227-
if (Array.isArray(pkg.workspaces))
228-
break
229-
}
230-
catch {
231-
this.error({
232-
message: `File ${JSON.stringify(packagePath)} does not look like a valid package.json file.`,
233-
stack: undefined
234-
})
235-
}
224+
// Break early if this is an npm/yarn workspace root.
225+
if (Array.isArray(manifest.workspaces))
226+
break
236227
}
237228

238229
// Add all dependencies as an include RegEx.
239-
const names = Object.keys(dependencies)
230+
const names = Object.keys(externals)
240231
if (names.length > 0)
241232
include.push(new RegExp('^(?:' + names.join('|') + ')(?:/.+)?$'))
242233
},

test/options.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ testProp(
2828
await initPlugin(options)
2929
t.pass()
3030
}
31-
catch(err) {
31+
catch (err) {
3232
const { message } = err as Error
33-
message.startsWith('Cannot read file') ? t.pass() : t.fail(message)
33+
message.startsWith('Cannot read') ? t.pass() : t.fail(message)
3434
}
3535
}
3636
)

0 commit comments

Comments
 (0)