Tumblr Engineering — Tumblr Themes & React and Redux: Part 1


As a platform that prides itself on being a home for artists and creatives alike, it only makes sense that we allow our users to fully customize their Tumblrs to fully express themselves. Here at Tumblr, the world is your oyster not only in terms of looks but also in how you create your theme. I wanted to demonstrate how you too can develop a theme using Redux and React. Since there are plenty of docs and tutorials on how to use those libraries themselves, I will briefly describe how I got the libraries to work with the Tumblr theme engine, and share some handy tips that made developing more efficient and more enjoyable.

If you follow the ever changing landscape of JavaScript, then you’ve at least heard of these two libraries. Prior to building the Post-It-Forward theme, I only knew of them by name but never got the chance to actually use them. Developers couldn’t get enough of how React made it easy to create and reuse components. Many also praise how elegantly React manages and renders views, especially when paired with Redux for state management. All of this sounded great. I wanted to turn this project into a learning experience. I thought, “why not?” and gave it a shot.

An Extremely Brief Introduction to Tumblr Themes

The way themes work on Tumblr is that we have a theme engine that provides special types of operators. These operators insert dynamic data, such as your Tumblr’s title or description, or are blocks that serve as conditionals for rendering a block of HTML, like the “Next Page” link.

My HTML started off a little something like this:

<!DOCTYPE html>
<head>
<title>{Title}</title>
<style></style>
</head>
<body>
<div id="post-it-forward-root"></div>
</body>
</html>

As you can see, {Title} is a variable that will return the title of the Tumblr. The point of entry for this theme is the <div> element with the #post-it-forward-root ID. In your index.js file you’ll reference this DOM element in your ReactDom.render() method. If you want to learn more about the theme engine, head over to our Theme Docs

Creating the Initial State

To get things started, we need to create an initial state. How do we introduce this initial state if we have to rely on the theme engine to give us all our data? How do we get the data from HTML land to JS land? Well, here’s one way of doing it:

<script type="text/javascript">
(function(root) {
var ensureString = function(str) {
return !str ? '' : str;
};
var basicVariables = {
title: ensureString({JSTitle}),
name: ensureString({JSName}),
description: ensureString({JSDescription}),
metaDescription: ensureString({JSMetaDescription}),
blogUrl: ensureString({JSBlogURL}),
rss: ensureString({JSRSS}),
favicon: ensureString({JSFavicon}),
customCss: ensureString({JSCustomCSS}),
isPermalinkPage: !!ensureString(/*{block:PermalinkPage}*/true/*{/block:PermalinkPage}*/),
isIndexPage: !!ensureString(/*{block:IndexPage}*/true/*{/block:IndexPage}*/),
/*{block:PostTitle}*/
postTitle: ensureString({JSPostTitle}),
/*{/block:PostTitle}*/
/*{block:PostSummary}*/
postSummary: ensureString({JSPostSummary}),
/*{/block:PostSummary}*/
portraitUrl16: ensureString({JSPortraitURL-16}),
portraitUrl24: ensureString({JSPortraitURL-24}),
portraitUrl30: ensureString({JSPortraitURL-30}),
portraitUrl40: ensureString({JSPortraitURL-40}),
portraitUrl48: ensureString({JSPortraitURL-48}),
portraitUrl64: ensureString({JSPortraitURL-64}),
portraitUrl96: ensureString({JSPortraitURL-96}),
portraitUrl128: ensureString({JSPortraitURL-128}),
copyrightYears: ensureString({JSCopyrightYears}),
isSearchPage: !!ensureString(/*{block:SearchPage}*/true/*{/block:SearchPage}*/),
searchQuery: ensureString({JSSearchQuery}),
safeSearchQuery: ensureString({JSURLSafeSearchQuery}),
searchPlaceHolder: ensureString('{lang:Search Blog}'),
noSearchResults: !!ensureString(/*{block:NoSearchResults}*/true/*{/block:NoSearchResults}*/),
};
root.tumblrData = {
basicVariables: basicVariables,
};
})(this);
</script>

This creates a tumblrData attribute on the browser’s window object.

Sometimes the theme engine returns nothing for a particular variable if it’s not available. For example, if I made a post that does not have a title, the final root.tumblrData object will not have postTitle as a key. Sometimes the key will be available but the theme engine returned an empty value for it. For those cases, I created a helper method called ensureString() that turns those empty values into empty strings. Sometimes you might need a boolean value. In those cases, I’ll enter the conditional variables from the theme engine into the helper method to get the boolean value from it.

Once you’ve set up your initial state make sure that you place this script tag before the script tag that references the rest of your code that should be compiled and minified and uploaded through the asset uploader that the Tumblr text editor provides. This ensures that the tumblrData is accessible through the window object by the time the React app gets initiated.

tumblrData should look something like this:

const tumblrData = {
basicVariables: {
blogUrl: "https://mentalhealthquilt.tumblr.com/",
copyrightYears: "2016–2017",
customCss: "",
description: "Mental Health Quilt",
favicon: "https://68.media.tumblr.com/avatar_c402eedfb9d5_128.png",
isIndexPage: true,
isPermalinkPage: false,
isSearchPage: false,
metaDescription: "Mental Health Quilt",
name: "mentalhealthquilt",
noSearchResults: false,
portraitUrl16: "https://68.media.tumblr.com/avatar_c402eedfb9d5_16.png",
portraitUrl24: "https://68.media.tumblr.com/avatar_c402eedfb9d5_24.png",
portraitUrl30: "https://68.media.tumblr.com/avatar_c402eedfb9d5_30.png",
portraitUrl40: "https://68.media.tumblr.com/avatar_c402eedfb9d5_40.png",
portraitUrl48: "https://68.media.tumblr.com/avatar_c402eedfb9d5_48.png",
portraitUrl64: "https://68.media.tumblr.com/avatar_c402eedfb9d5_64.png",
portraitUrl96: "https://68.media.tumblr.com/avatar_c402eedfb9d5_96.png",
portraitUrl128: "https://68.media.tumblr.com/avatar_c402eedfb9d5_128.png",
rss: "https://mentalhealthquilt.tumblr.com/rss",
safeSearchQuery: "",
searchPlaceHolder: "Search mentalhealthquilt",
searchQuery: "",
title: "Mental Health Quilt",
},
}

Now we have the data that the theme engine gave us in a format that React and Redux can work with.

If you are new to these libraries, I highly recommend following the simple Todo App Tutorial that is on the Redux website. They do a wonderful job of explaining the process as you build the app.

Helpful Tips

Setting up a local server will make developing way faster than the current setup. If you’re using both the “webpack” and “webpack-dev-server” packages, in your package.json file under scripts you can place something like this in it:

In your package.json file

...
"scripts": {
"local-server": "NODE_ENV=development webpack-dev-server --config path/to/webpack.config.js --port=3000 --inline --hot"
},
...

To run that script, in the terminal you will type this command:

> npm run local-server

In the Tumblr editor, be sure to replace your script tags referencing these external files like so:

<!DOCTYPE html>
<head>
<title>{Title}</title>
<link rel="stylesheet" type="text/css" href="http://localhost:3000/path/to/prod/index.css">
</head>
<body>
<div id="post-it-forward-root"></div>
<script type="text/javascript">
// where the tumblrData gets created
</script>
<script src="http://localhost:3000/path/to/prod/index.js"></script>
</body>
</html>

Once you run that script, it’ll enable live reload so that every time you save a .js_.css_.scss/etc. file, it’ll rebuild the assets and refresh your Tumblr blog for you. This is way faster than having to re-upload your assets every time you make a change, no matter how small. Just remember to return your script and style references to the uploaded assets when you’re done working. Localhost is only for development.

You could also add the Redux logger middleware to your project during development so that you can view how the state changes as you fire off different actions. For more information on how to set this up, the Redux Logger Github is a great resource.

Summary

Building a Tumblr theme using Redux and React is possible! Not only is there a workflow that makes development much faster, but it’s also a great way to flex your web development muscles. You can add more to the user experience of your Tumblr now that you have the world of JavaScript at your fingertips. Go forth and make some awesome themes!

Stay tuned for part 2 that will cover paginating.

@0xmichelle



Source link

Write a comment