React_ujs with Less Page Weight Using gzip

Background: our current state using react_ujs

Our React tools use the react_ujs library to manage the hand-off of a page’s props from the server to the client. The hand-off allows us to have a server-side render so that content appears quickly, but also use the exact same views and props to create rich client side interactions.

It manages this by embedding the props used to create a view into the view as an html data attribute.

Something like this:

[
  {
    "first_name": "John",
    "last_name": "Doe",
    "phone": "5551234567",
    "email": "example@example.com"
  },
  //...
]

becomes:

data-react-props="[{"first_name":"John","last_name":"Doe","phone":"5551234567","email":"example@example.com"}]"

Can we do better?

As we are building the next version of our tools, we are looking for ways to get more efficient. These ujs props are adding a lot of weight to our markup.

I got curious. Could we do better? I thought of a few methods to try:

  • Switch from a double quoted attribute to single (reduce the number of quotes we need to escape– because " is far more common in our JSON than ')
  • gzip the JSON and base64-encode the result (so that it is attribute safe)
  • Use BSON, gzip, and base64-encode.
  • Use MessagePack, gzip and base64-encode.

We can do better!

I ran these different algorithms against a variety of test cases from our apps (some simple, some complex). Here are the results:

react-ujs-compression-results-cropped

As you can see, gzipping the props string dramatically reduces the size for all but the smallest sets of props, even though you have to base64 encode it to be attribute safe. The other methods decreased the payload size, but by a smaller amount.

Other considerations

We would have to add a gzip library to our client JS bundle, but that library is 5.7k unminified. The savings from one heavier set of props exceeds the weight of the library many times over. And the client downloads new JS bundles infrequently, but new props for every page.

I have not yet benchmarked for any impact to render speed, but that is next on my list.

gzip + base64: see you in the next version

We are considering including a new ujs script which uses gzip in the next version of our framework. What do you think? Is there any reason we shouldn’t?

Revelry offers executive advising, design sprints, and custom software development.

Book office hours here.
We’re interested in talented people of all kinds – apply to work with us!