Skip to content
Draft
Show file tree
Hide file tree
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
36 changes: 32 additions & 4 deletions packages/app/src/cli/services/build/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {beforeEach, describe, expect, test, vi} from 'vitest'
import {exec} from '@shopify/cli-kit/node/system'
import lockfile from 'proper-lockfile'
import {AbortError} from '@shopify/cli-kit/node/error'
import {fileExistsSync, touchFile, writeFile} from '@shopify/cli-kit/node/fs'
import {copyFile, fileExistsSync, touchFile, writeFile} from '@shopify/cli-kit/node/fs'
import {joinPath} from '@shopify/cli-kit/node/path'

vi.mock('@shopify/cli-kit/node/system')
Expand Down Expand Up @@ -418,7 +418,32 @@ describe('buildFunctionExtension', () => {
expect(runWasmOpt).toHaveBeenCalled()
})

test('does not rebundle when build.path stays in the default output directory', async () => {
test('copies raw binary (not base64) to dist/index.wasm when build.path is in a different dir (standalone build)', async () => {
// Given
extension.configuration.build!.path = 'target/wasm32-wasi/release/my_func.wasm'
vi.mocked(fileExistsSync).mockReturnValue(true)

// When
await expect(
buildFunctionExtension(extension, {
stdout,
stderr,
signal,
app,
environment: 'production',
}),
).resolves.toBeUndefined()

// Then: copyFile is used (raw binary copy), NOT base64 bundling via touchFile/writeFile
expect(copyFile).toHaveBeenCalledWith(
joinPath(extension.directory, 'target/wasm32-wasi/release/my_func.wasm'),
joinPath(extension.directory, 'dist', 'index.wasm'),
)
expect(touchFile).not.toHaveBeenCalled()
expect(writeFile).not.toHaveBeenCalled()
})

test('copies raw binary to dist/index.wasm when build.path stays in the default output directory', async () => {
// Given
extension.configuration.build!.path = 'dist/custom.wasm'
vi.mocked(fileExistsSync).mockReturnValue(true)
Expand All @@ -434,8 +459,11 @@ describe('buildFunctionExtension', () => {
}),
).resolves.toBeUndefined()

// Then
expect(fileExistsSync).toHaveBeenCalledWith(joinPath(extension.directory, 'dist/custom.wasm'))
// Then: copyFile is used (raw binary copy), NOT base64 bundling via touchFile/writeFile
expect(copyFile).toHaveBeenCalledWith(
joinPath(extension.directory, 'dist/custom.wasm'),
joinPath(extension.directory, 'dist', 'index.wasm'),
)
expect(touchFile).not.toHaveBeenCalled()
expect(writeFile).not.toHaveBeenCalled()
})
Expand Down
19 changes: 12 additions & 7 deletions packages/app/src/cli/services/build/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {AbortError, AbortSilentError} from '@shopify/cli-kit/node/error'
import lockfile from 'proper-lockfile'
import {dirname, joinPath} from '@shopify/cli-kit/node/path'
import {outputDebug} from '@shopify/cli-kit/node/output'
import {readFile, touchFile, writeFile, fileExistsSync} from '@shopify/cli-kit/node/fs'
import {copyFile, readFile, touchFile, writeFile, fileExistsSync} from '@shopify/cli-kit/node/fs'
import {Writable} from 'stream'

export interface ExtensionBuildOptions {
Expand Down Expand Up @@ -161,12 +161,17 @@ export async function buildFunctionExtension(
await runTrampoline(extension.outputPath)
}

if (
fileExistsSync(extension.outputPath) &&
bundlePath !== extension.outputPath &&
dirname(bundlePath) !== dirname(extension.outputPath)
) {
await bundleFunctionExtension(extension.outputPath, bundlePath)
if (fileExistsSync(extension.outputPath) && bundlePath !== extension.outputPath) {
const projectOutputPath = joinPath(extension.directory, extension.outputRelativePath)
if (bundlePath === projectOutputPath) {
// Standalone build (e.g. `shopify app build`): copy raw binary to dist/index.wasm so
// vitest and other local tooling can load the wasm directly.
await copyFile(extension.outputPath, bundlePath)
} else if (dirname(bundlePath) !== dirname(extension.outputPath)) {
// Bundle build for deploy: base64-encode into the bundle directory to satisfy the
// server-side contract of uploaded_files["dist/index.wasm"].
await bundleFunctionExtension(extension.outputPath, bundlePath)
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
Expand Down
Loading