Skip to content

[Feature] Add Theme previews via JSON#6890

Open
dengjeffrey wants to merge 6 commits intomainfrom
jd/quick-preview
Open

[Feature] Add Theme previews via JSON#6890
dengjeffrey wants to merge 6 commits intomainfrom
jd/quick-preview

Conversation

@dengjeffrey
Copy link

@dengjeffrey dengjeffrey commented Feb 24, 2026

WHY are these changes introduced?

Resolves https://github.com/shop/issues-growth-activation/issues/1902

WHAT is this pull request doing?

  1. Adds additional flags to theme dev to support temporarily overriding a theme via JSON and being able to preview it

More internal context: https://docs.google.com/document/d/13sa0iRs_DSgyPHbx9IIF64rvhh_KZCDLfJgwpSIxP4A/edit?usp=sharing

--source allows for either a theme directory or a JSON. We will document the JSON schema on shopify.dev
--preview-id specifies an existing preview session to be updated with the JSON value in source

How to test your changes?

Requires https://app.graphite.com/github/pr/shop/world/448726/Add-ThemePreviewController-to-support-Shopify-CLI-theme-previews

Post-release steps

  • [] Add documentation on shopify.dev

Measuring impact

How do we know this change was effective? Please choose one:

  • n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix
  • Existing analytics will cater for this addition
  • PR includes analytics changes to measure impact

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes

@github-actions
Copy link
Contributor

github-actions bot commented Feb 24, 2026

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements 79.6% 14499/18214
🟡 Branches 73.94% 7195/9731
🟡 Functions 79.78% 3693/4629
🟡 Lines 79.96% 13710/17146

Test suite run success

3731 tests passing in 1443 suites.

Report generated by 🧪jest coverage report action from fedff6f

@dengjeffrey dengjeffrey force-pushed the jd/quick-preview branch 3 times, most recently from 2adb0f2 to 06454b5 Compare February 24, 2026 23:20
@dengjeffrey dengjeffrey changed the title Jd/quick preview [Feature] Add Theme previews via JSON Feb 25, 2026
devFlags.path = resolvedSource
} else {
recordEvent('theme-command:dev:override-session')
await createOverrideDevSession(resolvedSource, devFlags, adminSession)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this same pattern here to "create" a dev session even if we don't have a long running process yet. This will make it trivial to add hot reloading.

@dengjeffrey dengjeffrey requested a review from karreiro February 25, 2026 17:57
@dengjeffrey dengjeffrey marked this pull request as ready for review February 25, 2026 18:03
@dengjeffrey dengjeffrey requested review from a team as code owners February 25, 2026 18:03
@github-actions

This comment has been minimized.

@github-actions
Copy link
Contributor

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/private/node/session.d.ts
@@ -31,7 +31,7 @@ interface AppManagementAPIOauthOptions {
 /**
  * A scope supported by the Storefront Renderer API.
  */
-export type StorefrontRendererScope = 'devtools';
+export type StorefrontRendererScope = 'devtools' | 'graphql';
 interface StorefrontRendererAPIOAuthOptions {
     /** List of scopes to request permissions for. */
     scopes: StorefrontRendererScope[];

Copy link
Contributor

@karreiro karreiro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this PR, @dengjeffrey!

This feature is going to be really useful for developers — it feels like something they could use as a building block to create interesting things on top of.

I've left some comments. Once we tophat this, I'll revisit the review, try things end-to-end, and approve.

Thanks again!

}

const fileContent = await readFile(options.overrideJson)
const overrides = JSON.parse(fileContent) as ThemeOverrides
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May we handle JSON parser errors here?

description:
'The source for the dev server. Can be a directory or a JSON overrides file. When a directory is provided, it is used as the theme directory. When a JSON file is provided, overrides are applied to the theme specified by --theme.',
env: 'SHOPIFY_FLAG_SOURCE',
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While reviewing the flags for this command, I noticed we already have --path, so there are two options:

  1. When --source is empty, document that the command uses the file system as the source and relies on --path.
  2. Remove --source in favor of --path, allowing you to pass either a --path or an override file as a parameter.

I think option 2 is the cleaner approach. What do you think?

Comment on lines +150 to +154
'preview-id': Flags.string({
description:
'An existing preview identifier to update instead of creating a new preview. Used with --source when pointing to a JSON overrides file.',
env: 'SHOPIFY_FLAG_PREVIEW_ID',
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When reading this as a user, I immediately wondered how I would get a --preview-id. I think we could mention that --preview-id is an optional field that you may get from previous preview runs.

/**
* A scope supported by the Storefront Renderer API.
*/
export type StorefrontRendererScope = 'devtools'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferring review of this line to the @Shopify/app-inner-loop team, as they implemented the storefront renderer scopes and have more context on this area.

overridesContent,
}: CreateThemePreviewOptions): Promise<ThemePreviewResult> {
recordTiming('theme-preview:create')
const baseUrl = buildBaseStorefrontUrl(session)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you have a chance to tophat this using the Theme Access app?

I wonder if changes will be required there to support the new API call. I think it should work out of the box, but worth double-checking (specially from scopes perspective).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants