Skip to content

Commit ee3231c

Browse files
authored
fix: support process each out dir when there are two or more (#9748)
1 parent 8ede2f1 commit ee3231c

File tree

2 files changed

+92
-44
lines changed

2 files changed

+92
-44
lines changed

packages/vite/src/node/build.ts

+60-41
Original file line numberDiff line numberDiff line change
@@ -559,28 +559,30 @@ async function doBuild(
559559
libOptions,
560560
config.logger
561561
)
562+
const normalizedOutputs: OutputOptions[] = []
563+
564+
if (Array.isArray(outputs)) {
565+
for (const resolvedOutput of outputs) {
566+
normalizedOutputs.push(buildOutputOptions(resolvedOutput))
567+
}
568+
} else {
569+
normalizedOutputs.push(buildOutputOptions(outputs))
570+
}
571+
572+
const outDirs = normalizedOutputs.map(({ dir }) => resolve(dir!))
562573

563574
// watch file changes with rollup
564575
if (config.build.watch) {
565576
config.logger.info(colors.cyan(`\nwatching for file changes...`))
566577

567-
const output: OutputOptions[] = []
568-
if (Array.isArray(outputs)) {
569-
for (const resolvedOutput of outputs) {
570-
output.push(buildOutputOptions(resolvedOutput))
571-
}
572-
} else {
573-
output.push(buildOutputOptions(outputs))
574-
}
575-
576578
const resolvedChokidarOptions = resolveChokidarOptions(
577579
config.build.watch.chokidar
578580
)
579581

580582
const { watch } = await import('rollup')
581583
const watcher = watch({
582584
...rollupOptions,
583-
output,
585+
output: normalizedOutputs,
584586
watch: {
585587
...config.build.watch,
586588
chokidar: resolvedChokidarOptions
@@ -591,7 +593,7 @@ async function doBuild(
591593
if (event.code === 'BUNDLE_START') {
592594
config.logger.info(colors.cyan(`\nbuild started...`))
593595
if (options.write) {
594-
prepareOutDir(outDir, options.emptyOutDir, config)
596+
prepareOutDir(outDirs, options.emptyOutDir, config)
595597
}
596598
} else if (event.code === 'BUNDLE_END') {
597599
event.result.close()
@@ -610,55 +612,72 @@ async function doBuild(
610612
parallelBuilds.push(bundle)
611613

612614
const generate = (output: OutputOptions = {}) => {
613-
return bundle[options.write ? 'write' : 'generate'](
614-
buildOutputOptions(output)
615-
)
615+
return bundle[options.write ? 'write' : 'generate'](output)
616616
}
617617

618618
if (options.write) {
619-
prepareOutDir(outDir, options.emptyOutDir, config)
619+
prepareOutDir(outDirs, options.emptyOutDir, config)
620620
}
621621

622-
if (Array.isArray(outputs)) {
623-
const res = []
624-
for (const output of outputs) {
625-
res.push(await generate(output))
626-
}
627-
return res
628-
} else {
629-
return await generate(outputs)
622+
const res = []
623+
for (const output of normalizedOutputs) {
624+
res.push(await generate(output))
630625
}
626+
return Array.isArray(outputs) ? res : res[0]
631627
} catch (e) {
632628
outputBuildError(e)
633629
throw e
634630
}
635631
}
636632

637633
function prepareOutDir(
638-
outDir: string,
634+
outDirs: string[],
639635
emptyOutDir: boolean | null,
640636
config: ResolvedConfig
641637
) {
642-
if (fs.existsSync(outDir)) {
643-
if (
644-
emptyOutDir == null &&
645-
!normalizePath(outDir).startsWith(config.root + '/')
646-
) {
647-
// warn if outDir is outside of root
648-
config.logger.warn(
649-
colors.yellow(
650-
`\n${colors.bold(`(!)`)} outDir ${colors.white(
651-
colors.dim(outDir)
652-
)} is not inside project root and will not be emptied.\n` +
653-
`Use --emptyOutDir to override.\n`
638+
const nonDuplicateDirs = new Set(outDirs)
639+
let outside = false
640+
if (emptyOutDir == null) {
641+
for (const outDir of nonDuplicateDirs) {
642+
if (
643+
fs.existsSync(outDir) &&
644+
!normalizePath(outDir).startsWith(config.root + '/')
645+
) {
646+
// warn if outDir is outside of root
647+
config.logger.warn(
648+
colors.yellow(
649+
`\n${colors.bold(`(!)`)} outDir ${colors.white(
650+
colors.dim(outDir)
651+
)} is not inside project root and will not be emptied.\n` +
652+
`Use --emptyOutDir to override.\n`
653+
)
654654
)
655-
)
656-
} else if (emptyOutDir !== false) {
657-
emptyDir(outDir, ['.git'])
655+
outside = true
656+
break
657+
}
658658
}
659659
}
660-
if (config.publicDir && fs.existsSync(config.publicDir)) {
661-
copyDir(config.publicDir, outDir)
660+
for (const outDir of nonDuplicateDirs) {
661+
if (!outside && emptyOutDir !== false && fs.existsSync(outDir)) {
662+
// skip those other outDirs which are nested in current outDir
663+
const skipDirs = outDirs
664+
.map((dir) => {
665+
const relative = path.relative(outDir, dir)
666+
if (
667+
relative &&
668+
!relative.startsWith('..') &&
669+
!path.isAbsolute(relative)
670+
) {
671+
return relative
672+
}
673+
return ''
674+
})
675+
.filter(Boolean)
676+
emptyDir(outDir, [...skipDirs, '.git'])
677+
}
678+
if (config.publicDir && fs.existsSync(config.publicDir)) {
679+
copyDir(config.publicDir, outDir)
680+
}
662681
}
663682
}
664683

packages/vite/src/node/utils.ts

+32-3
Original file line numberDiff line numberDiff line change
@@ -549,16 +549,45 @@ export function isFileReadable(filename: string): boolean {
549549
}
550550
}
551551

552+
const splitFirstDirRE = /(.+?)[\\/](.+)/
553+
552554
/**
553555
* Delete every file and subdirectory. **The given directory must exist.**
554-
* Pass an optional `skip` array to preserve files in the root directory.
556+
* Pass an optional `skip` array to preserve files under the root directory.
555557
*/
556558
export function emptyDir(dir: string, skip?: string[]): void {
559+
const skipInDir: string[] = []
560+
let nested: Map<string, string[]> | null = null
561+
if (skip?.length) {
562+
for (const file of skip) {
563+
if (path.dirname(file) !== '.') {
564+
const matched = file.match(splitFirstDirRE)
565+
if (matched) {
566+
nested ??= new Map()
567+
const [, nestedDir, skipPath] = matched
568+
let nestedSkip = nested.get(nestedDir)
569+
if (!nestedSkip) {
570+
nestedSkip = []
571+
nested.set(nestedDir, nestedSkip)
572+
}
573+
if (!nestedSkip.includes(skipPath)) {
574+
nestedSkip.push(skipPath)
575+
}
576+
}
577+
} else {
578+
skipInDir.push(file)
579+
}
580+
}
581+
}
557582
for (const file of fs.readdirSync(dir)) {
558-
if (skip?.includes(file)) {
583+
if (skipInDir.includes(file)) {
559584
continue
560585
}
561-
fs.rmSync(path.resolve(dir, file), { recursive: true, force: true })
586+
if (nested?.has(file)) {
587+
emptyDir(path.resolve(dir, file), nested.get(file))
588+
} else {
589+
fs.rmSync(path.resolve(dir, file), { recursive: true, force: true })
590+
}
562591
}
563592
}
564593

0 commit comments

Comments
 (0)