Skip to content

Instantly share code, notes, and snippets.

@reggi
Last active January 23, 2022 21:46
Show Gist options
  • Save reggi/73b4a8deffd4e0becbb1 to your computer and use it in GitHub Desktop.
Save reggi/73b4a8deffd4e0becbb1 to your computer and use it in GitHub Desktop.

Templating engines and React.js

I want to make a shopify theme using react.

How shopify theming works

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

SEO

  • 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.

Injecting server-side variables into react

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?

Example

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>
@loicnestler
Copy link

loicnestler commented Aug 12, 2021

Hey!
What would be the 2021 approach of having a hybrid react/liquid shopify storefront?

I had the following idea in mind:
To each .liquid page, add a script tag that server side renders all needed liquid variables into a global JavaScript object (window.data or sth).

window.data = {
    count: '{{ cart.item_count }}',
    // ...
}

Liquid should then take care of rendering all content that is SEO-important (landing pages (?), on the product page the product title, description, ...). React is then only used for things that are rather hard to implement in liquid (such as image slider, variant / amount selectors, ...).

<body>
  <h1>{{ product.title }}</h1>
  <p>{{ product.description }}</p>
  <div id="root"></div>
</body>

What do you think of that?

EDIT:
I'm not that familiar with SEO, but it might even be an approach to first render all SEO-relevant content server side using liquid and then, client side, hide the content and mount a whole react application and not just smaller features as described above.

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