{"id":319240,"date":"2020-08-24T07:36:51","date_gmt":"2020-08-24T14:36:51","guid":{"rendered":"https:\/\/css-tricks.com\/?p=319240"},"modified":"2020-08-24T09:20:51","modified_gmt":"2020-08-24T16:20:51","slug":"where-does-logic-go-on-jamstack-sites","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/where-does-logic-go-on-jamstack-sites\/","title":{"rendered":"Where Does Logic Go on Jamstack Sites?"},"content":{"rendered":"\n

Here\u2019s something I had to get my head wrapped around when I started building Jamstack sites. There are these different stages<\/em> your site goes through where you can put logic.<\/p>\n\n\n\n

Let\u2019s look at a special example so you can see what I mean. Say you’re making a website for a music venue. The most important part of the site is a list of events, some in the past and some upcoming. You want to make sure to label them as such or design that to be very clear. That is date-based logic. How do you do that? Where does that logic live?<\/p>\n\n\n\n

There are at least four places to consider when it comes to Jamstack.<\/p>\n\n\n\n\n\n\n

Option 1: Write it into the HTML ourselves<\/h3>\n\n\n

Literally sit down and write an HTML file that represents all of the events. We\u2019d look at the date of the event, decide whether it\u2019s in the past or the future, and write different content for either case. Commit and deploy that file.<\/p>\n\n\n\n

<h1>Upcoming Event: Bill's Banjo Night<\/h1>\n<h1>Past Event: 70s Classics with Jill<\/h1><\/code><\/pre>\n\n\n\n

This would totally work! But the downside is that weu’d have to update that HTML file all the time \u2014 once Bill\u2019s Banjo Night is over, we have to open your code editor, change “Upcoming” to “Past” and re-upload the file.<\/p>\n\n\n

Option 2: Write structured data and do logic at build time<\/h3>\n\n\n

Instead of writing all the HTML by hand, we create a Markdown file to represent each event. Important information like the date and title is in there as structured data<\/em>. That\u2019s just one option. The point is we have access to this data directly. It could be a headless CMS or something like that as well.<\/p>\n\n\n\n

Then we set up a static site generator, like Eleventy<\/a>, that reads all the Markdown files (or pulls the information down from your CMS) and builds them into HTML files. The neat thing is thatwe can run any logic we want during the build process.<\/em> Do fancy math, hit APIs, run a spell-check\u2026 the sky is the limit.<\/p>\n\n\n\n

For our music venue site, we might represent events as Markdown files like this:<\/p>\n\n\n\n

---\ntitle: Bill's Banjo Night\ndate: 2020-09-02\n---\n\nThe event description goes here!<\/code><\/pre>\n\n\n\n

Then, we run a little bit of logic during the build process by writing a template like this:<\/p>\n\n\n\n

{% if event.date > now %}\n\u00a0 <h1>Upcoming Event: {{event.title}}<\/h1>\n{% else %}\n\u00a0 <h1>Past Event: {{event.title}}<\/h1>\n{% endif %}<\/code><\/pre>\n\n\n\n

Now, each time the build process runs, it looks at the date of the event, decides if it\u2019s in the past or the future and produces different HTML based on that information. No more changing HTML by hand!<\/p>\n\n\n\n

The problem with this approach is that the date comparison only happens one time, during the build process. The now<\/code> variable in the example above is going to refer to the date and time the build happens to run. And once we\u2019ve uploaded the HTML files that build produced, those won\u2019t change until we run the build again. This means that once an event at our music venue is over, we\u2019d have to re-run the build to make sure the website reflects that.<\/p>\n\n\n\n

Now, we could automate the rebuild so it happens once a day, or heck, even once an hour. That\u2019s literally what the CSS-Tricks conferences site<\/a> does via Zapier.<\/p>\n\n\n\n

\"\"
The conferences site is deployed daily using a Zapier automation that triggers a Netlify deploy,, ensuring information is current.<\/figcaption><\/figure>\n\n\n\n

But this could rack up build minutes if you\u2019re using a service like Netlify, and there might still be edge cases where someone gets an outdated version of the site.<\/p>\n\n\n

Option 3: Do logic at the edge<\/h3>\n\n\n

Edge workers are a way of running code at the CDN level whenever a request comes in. They\u2019re not widely available at the time of this writing but, once they are, we could write our date comparison like this:<\/p>\n\n\n\n

\/\/ THIS DOES NOT WORK\nimport eventsList from \".\/eventsList.json\"\nfunction onRequest(request) {\n\u00a0 const now = new Date();\n\u00a0 eventList.forEach(event => {\n\u00a0 \u00a0 if (event.date > now) {\n\u00a0 \u00a0 \u00a0 event.upcoming = true;\n\u00a0 \u00a0 }\n\u00a0 })\n\u00a0 const props = {\n\u00a0 \u00a0 events: events,\n\u00a0 }\n\u00a0 request.respondWith(200, render(props), {})\n}<\/code><\/pre>\n\n\n\n

The render()<\/code> function would take our processed list of events and turn it into HTML, perhaps by injecting it into a pre-rendered template. The big promise of edge workers is that they\u2019re extremely fast, so we could run this logic server-side while still enjoying the performance benefits of a CDN.<\/p>\n\n\n\n

And because the edge worker runs every time someone requests the website, we can be sure that they\u2019re going to get an up-to-date version of it.<\/p>\n\n\n

Option 4: Do logic at run time<\/h3>\n\n\n

Finally, we could pass our structured data to the front end directly, for example, in the form of data attributes. Then we write JavaScript that\u2019s going to do whatever logic we need on the user\u2019s device and manipulates the DOM on the fly.<\/p>\n\n\n\n

For our music venue site, we might write a template like this:<\/p>\n\n\n\n

<h1 data-date=\"{{event.date}}\">{{event.title}}<\/h1><\/code><\/pre>\n\n\n\n

Then, we do our date comparison in JavaScript after the page is loaded:<\/p>\n\n\n\n

function processEvents(){\n\u00a0 const now = new Date()\n\u00a0 events.forEach(event => {\n\u00a0 \u00a0 const eventDate = new Date(event.getAttribute('data-date'))\n\u00a0 \u00a0 if (eventDate > now){\n\u00a0 \u00a0 \u00a0 \u00a0 event.classList.add('upcoming')\n\u00a0 \u00a0 } else {\n\u00a0 \u00a0 \u00a0 \u00a0 event.classList.add('past')\n\u00a0 \u00a0 }\n\u00a0 })\n}<\/code><\/pre>\n\n\n\n

The now<\/code> variable reflects the time on the user\u2019s device, so we can be pretty sure the list of events will be up-to-date. Because we\u2019re running this code on the user\u2019s device, we could even get fancy and do things like adjust the way the date is displayed based on the user\u2019s language or timezone.<\/p>\n\n\n\n

And unlike the previous points in the lifecycle, run time lasts as long as the user has our website open. So, if we wanted to, we could run processEvents()<\/code> every few seconds and our list would stay perfectly up-to-date without having to refresh the page. This would probably be unnecessary for our music venue\u2019s website, but if we wanted to display the events on a billboard outside the building, it might just come in handy.<\/p>\n\n\n

Where will you put the logic?<\/h3>\n\n\n

Although one of the core concepts of Jamstack is that we do as much work as we can at build time and serve static HTML, we still get to decide where to put logic.<\/p>\n\n\n\n

Where will you put it?<\/p>\n\n\n\n

It really depends on what you\u2019re trying to do. Parts of your site that hardly ever change are totally fine to complete at edit time. When you find yourself changing a piece of information again and again, it\u2019s probably a good time to move that into a CMS and pull it in at build time. Features that are time-sensitive (like the event examples we used here), or that rely on information about the user, probably need to happen further down the lifecycle at the edge or even at runtime.<\/p>\n","protected":false},"excerpt":{"rendered":"

Here\u2019s something I had to get my head wrapped around when I started building Jamstack sites. There are these different stages your site goes through where you can put logic. Let\u2019s look at a special example so you can see what I mean. Say you’re making a website for a music venue. The most important […]<\/p>\n","protected":false},"author":253948,"featured_media":319246,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[4],"tags":[1401,885],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/08\/assembly-line.png?fit=1200%2C600&ssl=1","jetpack-related-posts":[{"id":284137,"url":"https:\/\/css-tricks.com\/stackbit\/","url_meta":{"origin":319240,"position":0},"title":"Stackbit","date":"March 12, 2019","format":false,"excerpt":"This is not a sponsored post. I requested a beta access for this site called Stackbit a while back, got my invite the other day, and thought it was a darn fine idea that's relevant to us web nerds \u2014 particularly those of us who spin up a lot of\u2026","rel":"","context":"In "Link"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/03\/stackbit.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":295944,"url":"https:\/\/css-tricks.com\/random-notes-from-a-jamstack-roundtable\/","url_meta":{"origin":319240,"position":1},"title":"Random Notes from a JAMstack Roundtable","date":"September 23, 2019","format":false,"excerpt":"I hosted a JAMstack roundtable discussion at Web Unleashed this past weekend. Just a few random notes from that experience. I was surprised at first that there really is confusion that the \"M\" in Jamstack stands for \"Markdown\" (the language that compiles to HTML) rather than \"Markup\" (the \"M\" in\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/06\/jam-stack.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":288467,"url":"https:\/\/css-tricks.com\/jamstack-more-like-shamstack\/","url_meta":{"origin":319240,"position":2},"title":"JAMstack? More like SHAMstack.","date":"June 5, 2019","format":false,"excerpt":"I'm a fan of the whole JAMstack thing. It seems like a healthy web movement. I'm looking forward to both of the upcoming conferences. Of any web trend, #jamstack seems like it will be the least regrettable.\u2014 Chris Coyier (@chriscoyier) May 22, 2019 I feel like the acronym might not\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/06\/jam-stack.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":297623,"url":"https:\/\/css-tricks.com\/a-look-at-jamstacks-speed-by-the-numbers\/","url_meta":{"origin":319240,"position":3},"title":"A Look at JAMstack’s Speed, By the Numbers","date":"November 1, 2019","format":false,"excerpt":"People say JAMstack sites are fast \u2014 let\u2019s find out why by looking at real performance metrics! We\u2019ll cover common metrics, like Time to First Byte (TTFB) among others, then compare data across a wide section of sites to see how different ways to slice those sites up compare. First,\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/10\/jam-layered.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":299314,"url":"https:\/\/css-tricks.com\/the-rising-complexity-of-jamstack-sites-and-how-to-manage-them\/","url_meta":{"origin":319240,"position":4},"title":"The Rising Complexity of JAMstack Sites and How to Manage Them","date":"December 5, 2019","format":false,"excerpt":"When you add anything with user-generated content or dynamic data to a static site, the complexity of the build process can become comparable to launching a monolithic CMS. How can we add rich content to static sites without stitching together multiple third-party services? For people in the development community static\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/11\/growing-circles.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":298412,"url":"https:\/\/css-tricks.com\/jamstack-cmss-have-finally-grown-up\/","url_meta":{"origin":319240,"position":5},"title":"JAMstack CMSs Have Finally Grown Up!","date":"November 15, 2019","format":false,"excerpt":"This article is based on Brian's presentation at Connect.Tech 2019. Slides with speaker notes from that presentation are available to download. In my experience, developers generally find the benefits of the JAMstack easy to comprehend. Sites are faster because the resources are static and served from a CDN. Sites are\u2026","rel":"","context":"In "Article"","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/11\/connecttech-artwork.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/319240"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/253948"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=319240"}],"version-history":[{"count":4,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/319240\/revisions"}],"predecessor-version":[{"id":319878,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/319240\/revisions\/319878"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/319246"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=319240"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=319240"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=319240"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}