How do you create an app that renders in the store's frontend? From what I can gather from the docs, the Storefront API simply allows you to inject a script from your Shopify instance. There are two issues I have with this, but please correct me if my understanding is incorrect.
1. Injecting a script isn't scalable. JQuery is dead. If I'm going to create a complex widget like a messaging component for customer service, a script will not cut it. I need a full frontend framework, and to my knowledge you can't just bundle a single component from a frontend framework for injection elsewhere.
2. How on earth do people handle different themes where all the class names and id attributes etc. are different from theme to theme? How do you select components to bind to and interact with?
How do you create an app that renders in the store's frontend?
Traditionally this has been done using the script tag: https://shopify.dev/docs/admin-api/rest/reference/online-store/scripttag
I need a full frontend framework, and to my knowledge you can't just bundle a single component from a frontend framework for injection elsewhere.
You'll need to use a tool to bundle your framework + App files for distribution. We use https://webpack.js.org/
One thing to be cognizant of nowadays is the impact of the Lighthouse performance report available to merchants to test their storefront loading speed. Techniques such as code splitting to optimize the performance and loading of your app can help a lot.
How on earth do people handle different themes where all the class names and id attributes etc. are different from theme to theme? How do you select components to bind to and interact with?
It is a right royal PITA to be sure. Plus over time you'll need to maintain it as new versions of the theme are released which often change the markup/behaviour. There are some heuristics you can use generally, but there is no nice solution to this problem and you'll end up sprinkling in bits and pieces specific to each theme.
There are alternative approaches each with pros/cons. For example I've seen Apps that create an alternate product page template with their code instead of the themes. Other Apps are using iframes to avoid JS and CSS conflicts.
Thanks for your reply. Just wanted to ask a couple clarifying questions.
1. Is webpack truly the best choice? I've looked into Parcel and it seems to handle code splitting without any configuration.
2. Even if you have a component won't you have to import React/ReactDOM (in the case of React) in order to actually mount it with ReactDOM.render (https://reactjs.org/docs/add-react-to-a-website.html)
3. If your app is paid, using the script API with a public static JS file is a bad idea no? How would you distribute it in a protected manner?
Is webpack truly the best choice?
We've been using it for a while and it has been doing a pretty good job for us. So much so that we haven't bothered to look for anything else.
won't you have to import React/ReactDOM (in the case of React) in order to actually mount it with ReactDOM.render
Yep. Anything your app requires would need to be bundled.
If you are worried about the bundle size, take a look at https://preactjs.com/
How would you distribute it in a protected manner?
Fun story: we once had a developer completely steal our client side code and sell it back to the merchant as a new and improved version of our App, but forgetting to change the API endpoints pointing to our servers. While they were developing their 'new' App the merchant reported an issue with our existing App. It was caused by.... You guessed it - changes made to our ripped off copy. The merchant fired them immediately after I pointed out the dodgy behaviour.
Not sure what you mean by this.
The script is loaded from your server. An attacker could not load a modified version of your file unless they have access to the theme and bypass the script loading mechanism Shopify uses.
I guess technically there might be some sort of MITM attack vector that I'm not aware of. If you were worried about that I'd suggest using an App Proxy as the script tag src.