Skip to content

Commit cd41af8

Browse files
committed
Add more detailed bundling error descriptions
1 parent 8fa8036 commit cd41af8

File tree

4 files changed

+83
-11
lines changed

4 files changed

+83
-11
lines changed

.changeset/shiny-jobs-wave.md

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+
Report bundling errors

packages/app/src/cli/services/build/extension.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,11 @@ export async function buildUIExtension(extension: ExtensionInstance, options: Ex
128128
)
129129
}
130130
} catch (extensionBundlingError) {
131-
// this fails if the app's own source code is broken; wrap such that this isn't flagged as a CLI bug
131+
// The bundleExtension function already wrote formatted errors to stderr
132+
// when esbuild errors occurred, so we just need to throw a user-friendly error
132133
throw new AbortError(
133-
`Failed to bundle extension ${extension.localIdentifier}. Please check the extension source code for errors.`,
134+
`Failed to bundle extension ${extension.localIdentifier}.`,
135+
'Please check the extension source code for errors.',
134136
)
135137
}
136138

packages/app/src/cli/services/extensions/bundle.test.ts

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ describe('bundleExtension()', () => {
4545
})
4646
const esbuildWatch = vi.fn()
4747
const esbuildDispose = vi.fn()
48-
const esbuildRebuild = vi.fn(esbuildResultFixture)
48+
const esbuildRebuild = vi.fn(esbuildSuccessResultFixture)
4949

5050
vi.mocked(esContext).mockResolvedValue({
5151
rebuild: esbuildRebuild,
@@ -139,7 +139,7 @@ describe('bundleExtension()', () => {
139139
})
140140
const esbuildWatch = vi.fn()
141141
const esbuildDispose = vi.fn()
142-
const esbuildRebuild = vi.fn(esbuildResultFixture)
142+
const esbuildRebuild = vi.fn(esbuildSuccessResultFixture)
143143

144144
vi.mocked(esContext).mockResolvedValue({
145145
rebuild: esbuildRebuild,
@@ -179,28 +179,88 @@ describe('bundleExtension()', () => {
179179
expect(plugins).not.toContain('shopify:deduplicate-react')
180180
})
181181

182-
async function esbuildResultFixture() {
182+
test('throws error when bundling fails and displays formatted errors', async () => {
183+
// Given
184+
const extension = await testUIExtension()
185+
const stdout: any = {
186+
write: vi.fn(),
187+
}
188+
const stderr: any = {
189+
write: vi.fn(),
190+
}
191+
const app = testApp({
192+
directory: '/project',
193+
allExtensions: [extension],
194+
})
195+
const esbuildWatch = vi.fn()
196+
const esbuildDispose = vi.fn()
197+
const esbuildRebuild = vi.fn(esbuildErrorResultFixture)
198+
199+
vi.mocked(esContext).mockResolvedValue({
200+
rebuild: esbuildRebuild,
201+
watch: esbuildWatch,
202+
dispose: esbuildDispose,
203+
cancel: vi.fn(),
204+
serve: vi.fn(),
205+
})
206+
207+
// When/Then
208+
await expect(
209+
bundleExtension({
210+
env: {},
211+
outputPath: extension.outputPath,
212+
minify: true,
213+
environment: 'production',
214+
stdin: {
215+
contents: 'console.log("mock stdin content")',
216+
resolveDir: 'mock/resolve/dir',
217+
loader: 'tsx',
218+
},
219+
stdout,
220+
stderr,
221+
}),
222+
).rejects.toThrow('ESBuild bundling failed')
223+
224+
// Verify errors were written to stderr
225+
const errorOutput = vi.mocked(stderr.write).mock.calls[0][0] as string
226+
expect(errorOutput).toMatch(/[X] \[ERROR\] error text \[plugin plugin\]/)
227+
})
228+
229+
async function esbuildSuccessResultFixture() {
183230
return {
184-
errors: [
231+
errors: [],
232+
warnings: [
185233
{
186-
id: 'error',
234+
id: 'warning',
187235
pluginName: 'plugin',
188-
text: 'error text',
236+
text: 'warning text',
189237
location: null,
190238
notes: [],
191239
detail: {},
192240
},
193241
],
194-
warnings: [
242+
outputFiles: [],
243+
metafile: {
244+
inputs: {},
245+
outputs: {},
246+
},
247+
mangleCache: {},
248+
}
249+
}
250+
251+
async function esbuildErrorResultFixture() {
252+
return {
253+
errors: [
195254
{
196-
id: 'warning',
255+
id: 'error',
197256
pluginName: 'plugin',
198-
text: 'warning text',
257+
text: 'error text',
199258
location: null,
200259
notes: [],
201260
detail: {},
202261
},
203262
],
263+
warnings: [],
204264
outputFiles: [],
205265
metafile: {
206266
inputs: {},

packages/app/src/cli/services/extensions/bundle.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ export async function bundleExtension(options: BundleOptions, processEnv = proce
6060
const result = await context.rebuild()
6161
onResult(result, options)
6262
await context.dispose()
63+
64+
// If there were errors, throw an error so the caller can handle it
65+
if (result.errors && result.errors.length > 0) {
66+
throw new Error('ESBuild bundling failed')
67+
}
6368
}
6469

6570
export async function bundleThemeExtension(

0 commit comments

Comments
 (0)