Skip to content

Commit e94c94e

Browse files
vctrchuclaude
andcommitted
Normalize paths in bundle-ui-step same-path guard
The same-path guard at bundle-ui-step.ts compared `localOutputDir` and `bundleOutputDir` as raw strings. In practice these two values are computed along different code paths (`dirname(buildUIExtension())` vs `dirname(extension.outputPath)` or `joinPath(..., bundleFolder)`) and can resolve to the same filesystem directory while differing as strings — e.g. when one path has a `.` segment, a trailing slash, or otherwise non-canonical shape. When that happens, the guard slips through and fs-extra rejects the copy with "Source and destination must not be the same". Normalize both sides via `resolvePath` before comparing so the guard catches any string variant that maps to the same directory. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 243750a commit e94c94e

2 files changed

Lines changed: 7 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/app': patch
3+
---
4+
5+
Fix `shopify app build` intermittently failing with "Source and destination must not be the same" on UI extensions when the local esbuild output directory and the bundle output directory resolve to the same path but differ as strings (e.g. due to `.` segments, trailing slashes, or path joining quirks). The same-path guard now normalizes both paths via `resolvePath` before comparison.

packages/app/src/cli/services/build/steps/bundle-ui-step.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {createOrUpdateManifestFile} from './include-assets/generate-manifest.js'
22
import {buildUIExtension} from '../extension.js'
33
import {BuildManifest} from '../../../models/extensions/specifications/ui_extension.js'
44
import {copyFile} from '@shopify/cli-kit/node/fs'
5-
import {dirname, joinPath} from '@shopify/cli-kit/node/path'
5+
import {dirname, joinPath, resolvePath} from '@shopify/cli-kit/node/path'
66
import type {BundleUIStep, BuildContext} from '../client-steps.js'
77

88
interface ExtensionPointWithBuildManifest {
@@ -27,7 +27,7 @@ export async function executeBundleUIStep(step: BundleUIStep, context: BuildCont
2727
const bundleOutputDir = step.config?.bundleFolder
2828
? joinPath(dirname(context.extension.outputPath), step.config.bundleFolder)
2929
: dirname(context.extension.outputPath)
30-
if (localOutputDir !== bundleOutputDir) {
30+
if (resolvePath(localOutputDir) !== resolvePath(bundleOutputDir)) {
3131
await copyFile(localOutputDir, bundleOutputDir)
3232
}
3333

0 commit comments

Comments
 (0)