diff --git a/packages/app/src/cli/services/build/extension.ts b/packages/app/src/cli/services/build/extension.ts index 97e8eca8f7..15911fa028 100644 --- a/packages/app/src/cli/services/build/extension.ts +++ b/packages/app/src/cli/services/build/extension.ts @@ -161,13 +161,18 @@ export async function buildFunctionExtension( await runTrampoline(extension.outputPath) } + const projectOutputPath = joinPath(extension.directory, extension.outputRelativePath) + if ( fileExistsSync(extension.outputPath) && bundlePath !== extension.outputPath && + bundlePath !== projectOutputPath && dirname(bundlePath) !== dirname(extension.outputPath) ) { + // Bundle build for deploy: base64-encode into the bundle directory await bundleFunctionExtension(extension.outputPath, bundlePath) } + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { // To avoid random user-code errors being reported as CLI bugs, we capture and rethrow them as AbortError. diff --git a/packages/app/src/cli/services/function/info.test.ts b/packages/app/src/cli/services/function/info.test.ts index 8c44aa96cf..1bfd70a239 100644 --- a/packages/app/src/cli/services/function/info.test.ts +++ b/packages/app/src/cli/services/function/info.test.ts @@ -49,6 +49,52 @@ describe('functionInfo', () => { expect(parsed).toHaveProperty('apiVersion') }) + test('uses build.path from config for wasmPath when present', async () => { + // Given + const funcWithBuildPath = await testFunctionExtension({ + dir: '/path/to/function', + config: { + name: 'My Function', + type: 'function', + handle: 'my-function', + api_version: '2024-01', + configuration_ui: false, + build: { + path: 'custom/output.wasm', + wasm_opt: false, + }, + }, + }) + const options = { + format: 'json' as const, + functionRunnerPath: '/path/to/runner', + schemaPath: '/path/to/schema.graphql', + } + + // When + const result = functionInfo(funcWithBuildPath, options) + + // Then + const parsed = JSON.parse(result as string) + expect(parsed.wasmPath).toBe('/path/to/function/custom/output.wasm') + }) + + test('falls back to outputRelativePath when build.path is not set', async () => { + // Given + const options = { + format: 'json' as const, + functionRunnerPath: '/path/to/runner', + schemaPath: '/path/to/schema.graphql', + } + + // When + const result = functionInfo(ourFunction, options) + + // Then + const parsed = JSON.parse(result as string) + expect(parsed.wasmPath).toBe(ourFunction.outputPath) + }) + test('returns AlertCustomSection array when format is text', async () => { // Given const options = { @@ -174,7 +220,15 @@ describe('functionInfo', () => { } // When - const result = formatAsJson(testFunc, config, targeting, '/path/to/runner', '/path/to/schema.graphql') + const functionOutputPath = '/path/to/function/output.wasm' + const result = formatAsJson( + testFunc, + config, + targeting, + '/path/to/runner', + functionOutputPath, + '/path/to/schema.graphql', + ) // Then const parsed = JSON.parse(result) @@ -189,7 +243,7 @@ describe('functionInfo', () => { }, }, schemaPath: '/path/to/schema.graphql', - wasmPath: testFunc.outputPath, + wasmPath: functionOutputPath, functionRunnerPath: '/path/to/runner', }) }) @@ -209,7 +263,7 @@ describe('functionInfo', () => { const targeting = {} // When - const result = formatAsJson(testFunc, config, targeting, '/path/to/runner') + const result = formatAsJson(testFunc, config, targeting, '/path/to/runner', 'path/to/function.wasm', undefined) // Then const parsed = JSON.parse(result) @@ -362,7 +416,14 @@ describe('functionInfo', () => { } // When - const result = buildTextFormatSections(testFunc, config, targeting, '/path/to/runner', '/path/to/schema.graphql') + const result = buildTextFormatSections( + testFunc, + config, + targeting, + '/path/to/runner', + '/path/to/function/output.wasm', + '/path/to/schema.graphql', + ) // Then // configuration, targeting, build, function runner diff --git a/packages/app/src/cli/services/function/info.ts b/packages/app/src/cli/services/function/info.ts index 3abc7d3d5c..5c1261adef 100644 --- a/packages/app/src/cli/services/function/info.ts +++ b/packages/app/src/cli/services/function/info.ts @@ -1,5 +1,6 @@ import {ExtensionInstance} from '../../models/extensions/extension-instance.js' import {outputContent, outputToken} from '@shopify/cli-kit/node/output' +import {joinPath} from '@shopify/cli-kit/node/path' import {InlineToken, AlertCustomSection} from '@shopify/cli-kit/node/ui' type Format = 'json' | 'text' @@ -14,6 +15,9 @@ interface FunctionConfiguration { handle?: string name?: string api_version?: string + build?: { + path?: string + } targeting?: { target: string input_query?: string @@ -42,6 +46,7 @@ export function formatAsJson( config: FunctionConfiguration, targeting: {[key: string]: {inputQueryPath?: string; export?: string}}, functionRunnerPath: string, + functionOutputPath: string, schemaPath?: string, ): string { return JSON.stringify( @@ -51,7 +56,7 @@ export function formatAsJson( apiVersion: config.api_version, targeting, schemaPath, - wasmPath: ourFunction.outputPath, + wasmPath: functionOutputPath, functionRunnerPath, }, null, @@ -127,6 +132,7 @@ export function buildTextFormatSections( config: FunctionConfiguration, targeting: {[key: string]: {inputQueryPath?: string; export?: string}}, functionRunnerPath: string, + functionOutputPath: string, schemaPath?: string, ): AlertCustomSection[] { const sections: AlertCustomSection[] = [buildConfigurationSection(config, ourFunction.name)] @@ -136,7 +142,7 @@ export function buildTextFormatSections( sections.push(targetingSection) } - sections.push(buildBuildSection(ourFunction.outputPath, schemaPath), buildFunctionRunnerSection(functionRunnerPath)) + sections.push(buildBuildSection(functionOutputPath, schemaPath), buildFunctionRunnerSection(functionRunnerPath)) return sections } @@ -150,9 +156,11 @@ export function functionInfo( const targeting = buildTargetingData(config, ourFunction.directory) + const functionOutputPath = joinPath(ourFunction.directory, config.build?.path ?? ourFunction.outputRelativePath) + if (format === 'json') { - return formatAsJson(ourFunction, config, targeting, functionRunnerPath, schemaPath) + return formatAsJson(ourFunction, config, targeting, functionRunnerPath, functionOutputPath, schemaPath) } - return buildTextFormatSections(ourFunction, config, targeting, functionRunnerPath, schemaPath) + return buildTextFormatSections(ourFunction, config, targeting, functionRunnerPath, functionOutputPath, schemaPath) }