Skip to content

Commit 2c4af1f

Browse files
authored
refactor: extract prepareOutDir as a plugin (#20373)
1 parent 6970d17 commit 2c4af1f

File tree

2 files changed

+119
-89
lines changed

2 files changed

+119
-89
lines changed

packages/vite/src/node/build.ts

Lines changed: 17 additions & 89 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 {
@@ -24,7 +23,6 @@ import commonjsPlugin from '@rollup/plugin-commonjs'
2423
import type { RollupCommonJSOptions } from 'dep-types/commonjs'
2524
import type { RollupDynamicImportVarsOptions } from 'dep-types/dynamicImportVars'
2625
import type { TransformOptions } from 'esbuild'
27-
import { withTrailingSlash } from '../shared/utils'
2826
import {
2927
DEFAULT_ASSETS_INLINE_LIMIT,
3028
ESBUILD_BASELINE_WIDELY_AVAILABLE_TARGET,
@@ -45,15 +43,12 @@ import { type TerserOptions, terserPlugin } from './plugins/terser'
4543
import {
4644
arraify,
4745
asyncFlatten,
48-
copyDir,
4946
createDebugger,
5047
displayTime,
51-
emptyDir,
5248
getPkgName,
5349
joinUrlSegments,
5450
mergeConfig,
5551
mergeWithDefaults,
56-
normalizePath,
5752
partialEncodeURIPath,
5853
} from './utils'
5954
import { perEnvironmentPlugin } from './plugin'
@@ -80,6 +75,7 @@ import {
8075
BasicMinimalPluginContext,
8176
basePluginContextMeta,
8277
} from './server/pluginContainer'
78+
import { prepareOutDirPlugin } from './plugins/prepareOutDir'
8379

8480
export interface BuildEnvironmentOptions {
8581
/**
@@ -466,6 +462,7 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
466462
return {
467463
pre: [
468464
completeSystemWrapPlugin(),
465+
prepareOutDirPlugin(),
469466
perEnvironmentPlugin('commonjs', (environment) => {
470467
const { commonjsOptions } = environment.config.build
471468
const usePluginCommonjs =
@@ -665,12 +662,6 @@ async function buildEnvironment(
665662
}
666663
}
667664

668-
const outputBuildError = (e: RollupError) => {
669-
enhanceRollupError(e)
670-
clearLine()
671-
logger.error(e.message, { error: e })
672-
}
673-
674665
const isSsrTargetWebworkerEnvironment =
675666
environment.name === 'ssr' &&
676667
environment.getTopLevelConfig().ssr?.target === 'webworker'
@@ -766,22 +757,21 @@ async function buildEnvironment(
766757
normalizedOutputs.push(buildOutputOptions(outputs))
767758
}
768759

769-
const resolvedOutDirs = getResolvedOutDirs(
770-
root,
771-
options.outDir,
772-
options.rollupOptions.output,
773-
)
774-
const emptyOutDir = resolveEmptyOutDir(
775-
options.emptyOutDir,
776-
root,
777-
resolvedOutDirs,
778-
logger,
779-
)
780-
781760
// watch file changes with rollup
782761
if (options.watch) {
783762
logger.info(colors.cyan(`\nwatching for file changes...`))
784763

764+
const resolvedOutDirs = getResolvedOutDirs(
765+
root,
766+
options.outDir,
767+
options.rollupOptions.output,
768+
)
769+
const emptyOutDir = resolveEmptyOutDir(
770+
options.emptyOutDir,
771+
root,
772+
resolvedOutDirs,
773+
logger,
774+
)
785775
const resolvedChokidarOptions = resolveChokidarOptions(
786776
options.watch.chokidar,
787777
resolvedOutDirs,
@@ -802,14 +792,14 @@ async function buildEnvironment(
802792
watcher.on('event', (event) => {
803793
if (event.code === 'BUNDLE_START') {
804794
logger.info(colors.cyan(`\nbuild started...`))
805-
if (options.write) {
806-
prepareOutDir(resolvedOutDirs, emptyOutDir, environment)
807-
}
808795
} else if (event.code === 'BUNDLE_END') {
809796
event.result.close()
810797
logger.info(colors.cyan(`built in ${event.duration}ms.`))
811798
} else if (event.code === 'ERROR') {
812-
outputBuildError(event.error)
799+
const e = event.error
800+
enhanceRollupError(e)
801+
clearLine()
802+
logger.error(e.message, { error: e })
813803
}
814804
})
815805

@@ -821,10 +811,6 @@ async function buildEnvironment(
821811
startTime = Date.now()
822812
bundle = await rollup(rollupOptions)
823813

824-
if (options.write) {
825-
prepareOutDir(resolvedOutDirs, emptyOutDir, environment)
826-
}
827-
828814
const res: RollupOutput[] = []
829815
for (const output of normalizedOutputs) {
830816
res.push(await bundle[options.write ? 'write' : 'generate'](output))
@@ -848,54 +834,6 @@ async function buildEnvironment(
848834
}
849835
}
850836

851-
function prepareOutDir(
852-
outDirs: Set<string>,
853-
emptyOutDir: boolean | null,
854-
environment: BuildEnvironment,
855-
) {
856-
const { publicDir } = environment.config
857-
const outDirsArray = [...outDirs]
858-
for (const outDir of outDirs) {
859-
if (emptyOutDir !== false && fs.existsSync(outDir)) {
860-
// skip those other outDirs which are nested in current outDir
861-
const skipDirs = outDirsArray
862-
.map((dir) => {
863-
const relative = path.relative(outDir, dir)
864-
if (
865-
relative &&
866-
!relative.startsWith('..') &&
867-
!path.isAbsolute(relative)
868-
) {
869-
return relative
870-
}
871-
return ''
872-
})
873-
.filter(Boolean)
874-
emptyDir(outDir, [...skipDirs, '.git'])
875-
}
876-
if (
877-
environment.config.build.copyPublicDir &&
878-
publicDir &&
879-
fs.existsSync(publicDir)
880-
) {
881-
if (!areSeparateFolders(outDir, publicDir)) {
882-
environment.logger.warn(
883-
colors.yellow(
884-
`\n${colors.bold(
885-
`(!)`,
886-
)} The public directory feature may not work correctly. outDir ${colors.white(
887-
colors.dim(outDir),
888-
)} and publicDir ${colors.white(
889-
colors.dim(publicDir),
890-
)} are not separate folders.\n`,
891-
),
892-
)
893-
}
894-
copyDir(publicDir, outDir)
895-
}
896-
}
897-
}
898-
899837
type JsExt = 'js' | 'cjs' | 'mjs'
900838

901839
function resolveOutputJsExtension(
@@ -1458,16 +1396,6 @@ export function toOutputFilePathWithoutRuntime(
14581396
export const toOutputFilePathInCss = toOutputFilePathWithoutRuntime
14591397
export const toOutputFilePathInHtml = toOutputFilePathWithoutRuntime
14601398

1461-
function areSeparateFolders(a: string, b: string) {
1462-
const na = normalizePath(a)
1463-
const nb = normalizePath(b)
1464-
return (
1465-
na !== nb &&
1466-
!na.startsWith(withTrailingSlash(nb)) &&
1467-
!nb.startsWith(withTrailingSlash(na))
1468-
)
1469-
}
1470-
14711399
export class BuildEnvironment extends BaseEnvironment {
14721400
mode = 'build' as const
14731401

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)