Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

fix: support process each out dir when there are two or more #9748

Merged
merged 8 commits into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 60 additions & 41 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,28 +491,30 @@ async function doBuild(
libOptions,
config.logger
)
const normalizedOutputs: OutputOptions[] = []

if (Array.isArray(outputs)) {
for (const resolvedOutput of outputs) {
normalizedOutputs.push(buildOutputOptions(resolvedOutput))
}
} else {
normalizedOutputs.push(buildOutputOptions(outputs))
}

const outDirs = normalizedOutputs.map(({ dir }) => resolve(dir!))

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

const output: OutputOptions[] = []
if (Array.isArray(outputs)) {
for (const resolvedOutput of outputs) {
output.push(buildOutputOptions(resolvedOutput))
}
} else {
output.push(buildOutputOptions(outputs))
}

const resolvedChokidarOptions = resolveChokidarOptions(
config.build.watch.chokidar
)

const { watch } = await import('rollup')
const watcher = watch({
...rollupOptions,
output,
output: normalizedOutputs,
watch: {
...config.build.watch,
chokidar: resolvedChokidarOptions
Expand All @@ -523,7 +525,7 @@ async function doBuild(
if (event.code === 'BUNDLE_START') {
config.logger.info(colors.cyan(`\nbuild started...`))
if (options.write) {
prepareOutDir(outDir, options.emptyOutDir, config)
prepareOutDir(outDirs, options.emptyOutDir, config)
}
} else if (event.code === 'BUNDLE_END') {
event.result.close()
Expand All @@ -542,55 +544,72 @@ async function doBuild(
parallelBuilds.push(bundle)

const generate = (output: OutputOptions = {}) => {
return bundle[options.write ? 'write' : 'generate'](
buildOutputOptions(output)
)
return bundle[options.write ? 'write' : 'generate'](output)
}

if (options.write) {
prepareOutDir(outDir, options.emptyOutDir, config)
prepareOutDir(outDirs, options.emptyOutDir, config)
}

if (Array.isArray(outputs)) {
const res = []
for (const output of outputs) {
res.push(await generate(output))
}
return res
} else {
return await generate(outputs)
const res = []
for (const output of normalizedOutputs) {
res.push(await generate(output))
}
return Array.isArray(outputs) ? res : res[0]
} catch (e) {
outputBuildError(e)
throw e
}
}

function prepareOutDir(
outDir: string,
outDirs: string[],
emptyOutDir: boolean | null,
config: ResolvedConfig
) {
if (fs.existsSync(outDir)) {
if (
emptyOutDir == null &&
!normalizePath(outDir).startsWith(config.root + '/')
) {
// warn if outDir is outside of root
config.logger.warn(
colors.yellow(
`\n${colors.bold(`(!)`)} outDir ${colors.white(
colors.dim(outDir)
)} is not inside project root and will not be emptied.\n` +
`Use --emptyOutDir to override.\n`
const nonDuplicateDirs = new Set(outDirs)
let outside = false
if (emptyOutDir == null) {
for (const outDir of nonDuplicateDirs) {
if (
fs.existsSync(outDir) &&
!normalizePath(outDir).startsWith(config.root + '/')
) {
// warn if outDir is outside of root
config.logger.warn(
colors.yellow(
`\n${colors.bold(`(!)`)} outDir ${colors.white(
colors.dim(outDir)
)} is not inside project root and will not be emptied.\n` +
`Use --emptyOutDir to override.\n`
)
)
)
} else if (emptyOutDir !== false) {
emptyDir(outDir, ['.git'])
outside = true
break
}
}
}
if (config.publicDir && fs.existsSync(config.publicDir)) {
copyDir(config.publicDir, outDir)
for (const outDir of nonDuplicateDirs) {
if (!outside && emptyOutDir !== false && fs.existsSync(outDir)) {
// skip those other outDirs which are nested in current outDir
const skipDirs = outDirs
.map((dir) => {
const relative = path.relative(outDir, dir)
if (
relative &&
!relative.startsWith('..') &&
!path.isAbsolute(relative)
) {
return relative
}
return ''
})
.filter(Boolean)
emptyDir(outDir, [...skipDirs, '.git'])
}
if (config.publicDir && fs.existsSync(config.publicDir)) {
copyDir(config.publicDir, outDir)
}
}
}

Expand Down
35 changes: 32 additions & 3 deletions packages/vite/src/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -532,16 +532,45 @@ export function isFileReadable(filename: string): boolean {
}
}

const splitFirstDirRE = /(.+?)[\\/](.+)/

/**
* Delete every file and subdirectory. **The given directory must exist.**
* Pass an optional `skip` array to preserve files in the root directory.
* Pass an optional `skip` array to preserve files under the root directory.
*/
export function emptyDir(dir: string, skip?: string[]): void {
const skipInDir: string[] = []
let nested: Map<string, string[]> | null = null
if (skip?.length) {
for (const file of skip) {
if (path.dirname(file) !== '.') {
const matched = file.match(splitFirstDirRE)
if (matched) {
nested ??= new Map()
const [, nestedDir, skipPath] = matched
let nestedSkip = nested.get(nestedDir)
if (!nestedSkip) {
nestedSkip = []
nested.set(nestedDir, nestedSkip)
}
if (!nestedSkip.includes(skipPath)) {
nestedSkip.push(skipPath)
}
}
} else {
skipInDir.push(file)
}
}
}
for (const file of fs.readdirSync(dir)) {
if (skip?.includes(file)) {
if (skipInDir.includes(file)) {
continue
}
fs.rmSync(path.resolve(dir, file), { recursive: true, force: true })
if (nested?.has(file)) {
emptyDir(path.resolve(dir, file), nested.get(file))
} else {
fs.rmSync(path.resolve(dir, file), { recursive: true, force: true })
}
}
}

Expand Down