Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion packages/taro-platform-h5/src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,16 @@ export default class H5 extends TaroPlatformWeb {
const viteCompilerContext = await getViteH5CompilerContext(this)
if (viteCompilerContext) {
const exts = Array.from(new Set(viteCompilerContext.frameworkExts.concat(SCRIPT_EXT)))
if (id.startsWith(viteCompilerContext.sourceDir) && exts.some((ext) => id.includes(ext))) {
let cleanId = id

if (cleanId.startsWith('\u0000')) {
cleanId = cleanId.slice(1)
}

cleanId = cleanId.split('?')[0].replace(/\\/g, '/') // 👈 替换斜杠方向

const normalizedSourceDir = viteCompilerContext.sourceDir.replace(/\\/g, '/') // 👈 替换斜杠方向
if (cleanId.startsWith(normalizedSourceDir) && exts.some((ext) => id.includes(ext))) {
Comment on lines +233 to +236
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

用路径边界判断与基于 cleanId 的后缀匹配,避免误判与平台差异

当前仍然存在两处潜在问题:

  • 目录前缀误判:cleanId.startsWith(normalizedSourceDir) 在 sourceDir 是另一路径前缀时会误命中(如 C:/src 与 C:/src2)。
  • 扩展名匹配:仍用原始 id.includes(ext) 且为包含匹配,可能出现误判;亦未与上面的 cleanId 清洗保持一致。

建议在本段内改为“边界安全的目录判断 + 基于 cleanId 的结尾扩展匹配”,示例 diff 如下:

-              cleanId = cleanId.split('?')[0].replace(/\\/g, '/') // 👈 替换斜杠方向
+              // 统一斜杠并去掉查询参数,便于跨平台匹配
+              cleanId = cleanId.split('?')[0].replace(/\\/g, '/')

-              const normalizedSourceDir = viteCompilerContext.sourceDir.replace(/\\/g, '/') // 👈 替换斜杠方向
-              if (cleanId.startsWith(normalizedSourceDir) && exts.some((ext) => id.includes(ext))) {
+              // 统一 sourceDir,并确保以路径边界比较,避免前缀相似导致的误命中
+              const normalizedSourceDir = viteCompilerContext.sourceDir.replace(/\\/g, '/').replace(/\/+$/, '')
+              const inSource = cleanId === normalizedSourceDir || cleanId.startsWith(normalizedSourceDir + '/')
+
+              // 更稳健的扩展名判断:基于 cleanId 且只匹配结尾
+              const extsPattern = new RegExp(`\\.(?:${exts.map((e: string) => e.replace(/^\\./, '')).join('|')})$`, 'i')
+
+              if (inSource && extsPattern.test(cleanId)) {

这样可同时解决:

  • Windows 路径前缀误匹配;
  • 查询参数与分隔符已清洗,扩展名判断与之保持一致;
  • 降低 includes 带来的误匹配风险。
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cleanId = cleanId.split('?')[0].replace(/\\/g, '/') // 👈 替换斜杠方向
const normalizedSourceDir = viteCompilerContext.sourceDir.replace(/\\/g, '/') // 👈 替换斜杠方向
if (cleanId.startsWith(normalizedSourceDir) && exts.some((ext) => id.includes(ext))) {
// 统一斜杠并去掉查询参数,便于跨平台匹配
cleanId = cleanId.split('?')[0].replace(/\\/g, '/')
// 统一 sourceDir,并确保以路径边界比较,避免前缀相似导致的误命中
const normalizedSourceDir = viteCompilerContext.sourceDir
.replace(/\\/g, '/')
.replace(/\/+$/, '')
const inSource =
cleanId === normalizedSourceDir ||
cleanId.startsWith(normalizedSourceDir + '/')
// 更稳健的扩展名判断:基于 cleanId 且只匹配结尾
const extsPattern = new RegExp(
`\\.(?:${exts
.map((e: string) => e.replace(/^\./, ''))
.join('|')})$`,
'i'
)
if (inSource && extsPattern.test(cleanId)) {
🤖 Prompt for AI Agents
In packages/taro-platform-h5/src/program.ts around lines 233 to 236, the current
check using cleanId.startsWith(normalizedSourceDir) can cause false positives
when sourceDir is a prefix of another path, and the extension check uses
id.includes(ext) which is an imprecise substring match. To fix this, replace the
startsWith check with a boundary-safe directory comparison (e.g., ensure the
character after normalizedSourceDir in cleanId is a path separator or the string
ends) and change the extension check to use cleanId.endsWith(ext) to accurately
match file extensions after cleaning the path. This ensures correct path prefix
matching and precise extension validation.

💡 Verification agent

🧩 Analysis chain

建议对全仓库同类判定做一致性巡检

为避免类似 Windows 路径问题在其它插件/分支重复出现,建议巡检是否还有基于 id.startsWith(sourceDir) 的直接字符串比较,并统一采用“清洗 + 路径边界 + 扩展名后缀”的写法。

可用以下脚本在仓库检索潜在位置,人工复核是否需要采用同样规范化处理:


🏁 Script executed:

#!/bin/bash
# 搜索基于 sourceDir 的 startsWith 判定
rg -n --no-heading "startsWith\\(.*sourceDir" -A 2 -B 2

# 搜索对 id 的扩展名 includes 判定
rg -n --no-heading "exts\\.some\\(.*id\\.includes\\(" -A 2 -B 2

# 搜索 Vite 插件 transform 中对 id 的处理(便于发现未清洗的地方)
rg -n --no-heading "async?\\s+transform\\s*\\(code,\\s*id\\)" -A 20 -B 2

Length of output: 6180


统一路径前缀匹配时的清洗及后缀校验
为避免 Windows 下反斜杠和 query 参数导致匹配失效,全仓库所有基于 sourceDirstartsWith 判定都应按以下流程处理:

  1. 去除特殊前缀(如 \u0000)和 ? 及后续参数
  2. 将所有 \ 统一替换为 /
  3. 使用清洗后的路径做 startsWith(normalizedSourceDir),并尽量结合路径边界(如 normalizedSourceDir + '/'
  4. 再做扩展名后缀过滤(exts.some(ext => cleanId.endsWith(ext))

以下位置需同样引入该规范化处理:

  • packages/taro-vite-runner/src/harmony/babel.ts(transform 钩子中对 id.startsWith(viteCompilerContext.sourceDir) 及后续 exts.some(id.includes)
  • packages/taro-vite-runner/src/h5/config.ts(entryFileNames 中对 facadeModuleId.startsWith(sourceDir) 的判断)
  • (packages/taro-platform-h5/src/program.ts 已按规范处理,无需改动)

可用脚本复核并定位所有潜在场景:

rg -n --no-heading "startsWith\\(.*sourceDir" -A2 -B2
rg -n --no-heading "facadeModuleId\\?\\.startsWith" -A2 -B2
🤖 Prompt for AI Agents
In packages/taro-vite-runner/src/harmony/babel.ts and
packages/taro-vite-runner/src/h5/config.ts, locate all instances where sourceDir
is used with startsWith for path prefix matching and ensure the following
normalization steps are applied: first remove special prefixes like \u0000 and
query parameters starting with '?', then replace all backslashes '\' with
forward slashes '/', and use the cleaned path for startsWith checks combined
with a trailing '/' to ensure path boundary correctness. After that, perform
extension suffix filtering using endsWith on the cleaned path. This will align
these files with the normalization approach already implemented in
packages/taro-platform-h5/src/program.ts.

// @TODO 后续考虑使用 SWC 插件的方式实现
const result = await transformAsync(code, {
filename: id,
Expand Down
Loading