Skip to content

Commit c4758d1

Browse files
danielroebluwy
authored andcommitted
fix(vite): precisely check if files are in dirs (#14241)
1 parent 218861f commit c4758d1

File tree

14 files changed

+77
-31
lines changed

14 files changed

+77
-31
lines changed

packages/vite/src/node/build.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
joinUrlSegments,
3636
normalizePath,
3737
requireResolveFromRootWithFallback,
38+
withTrailingSlash,
3839
} from './utils'
3940
import { manifestPlugin } from './plugins/manifest'
4041
import type { Logger } from './logger'
@@ -714,7 +715,7 @@ function prepareOutDir(
714715
for (const outDir of nonDuplicateDirs) {
715716
if (
716717
fs.existsSync(outDir) &&
717-
!normalizePath(outDir).startsWith(config.root + '/')
718+
!normalizePath(outDir).startsWith(withTrailingSlash(config.root))
718719
) {
719720
// warn if outDir is outside of root
720721
config.logger.warn(
@@ -1240,5 +1241,9 @@ export const toOutputFilePathInHtml = toOutputFilePathWithoutRuntime
12401241
function areSeparateFolders(a: string, b: string) {
12411242
const na = normalizePath(a)
12421243
const nb = normalizePath(b)
1243-
return na !== nb && !na.startsWith(nb + '/') && !nb.startsWith(na + '/')
1244+
return (
1245+
na !== nb &&
1246+
!na.startsWith(withTrailingSlash(nb)) &&
1247+
!nb.startsWith(withTrailingSlash(na))
1248+
)
12441249
}

packages/vite/src/node/config.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
mergeConfig,
4040
normalizeAlias,
4141
normalizePath,
42+
withTrailingSlash,
4243
} from './utils'
4344
import {
4445
createPluginHookUtils,
@@ -680,7 +681,7 @@ export async function resolveConfig(
680681
),
681682
inlineConfig,
682683
root: resolvedRoot,
683-
base: resolvedBase.endsWith('/') ? resolvedBase : resolvedBase + '/',
684+
base: withTrailingSlash(resolvedBase),
684685
rawBase: resolvedBase,
685686
resolve: resolveOptions,
686687
publicDir: resolvedPublicDir,
@@ -856,7 +857,7 @@ assetFileNames isn't equal for every build.rollupOptions.output. A single patter
856857
) {
857858
resolved.logger.warn(
858859
colors.yellow(`
859-
(!) Experimental legacy.buildSsrCjsExternalHeuristics and ssr.format: 'cjs' are going to be removed in Vite 5.
860+
(!) Experimental legacy.buildSsrCjsExternalHeuristics and ssr.format: 'cjs' are going to be removed in Vite 5.
860861
Find more information and give feedback at https://github.com/vitejs/vite/discussions/13816.
861862
`),
862863
)

packages/vite/src/node/plugins/asset.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
joinUrlSegments,
2424
normalizePath,
2525
removeLeadingSlash,
26+
withTrailingSlash,
2627
} from '../utils'
2728
import { FS_PREFIX } from '../constants'
2829

@@ -229,7 +230,11 @@ export function checkPublicFile(
229230
return
230231
}
231232
const publicFile = path.join(publicDir, cleanUrl(url))
232-
if (!publicFile.startsWith(publicDir)) {
233+
if (
234+
!normalizePath(publicFile).startsWith(
235+
withTrailingSlash(normalizePath(publicDir)),
236+
)
237+
) {
233238
// can happen if URL starts with '../'
234239
return
235240
}
@@ -257,7 +262,7 @@ function fileToDevUrl(id: string, config: ResolvedConfig) {
257262
if (checkPublicFile(id, config)) {
258263
// in public dir, keep the url as-is
259264
rtn = id
260-
} else if (id.startsWith(config.root)) {
265+
} else if (id.startsWith(withTrailingSlash(config.root))) {
261266
// in project root, infer short public path
262267
rtn = '/' + path.posix.relative(config.root, id)
263268
} else {

packages/vite/src/node/plugins/importAnalysis.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
timeFrom,
4545
transformStableResult,
4646
unwrapId,
47+
withTrailingSlash,
4748
wrapId,
4849
} from '../utils'
4950
import { getDepOptimizationConfig } from '../config'
@@ -335,7 +336,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
335336

336337
// normalize all imports into resolved URLs
337338
// e.g. `import 'foo'` -> `import '/@fs/.../node_modules/foo/index.js'`
338-
if (resolved.id.startsWith(root + '/')) {
339+
if (resolved.id.startsWith(withTrailingSlash(root))) {
339340
// in root: infer short absolute path from root
340341
url = resolved.id.slice(root.length)
341342
} else if (
@@ -672,7 +673,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
672673
config.logger.error(e.message, { error: e })
673674
})
674675
}
675-
} else if (!importer.startsWith(clientDir)) {
676+
} else if (!importer.startsWith(withTrailingSlash(clientDir))) {
676677
if (!isInNodeModules(importer)) {
677678
// check @vite-ignore which suppresses dynamic import warning
678679
const hasViteIgnore = hasViteIgnoreRE.test(

packages/vite/src/node/plugins/importAnalysisBuild.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
isInNodeModules,
1717
moduleListContains,
1818
numberToPos,
19+
withTrailingSlash,
1920
} from '../utils'
2021
import type { Plugin } from '../plugin'
2122
import { getDepOptimizationConfig } from '../config'
@@ -271,7 +272,7 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin {
271272

272273
// normalize all imports into resolved URLs
273274
// e.g. `import 'foo'` -> `import '/@fs/.../node_modules/foo/index.js'`
274-
if (resolved.id.startsWith(root + '/')) {
275+
if (resolved.id.startsWith(withTrailingSlash(root))) {
275276
// in root: infer short absolute path from root
276277
url = resolved.id.slice(root.length)
277278
} else {

packages/vite/src/node/plugins/preAlias.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
isInNodeModules,
1515
isOptimizable,
1616
moduleListContains,
17+
withTrailingSlash,
1718
} from '../utils'
1819
import { getDepsOptimizer } from '../optimizer'
1920
import { tryOptimizedResolve } from './resolve'
@@ -114,7 +115,7 @@ function matches(pattern: string | RegExp, importee: string) {
114115
if (importee === pattern) {
115116
return true
116117
}
117-
return importee.startsWith(pattern + '/')
118+
return importee.startsWith(withTrailingSlash(pattern))
118119
}
119120

120121
function getAliasPatterns(

packages/vite/src/node/plugins/reporter.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@ import { promisify } from 'node:util'
44
import colors from 'picocolors'
55
import type { Plugin } from 'rollup'
66
import type { ResolvedConfig } from '../config'
7-
import { isDefined, isInNodeModules, normalizePath } from '../utils'
7+
import {
8+
isDefined,
9+
isInNodeModules,
10+
normalizePath,
11+
withTrailingSlash,
12+
} from '../utils'
813
import { LogLevels } from '../logger'
914

1015
const groups = [
@@ -243,9 +248,10 @@ export function buildReporterPlugin(config: ResolvedConfig): Plugin {
243248
group.name === 'JS' && entry.size / 1000 > chunkLimit
244249
if (isLarge) hasLargeChunks = true
245250
const sizeColor = isLarge ? colors.yellow : colors.dim
246-
let log = colors.dim(relativeOutDir + '/')
251+
let log = colors.dim(withTrailingSlash(relativeOutDir))
247252
log +=
248-
!config.build.lib && entry.name.startsWith(assetsDir)
253+
!config.build.lib &&
254+
entry.name.startsWith(withTrailingSlash(assetsDir))
249255
? colors.dim(assetsDir) +
250256
group.color(
251257
entry.name

packages/vite/src/node/plugins/resolve.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
safeRealpathSync,
3737
slash,
3838
tryStatSync,
39+
withTrailingSlash,
3940
} from '../utils'
4041
import { optimizedDepInfoFromFile, optimizedDepInfoFromId } from '../optimizer'
4142
import type { DepsOptimizer } from '../optimizer'
@@ -228,7 +229,11 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin {
228229

229230
// URL
230231
// /foo -> /fs-root/foo
231-
if (asSrc && id[0] === '/' && (rootInRoot || !id.startsWith(root))) {
232+
if (
233+
asSrc &&
234+
id[0] === '/' &&
235+
(rootInRoot || !id.startsWith(withTrailingSlash(root)))
236+
) {
232237
const fsPath = path.resolve(root, id.slice(1))
233238
if ((res = tryFsResolve(fsPath, options))) {
234239
debug?.(`[url] ${colors.cyan(id)} -> ${colors.dim(res)}`)
@@ -939,7 +944,7 @@ export async function tryOptimizedResolve(
939944
}
940945

941946
// match by src to correctly identify if id belongs to nested dependency
942-
if (optimizedData.src.startsWith(idPkgDir)) {
947+
if (optimizedData.src.startsWith(withTrailingSlash(idPkgDir))) {
943948
return depsOptimizer.getOptimizedDepId(optimizedData)
944949
}
945950
}

packages/vite/src/node/server/hmr.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ import colors from 'picocolors'
55
import type { Update } from 'types/hmrPayload'
66
import type { RollupError } from 'rollup'
77
import { CLIENT_DIR } from '../constants'
8-
import { createDebugger, normalizePath, unique, wrapId } from '../utils'
8+
import {
9+
createDebugger,
10+
normalizePath,
11+
unique,
12+
withTrailingSlash,
13+
wrapId,
14+
} from '../utils'
915
import type { ViteDevServer } from '..'
1016
import { isCSSRequest } from '../plugins/css'
1117
import { getAffectedGlobModules } from '../plugins/importMetaGlob'
@@ -38,7 +44,9 @@ export interface HmrContext {
3844
}
3945

4046
export function getShortName(file: string, root: string): string {
41-
return file.startsWith(root + '/') ? path.posix.relative(root, file) : file
47+
return file.startsWith(withTrailingSlash(root))
48+
? path.posix.relative(root, file)
49+
: file
4250
}
4351

4452
export async function handleHMRUpdate(
@@ -81,7 +89,7 @@ export async function handleHMRUpdate(
8189
debugHmr?.(`[file change] ${colors.dim(shortFile)}`)
8290

8391
// (dev only) the client itself cannot be hot updated.
84-
if (file.startsWith(normalizedClientDir)) {
92+
if (file.startsWith(withTrailingSlash(normalizedClientDir))) {
8593
ws.send({
8694
type: 'full-reload',
8795
path: '*',

packages/vite/src/node/server/middlewares/base.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Connect } from 'dep-types/connect'
22
import type { ViteDevServer } from '..'
3-
import { joinUrlSegments, stripBase } from '../../utils'
3+
import { joinUrlSegments, stripBase, withTrailingSlash } from '../../utils'
44

55
// this middleware is only active when (base !== '/')
66

@@ -36,7 +36,7 @@ export function baseMiddleware({
3636
} else if (req.headers.accept?.includes('text/html')) {
3737
// non-based page visit
3838
const redirectPath =
39-
url + '/' !== base ? joinUrlSegments(base, url) : base
39+
withTrailingSlash(url) !== base ? joinUrlSegments(base, url) : base
4040
res.writeHead(404, {
4141
'Content-Type': 'text/html',
4242
})

0 commit comments

Comments
 (0)