Skip to content

Commit 5c56180

Browse files
committed
refactor: extract prepareOutDir as a plugin
1 parent 9b5e32a commit 5c56180

File tree

2 files changed

+119
-90
lines changed

2 files changed

+119
-90
lines changed

packages/vite/src/node/build.ts

Lines changed: 17 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import fs from 'node:fs'
21
import path from 'node:path'
32
import colors from 'picocolors'
43
import type {
@@ -28,7 +27,6 @@ import type { RollupCommonJSOptions } from 'dep-types/commonjs'
2827
import type { RollupDynamicImportVarsOptions } from 'dep-types/dynamicImportVars'
2928
import type { EsbuildTarget } from 'types/internal/esbuildOptions'
3029
import type { ChunkMetadata } from 'types/metadata'
31-
import { withTrailingSlash } from '../shared/utils'
3230
import {
3331
DEFAULT_ASSETS_INLINE_LIMIT,
3432
ESBUILD_BASELINE_WIDELY_AVAILABLE_TARGET,
@@ -49,15 +47,12 @@ import { type TerserOptions, terserPlugin } from './plugins/terser'
4947
import {
5048
arraify,
5149
asyncFlatten,
52-
copyDir,
5350
createDebugger,
5451
displayTime,
55-
emptyDir,
5652
getPkgName,
5753
joinUrlSegments,
5854
mergeConfig,
5955
mergeWithDefaults,
60-
normalizePath,
6156
partialEncodeURIPath,
6257
unique,
6358
} from './utils'
@@ -85,6 +80,7 @@ import {
8580
BasicMinimalPluginContext,
8681
basePluginContextMeta,
8782
} from './server/pluginContainer'
83+
import { prepareOutDirPlugin } from './plugins/prepareOutDir'
8884

8985
export interface BuildEnvironmentOptions {
9086
/**
@@ -480,6 +476,7 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
480476
return {
481477
pre: [
482478
completeSystemWrapPlugin(),
479+
prepareOutDirPlugin(),
483480
perEnvironmentPlugin(
484481
'vite:rollup-options-plugins',
485482
async (environment) =>
@@ -697,12 +694,6 @@ async function buildEnvironment(
697694
}
698695
}
699696

700-
const outputBuildError = (e: RollupError) => {
701-
enhanceRollupError(e)
702-
clearLine()
703-
logger.error(e.message, { error: e })
704-
}
705-
706697
const isSsrTargetWebworkerEnvironment =
707698
environment.name === 'ssr' &&
708699
environment.getTopLevelConfig().ssr?.target === 'webworker'
@@ -804,22 +795,21 @@ async function buildEnvironment(
804795
normalizedOutputs.push(buildOutputOptions(outputs))
805796
}
806797

807-
const resolvedOutDirs = getResolvedOutDirs(
808-
root,
809-
options.outDir,
810-
options.rollupOptions.output,
811-
)
812-
const emptyOutDir = resolveEmptyOutDir(
813-
options.emptyOutDir,
814-
root,
815-
resolvedOutDirs,
816-
logger,
817-
)
818-
819798
// watch file changes with rollup
820799
if (options.watch) {
821800
logger.info(colors.cyan(`\nwatching for file changes...`))
822801

802+
const resolvedOutDirs = getResolvedOutDirs(
803+
root,
804+
options.outDir,
805+
options.rollupOptions.output,
806+
)
807+
const emptyOutDir = resolveEmptyOutDir(
808+
options.emptyOutDir,
809+
root,
810+
resolvedOutDirs,
811+
logger,
812+
)
823813
const resolvedChokidarOptions = resolveChokidarOptions(
824814
// @ts-expect-error chokidar option does not exist in rolldown but used for backward compat
825815
options.watch.chokidar,
@@ -841,14 +831,14 @@ async function buildEnvironment(
841831
watcher.on('event', (event) => {
842832
if (event.code === 'BUNDLE_START') {
843833
logger.info(colors.cyan(`\nbuild started...`))
844-
if (options.write) {
845-
prepareOutDir(resolvedOutDirs, emptyOutDir, environment)
846-
}
847834
} else if (event.code === 'BUNDLE_END') {
848835
event.result.close()
849836
logger.info(colors.cyan(`built in ${event.duration}ms.`))
850837
} else if (event.code === 'ERROR') {
851-
outputBuildError(event.error)
838+
const e = event.error
839+
enhanceRollupError(e)
840+
clearLine()
841+
logger.error(e.message, { error: e })
852842
}
853843
})
854844

@@ -859,11 +849,6 @@ async function buildEnvironment(
859849
const { rolldown } = await import('rolldown')
860850
startTime = Date.now()
861851
bundle = await rolldown(rollupOptions)
862-
863-
if (options.write) {
864-
prepareOutDir(resolvedOutDirs, emptyOutDir, environment)
865-
}
866-
867852
const res: RolldownOutput[] = []
868853
for (const output of normalizedOutputs) {
869854
res.push(await bundle[options.write ? 'write' : 'generate'](output))
@@ -894,54 +879,6 @@ async function buildEnvironment(
894879
}
895880
}
896881

897-
function prepareOutDir(
898-
outDirs: Set<string>,
899-
emptyOutDir: boolean | null,
900-
environment: BuildEnvironment,
901-
) {
902-
const { publicDir } = environment.config
903-
const outDirsArray = [...outDirs]
904-
for (const outDir of outDirs) {
905-
if (emptyOutDir !== false && fs.existsSync(outDir)) {
906-
// skip those other outDirs which are nested in current outDir
907-
const skipDirs = outDirsArray
908-
.map((dir) => {
909-
const relative = path.relative(outDir, dir)
910-
if (
911-
relative &&
912-
!relative.startsWith('..') &&
913-
!path.isAbsolute(relative)
914-
) {
915-
return relative
916-
}
917-
return ''
918-
})
919-
.filter(Boolean)
920-
emptyDir(outDir, [...skipDirs, '.git'])
921-
}
922-
if (
923-
environment.config.build.copyPublicDir &&
924-
publicDir &&
925-
fs.existsSync(publicDir)
926-
) {
927-
if (!areSeparateFolders(outDir, publicDir)) {
928-
environment.logger.warn(
929-
colors.yellow(
930-
`\n${colors.bold(
931-
`(!)`,
932-
)} The public directory feature may not work correctly. outDir ${colors.white(
933-
colors.dim(outDir),
934-
)} and publicDir ${colors.white(
935-
colors.dim(publicDir),
936-
)} are not separate folders.\n`,
937-
),
938-
)
939-
}
940-
copyDir(publicDir, outDir)
941-
}
942-
}
943-
}
944-
945882
type JsExt = 'js' | 'cjs' | 'mjs'
946883

947884
function resolveOutputJsExtension(
@@ -1567,16 +1504,6 @@ export function toOutputFilePathWithoutRuntime(
15671504
export const toOutputFilePathInCss = toOutputFilePathWithoutRuntime
15681505
export const toOutputFilePathInHtml = toOutputFilePathWithoutRuntime
15691506

1570-
function areSeparateFolders(a: string, b: string) {
1571-
const na = normalizePath(a)
1572-
const nb = normalizePath(b)
1573-
return (
1574-
na !== nb &&
1575-
!na.startsWith(withTrailingSlash(nb)) &&
1576-
!nb.startsWith(withTrailingSlash(na))
1577-
)
1578-
}
1579-
15801507
export class BuildEnvironment extends BaseEnvironment {
15811508
mode = 'build' as const
15821509

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import fs from 'node:fs'
2+
import path from 'node:path'
3+
import colors from 'picocolors'
4+
import type { Plugin } from '../plugin'
5+
import { getResolvedOutDirs, resolveEmptyOutDir } from '../watch'
6+
import type { Environment } from '../environment'
7+
import { copyDir, emptyDir, normalizePath } from '../utils'
8+
import { withTrailingSlash } from '../../shared/utils'
9+
10+
export function prepareOutDirPlugin(): Plugin {
11+
const rendered = new Set<Environment>()
12+
return {
13+
name: 'vite:prepare-out-dir',
14+
options() {
15+
rendered.delete(this.environment)
16+
},
17+
renderStart: {
18+
order: 'pre',
19+
handler() {
20+
if (rendered.has(this.environment)) {
21+
return
22+
}
23+
rendered.add(this.environment)
24+
25+
const { config } = this.environment
26+
if (config.build.write) {
27+
const { root, build: options } = config
28+
const resolvedOutDirs = getResolvedOutDirs(
29+
root,
30+
options.outDir,
31+
options.rollupOptions.output,
32+
)
33+
const emptyOutDir = resolveEmptyOutDir(
34+
options.emptyOutDir,
35+
root,
36+
resolvedOutDirs,
37+
this.environment.logger,
38+
)
39+
prepareOutDir(resolvedOutDirs, emptyOutDir, this.environment)
40+
}
41+
},
42+
},
43+
}
44+
}
45+
46+
function prepareOutDir(
47+
outDirs: Set<string>,
48+
emptyOutDir: boolean | null,
49+
environment: Environment,
50+
) {
51+
const { publicDir } = environment.config
52+
const outDirsArray = [...outDirs]
53+
for (const outDir of outDirs) {
54+
if (emptyOutDir !== false && fs.existsSync(outDir)) {
55+
// skip those other outDirs which are nested in current outDir
56+
const skipDirs = outDirsArray
57+
.map((dir) => {
58+
const relative = path.relative(outDir, dir)
59+
if (
60+
relative &&
61+
!relative.startsWith('..') &&
62+
!path.isAbsolute(relative)
63+
) {
64+
return relative
65+
}
66+
return ''
67+
})
68+
.filter(Boolean)
69+
emptyDir(outDir, [...skipDirs, '.git'])
70+
}
71+
if (
72+
environment.config.build.copyPublicDir &&
73+
publicDir &&
74+
fs.existsSync(publicDir)
75+
) {
76+
if (!areSeparateFolders(outDir, publicDir)) {
77+
environment.logger.warn(
78+
colors.yellow(
79+
`\n${colors.bold(
80+
`(!)`,
81+
)} The public directory feature may not work correctly. outDir ${colors.white(
82+
colors.dim(outDir),
83+
)} and publicDir ${colors.white(
84+
colors.dim(publicDir),
85+
)} are not separate folders.\n`,
86+
),
87+
)
88+
}
89+
copyDir(publicDir, outDir)
90+
}
91+
}
92+
}
93+
94+
function areSeparateFolders(a: string, b: string) {
95+
const na = normalizePath(a)
96+
const nb = normalizePath(b)
97+
return (
98+
na !== nb &&
99+
!na.startsWith(withTrailingSlash(nb)) &&
100+
!nb.startsWith(withTrailingSlash(na))
101+
)
102+
}

0 commit comments

Comments
 (0)