Skip to content

Commit 8615bd7

Browse files
committed
refactor: extract prepareOutDir as a plugin
1 parent 6e08b30 commit 8615bd7

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_MODULES_TARGET,
@@ -49,14 +47,11 @@ 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
mergeWithDefaults,
59-
normalizePath,
6055
partialEncodeURIPath,
6156
unique,
6257
} from './utils'
@@ -84,6 +79,7 @@ import {
8479
import type { Plugin } from './plugin'
8580
import type { RollupPluginHooks } from './typeUtils'
8681
import { buildOxcPlugin } from './plugins/oxc'
82+
import { prepareOutDirPlugin } from './plugins/prepareOutDir'
8783

8884
export interface BuildEnvironmentOptions {
8985
/**
@@ -479,6 +475,7 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
479475
return {
480476
pre: [
481477
completeSystemWrapPlugin(),
478+
prepareOutDirPlugin(),
482479
perEnvironmentPlugin(
483480
'vite:rollup-options-plugins',
484481
async (environment) =>
@@ -693,12 +690,6 @@ async function buildEnvironment(
693690
}
694691
}
695692

696-
const outputBuildError = (e: RollupError) => {
697-
enhanceRollupError(e)
698-
clearLine()
699-
logger.error(e.message, { error: e })
700-
}
701-
702693
const isSsrTargetWebworkerEnvironment =
703694
environment.name === 'ssr' &&
704695
environment.getTopLevelConfig().ssr?.target === 'webworker'
@@ -800,22 +791,21 @@ async function buildEnvironment(
800791
normalizedOutputs.push(buildOutputOptions(outputs))
801792
}
802793

803-
const resolvedOutDirs = getResolvedOutDirs(
804-
root,
805-
options.outDir,
806-
options.rollupOptions.output,
807-
)
808-
const emptyOutDir = resolveEmptyOutDir(
809-
options.emptyOutDir,
810-
root,
811-
resolvedOutDirs,
812-
logger,
813-
)
814-
815794
// watch file changes with rollup
816795
if (options.watch) {
817796
logger.info(colors.cyan(`\nwatching for file changes...`))
818797

798+
const resolvedOutDirs = getResolvedOutDirs(
799+
root,
800+
options.outDir,
801+
options.rollupOptions.output,
802+
)
803+
const emptyOutDir = resolveEmptyOutDir(
804+
options.emptyOutDir,
805+
root,
806+
resolvedOutDirs,
807+
logger,
808+
)
819809
const resolvedChokidarOptions = resolveChokidarOptions(
820810
// @ts-expect-error chokidar option does not exist in rolldown but used for backward compat
821811
options.watch.chokidar,
@@ -837,14 +827,14 @@ async function buildEnvironment(
837827
watcher.on('event', (event) => {
838828
if (event.code === 'BUNDLE_START') {
839829
logger.info(colors.cyan(`\nbuild started...`))
840-
if (options.write) {
841-
prepareOutDir(resolvedOutDirs, emptyOutDir, environment)
842-
}
843830
} else if (event.code === 'BUNDLE_END') {
844831
event.result.close()
845832
logger.info(colors.cyan(`built in ${event.duration}ms.`))
846833
} else if (event.code === 'ERROR') {
847-
outputBuildError(event.error)
834+
const e = event.error
835+
enhanceRollupError(e)
836+
clearLine()
837+
logger.error(e.message, { error: e })
848838
}
849839
})
850840

@@ -855,11 +845,6 @@ async function buildEnvironment(
855845
const { rolldown } = await import('rolldown')
856846
startTime = Date.now()
857847
bundle = await rolldown(rollupOptions)
858-
859-
if (options.write) {
860-
prepareOutDir(resolvedOutDirs, emptyOutDir, environment)
861-
}
862-
863848
const res: RolldownOutput[] = []
864849
for (const output of normalizedOutputs) {
865850
res.push(await bundle[options.write ? 'write' : 'generate'](output))
@@ -883,54 +868,6 @@ async function buildEnvironment(
883868
}
884869
}
885870

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

936873
function resolveOutputJsExtension(
@@ -1553,16 +1490,6 @@ export function toOutputFilePathWithoutRuntime(
15531490
export const toOutputFilePathInCss = toOutputFilePathWithoutRuntime
15541491
export const toOutputFilePathInHtml = toOutputFilePathWithoutRuntime
15551492

1556-
function areSeparateFolders(a: string, b: string) {
1557-
const na = normalizePath(a)
1558-
const nb = normalizePath(b)
1559-
return (
1560-
na !== nb &&
1561-
!na.startsWith(withTrailingSlash(nb)) &&
1562-
!nb.startsWith(withTrailingSlash(na))
1563-
)
1564-
}
1565-
15661493
export class BuildEnvironment extends BaseEnvironment {
15671494
mode = 'build' as const
15681495

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)