Skip to content

Commit 3dfb046

Browse files
committed
refactor: extract prepareOutDir as a plugin
1 parent b19b90a commit 3dfb046

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) =>
@@ -706,12 +703,6 @@ async function buildEnvironment(
706703
}
707704
}
708705

709-
const outputBuildError = (e: RollupError) => {
710-
enhanceRollupError(e)
711-
clearLine()
712-
logger.error(e.message, { error: e })
713-
}
714-
715706
const isSsrTargetWebworkerEnvironment =
716707
environment.name === 'ssr' &&
717708
environment.getTopLevelConfig().ssr?.target === 'webworker'
@@ -814,22 +805,21 @@ async function buildEnvironment(
814805
normalizedOutputs.push(buildOutputOptions(outputs))
815806
}
816807

817-
const resolvedOutDirs = getResolvedOutDirs(
818-
root,
819-
options.outDir,
820-
options.rollupOptions.output,
821-
)
822-
const emptyOutDir = resolveEmptyOutDir(
823-
options.emptyOutDir,
824-
root,
825-
resolvedOutDirs,
826-
logger,
827-
)
828-
829808
// watch file changes with rollup
830809
if (options.watch) {
831810
logger.info(colors.cyan(`\nwatching for file changes...`))
832811

812+
const resolvedOutDirs = getResolvedOutDirs(
813+
root,
814+
options.outDir,
815+
options.rollupOptions.output,
816+
)
817+
const emptyOutDir = resolveEmptyOutDir(
818+
options.emptyOutDir,
819+
root,
820+
resolvedOutDirs,
821+
logger,
822+
)
833823
const resolvedChokidarOptions = resolveChokidarOptions(
834824
// @ts-expect-error chokidar option does not exist in rolldown but used for backward compat
835825
options.watch.chokidar,
@@ -851,14 +841,14 @@ async function buildEnvironment(
851841
watcher.on('event', (event) => {
852842
if (event.code === 'BUNDLE_START') {
853843
logger.info(colors.cyan(`\nbuild started...`))
854-
if (options.write) {
855-
prepareOutDir(resolvedOutDirs, emptyOutDir, environment)
856-
}
857844
} else if (event.code === 'BUNDLE_END') {
858845
event.result.close()
859846
logger.info(colors.cyan(`built in ${event.duration}ms.`))
860847
} else if (event.code === 'ERROR') {
861-
outputBuildError(event.error)
848+
const e = event.error
849+
enhanceRollupError(e)
850+
clearLine()
851+
logger.error(e.message, { error: e })
862852
}
863853
})
864854

@@ -869,11 +859,6 @@ async function buildEnvironment(
869859
const { rolldown } = await import('rolldown')
870860
startTime = Date.now()
871861
bundle = await rolldown(rollupOptions)
872-
873-
if (options.write) {
874-
prepareOutDir(resolvedOutDirs, emptyOutDir, environment)
875-
}
876-
877862
const res: RolldownOutput[] = []
878863
for (const output of normalizedOutputs) {
879864
res.push(await bundle[options.write ? 'write' : 'generate'](output))
@@ -904,54 +889,6 @@ async function buildEnvironment(
904889
}
905890
}
906891

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

957894
function resolveOutputJsExtension(
@@ -1577,16 +1514,6 @@ export function toOutputFilePathWithoutRuntime(
15771514
export const toOutputFilePathInCss = toOutputFilePathWithoutRuntime
15781515
export const toOutputFilePathInHtml = toOutputFilePathWithoutRuntime
15791516

1580-
function areSeparateFolders(a: string, b: string) {
1581-
const na = normalizePath(a)
1582-
const nb = normalizePath(b)
1583-
return (
1584-
na !== nb &&
1585-
!na.startsWith(withTrailingSlash(nb)) &&
1586-
!nb.startsWith(withTrailingSlash(na))
1587-
)
1588-
}
1589-
15901517
export class BuildEnvironment extends BaseEnvironment {
15911518
mode = 'build' as const
15921519

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)