diff --git a/.changeset/theme-extension-build-watch.md b/.changeset/theme-extension-build-watch.md new file mode 100644 index 0000000000..3f985201bf --- /dev/null +++ b/.changeset/theme-extension-build-watch.md @@ -0,0 +1,5 @@ +--- +'@shopify/app': patch +--- + +Theme app extensions now support `[build].watch` in `shopify.extension.toml` to restrict which files trigger bundle rebuilds during `shopify app dev`. This mirrors the behavior already available for function extensions. When `build.watch` is specified, the CLI only reacts to changes in those paths (plus `locales/**.json` and `**.toml`) instead of the entire extension directory, preventing redundant bundle cycles when an external build tool (e.g. Vite) writes multiple output files. diff --git a/packages/app/src/cli/models/extensions/specifications/theme.ts b/packages/app/src/cli/models/extensions/specifications/theme.ts index 8e6d27d27e..f6381275d2 100644 --- a/packages/app/src/cli/models/extensions/specifications/theme.ts +++ b/packages/app/src/cli/models/extensions/specifications/theme.ts @@ -3,13 +3,24 @@ import {BaseSchema} from '../schemas.js' import {themeExtensionFiles} from '../../../utilities/extensions/theme.js' import {ExtensionInstance} from '../extension-instance.js' import {fileSize} from '@shopify/cli-kit/node/fs' -import {dirname, relativePath} from '@shopify/cli-kit/node/path' +import {dirname, joinPath, relativePath} from '@shopify/cli-kit/node/path' import {AbortError} from '@shopify/cli-kit/node/error' import {outputContent, outputToken} from '@shopify/cli-kit/node/output' +import {zod} from '@shopify/cli-kit/node/schema' + +const ThemeExtensionSchema = BaseSchema.extend({ + build: zod + .object({ + watch: zod.union([zod.string(), zod.string().array()]).optional(), + }) + .optional(), +}) + +type ThemeExtensionConfigType = zod.infer const themeSpec = createExtensionSpecification({ identifier: 'theme', - schema: BaseSchema, + schema: ThemeExtensionSchema, partnersWebIdentifier: 'theme_app_extension', graphQLType: 'theme_app_extension', clientSteps: [ @@ -24,6 +35,17 @@ const themeSpec = createExtensionSpecification({ appModuleFeatures: (_) => { return ['theme'] }, + devSessionWatchConfig: (extension: ExtensionInstance) => { + const config = extension.configuration + if (!config.build || !config.build.watch) return undefined + + const paths = [config.build.watch].flat().map((path) => joinPath(extension.directory, path)) + + paths.push(joinPath(extension.directory, 'locales', '**.json')) + paths.push(joinPath(extension.directory, '**.toml')) + + return {paths} + }, deployConfig: async () => { return {theme_extension: {files: {}}} },