Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Themes] PoC Hot Reload for OSE #4908

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open

[Themes] PoC Hot Reload for OSE #4908

wants to merge 21 commits into from

Conversation

frandiox
Copy link
Contributor

@frandiox frandiox commented Nov 22, 2024

wip

Goals: support hot reload for Online Store Editor and Theme Preview.

The changes in this repo are:

  • Move the hot reload decisions from the server to the client. For example, instead of sending an event for "CSS update" from the server to the client, now the server sill simply say "here, this file has been changed". The client will check the extension of the file and decide to perform a CSS update, or something else.
  • The server now emits 2 events per file: once when the file is updated locally, and another one when it's uploaded to the cloud. This means that the client can choose to refresh earlier or later, depending of what it needs. For example, when running on localhost, hot reload will happen as soon as a file is updated locally because we can access the content. However, in OSE, we will wait for the "cloud sync" event before triggering a refresh.
  • Implement handling for events in the client for multiple situations: CLI, OSE, Theme Preview.

Copy link
Contributor

github-actions bot commented Nov 22, 2024

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
74.53% (-0.71% 🔻)
8540/11459
🟡 Branches
70.31% (-0.29% 🔻)
4165/5924
🟡 Functions
74.06% (-0.77% 🔻)
2241/3026
🟡 Lines
75.07% (-0.73% 🔻)
8077/10759
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🟢
... / bundler.ts
100% 100% 100% 100%
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟢
... / app.test-data.ts
91.44% (-1.07% 🔻)
93.4%
81.25% (-2.5% 🔻)
90.86% (-1.14% 🔻)
🟢
... / release.ts
93.33%
58.33% (-11.67% 🔻)
75% 92.86%
🟢
... / extension-to-toml.ts
77.78% (-10.46% 🔻)
75% 100% 100%
🟢
... / app-event-watcher.ts
90.67% (-4.07% 🔻)
80% (-10.91% 🔻)
90.48%
95.52% (-3.01% 🔻)
🟢
... / app-watcher-esbuild.ts
83.33% (-5.56% 🔻)
87.5%
80% (-6.67% 🔻)
87.88% (-6.06% 🔻)
🔴
... / dev-session.ts
4.21% (-81.75% 🔻)
0% (-68.33% 🔻)
4.35% (-87.32% 🔻)
4.76% (-88.17% 🔻)
🟢
... / binaries.ts
96.36% (+0.98% 🔼)
88% (+2.81% 🔼)
88.89% (-3.97% 🔻)
96.36% (+0.98% 🔼)
🟡
... / build.ts
74.49% (-0.26% 🔻)
61.36% 75.76%
72.22% (-0.31% 🔻)
🟢
... / Replay.tsx
91.67% (-0.33% 🔻)
69.23% 100%
91.3% (-0.36% 🔻)
🔴
... / json-schema.ts
25% (-3% 🔻)
22.22% 33.33%
25% (-3% 🔻)
🔴
... / app-management-client.ts
20.33% (-4.99% 🔻)
9.52% (-3.73% 🔻)
22.11% (-4.49% 🔻)
18.75% (-5.23% 🔻)
🔴
... / environment.ts
15.38% (-6.04% 🔻)
0% (-18.18% 🔻)
33.33% (-9.52% 🔻)
16.67% (-6.41% 🔻)
🟢
... / json-schema.ts
91.67% (-0.19% 🔻)
81.08% (-0.97% 🔻)
100%
91.57% (-0.2% 🔻)
🟡
... / notifications-system.ts
65.52% (-1.15% 🔻)
62.3% (-3.38% 🔻)
88.89% (-0.58% 🔻)
73.61% (-0.71% 🔻)
🟡
... / path.ts
76.67% (-2.64% 🔻)
72.22% (+7.22% 🔼)
75%
77.78% (-2.99% 🔻)

Test suite run success

1946 tests passing in 885 suites.

Report generated by 🧪jest coverage report action from 38bd7c1

@frandiox
Copy link
Contributor Author

/snapit

Copy link
Contributor

🫰✨ Thanks @frandiox! Your snapshot has been published to npm.

Test the snapshot by intalling your package globally:

pnpm i -g @shopify/cli@0.0.0-snapshot-20250110184614

After installing, validate the version by running just shopify in your terminal
If the versions don't match, you might have multiple global instances installed.
Use which shopify to find out which one you are running and uninstall it.

@frandiox frandiox marked this pull request as ready for review January 16, 2025 19:42
@frandiox frandiox requested a review from a team as a code owner January 16, 2025 19:42
Comment on lines +148 to +186
startDataReload: async (signal: AbortSignal) => {
if (!isOSE) return null

// Force OSE to show the loading state
window.dispatchEvent(new Event('pagehide'))

return fetch(window.location.href, {
// Note: enable these properties when we have access to replace_templates
// method: 'POST',
// body: storefrontReplaceTemplatesParams(data.replaceTemplates),
// This is required to get the OnlineStoreEditorData script:
headers: {Accept: 'text/html'},
signal,
})
.then((response) => response.text())
.catch((error) => {
logError('Error fetching full page reload for section settings', error)
return null
})
},
finishDataReload: async (oseDataPromise: Promise<string | null>) => {
if (!isOSE) return null

const refreshedHtml = await oseDataPromise
const newOSEData = new DOMParser()
.parseFromString(refreshedHtml ?? '', 'text/html')
.querySelector('#OnlineStoreEditorData')?.textContent

if (newOSEData) {
const oseDataElement = document.querySelector('#OnlineStoreEditorData')
if (oseDataElement && newOSEData !== oseDataElement.textContent) {
oseDataElement.textContent = newOSEData
logInfo('OSE data updated')
}
}

// OSE reads the new data after the page is loaded
window.dispatchEvent(new Event('load'))
},
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could remove these actions since they are not used yet. Using them is faster but it seems to create some small issues with OSE state.

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, @frandiox 🔥 Amazing work as usual!

I couldn't spot any issues with themes neither theme app extension. Given the nature of this change tho, I'd love to expand these tests even further.

When we feel ready, I believe we can snapit this branch and share a build with our partners to gather their feedback before the release. I'm sure they will love having hot reload on OSE, so we will likely have a wide audience.

Regarding these changes:

  • Move the hot reload decisions from the server to the client. For example, instead of sending an event for "CSS update" from the server to the client, now the server sill simply say "here, this file has been changed". The client will check the extension of the file and decide to perform a CSS update, or something else.

This is very neat. The more I look at the client.ts file, the more it feels like it should be a standalone library. I can see it being a dependency for the CLI and for the OSE/theme-preview, and I can also see third-party tooling being built on top of it.

Having that as a standalone library might also give us more room to separate the logic and version those APIs—keeping in mind that OSE won't have guarantees about the CLI version.

  • The server now emits 2 events per file: once when the file is updated locally, and another one when it's uploaded to the cloud

This is an excellent decision! ✨

Please, let me know your thoughts about this! Thanks again for this PR!

Comment on lines +60 to +62
// - Local preview in the CLI: the URL is like localhost:<port>
// - OSE visual preview: the URL is a myshopify.com domain
// - Theme Preview: the URL is a myshopify.com domain
Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking about these consumers, I believe we could consider extracting this from the CLI and turning client.ts into a standalone package.

For Shopify CLI, it would be a dependency, but having it as a standalone package (and possibly a standalone repository) might help us with bundling and making this asset available for OSE/theme-preview.

Copy link
Contributor Author

@frandiox frandiox Jan 17, 2025

Choose a reason for hiding this comment

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

The thing is, if we inject this in SFR for theme-preview... we would get it automatically injected also in the CLI.
We could always overwrite it at the proxy stage with custom stuff but since we control every part, maybe we can just rely on it? The code connects to the localhost:<port> if available automatically, so it would know it runs under the CLI.

In this case, it almost makes more sense for this client.ts to live in SFR directly? :confused-parrot:
It could still be good to have it as a library to import types I guess? So maybe in theme-tools as theme-hot-reload?

}

export interface HotReloadEventPayload {
isAppExtension?: boolean
Copy link
Contributor

Choose a reason for hiding this comment

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

Generally, we refer to TAEs as theme extensions in the code base, I believe we could rename this to:

Suggested change
isAppExtension?: boolean
isThemeExtension?: boolean

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