I want to make a shopify theme using react.
You have a bunch of template files that have access to global server-side variables with liquid e.g. {{ product.title }}
. Think wordpress or any other theme-based system.
/theme
/template
/index.liquid
/products.liquid
- Because this site is hosted on Shopify I don't have access to the server to render out react on the server dynamically.
- Because this is an e-commerce store I can't have pages not be rendered server side, for SEO reasons.
- I need to programmatically generate all of the pages in the template with react
render
locally, each template would have a component.
It's simple enough to pass the string versions of liquid variables to a component. What I'm not sure of is how to differentiate the props / components that are render out saved within a template and the instance of react in javascript that is running on the site. When the client runs react if the liquid variables are the default properties all the valued server-side variables will be converted to their string / variable counterpart this isn't what we want. React doesn't have the data, this is bad.
To fix this I thought about having two sets of properties, one getLiquidProps
that will be utilized when I call something like renderLiquid()
. Similar to the way react-async works. However what I really need is a way to read the existing values that the server wrote to the DOM and have those values be the component props. But this is us using the react server DOM as our datastore is this possible?
If I have a simple component for cart counter:
var CartCount = React.createClass({
getDefaultProps: function(){
return {
"count": '{{ cart.item_count }}'
}
},
render: function() {
return (
<div className="cartCount">
{ this.props.count }
</div>
)
}
});
The server will render
<div className="cartCount">
3
</div>
The client-side react will overwrite it again
<div className="cartCount">
{ this.props.count }
</div>
Transpiling React code into Liquid is pretty darn hard as Liquid has completely different concepts of e.g. looping over collections, generating HTML tags etc.
I launched a b2b shop (unfortunately non-public) a couple of months ago that uses SSR with React and a technique similar to the one shared by @reggi. I didn't reach feature parity between server-side and client-side templates but this is — so far — better than nothing.
I used https://github.com/postcss/postcss-url for changing all referenced image URLs to Liquid's
asset_url
tags and some custom gulp scripts to move statically rendered routes like/account/login
,collection
andproduct
to the respective Liquid files (templates/customers/login.liquid
etc.).For local staging, I grabbed all data I could from Shopify's JSON API, cached it locally and rendered the generated Liquid templates using Koa as local server. To achieve that, I had to implement a couple of Shopify's custom liquid filters in JS and re-organise the JSON data a bit. All of that code is extremely untidy so there won't be any open source library soon. If I should end up developing more shops with that dev setup, I will have to clean things as builds are somehow sluggish (incremental: ~2s, full build: ~50s).
HMA on Twitter (@dlindenkreuz) if you want to know more ¯_(ツ)_/¯