About

Friday, May 28, 2021

Dynamic Favicons for WordPress

Typically, a single favicon is used across a whole domain. But there are times you wanna step it up with different favicons depending on context. A website might change the favicon to match the content being viewed. Or a site might allow users to personalize their theme colors, and those preferences are reflected in the favicon. Maybe you’ve seen favicons that attempt to alert the user of some event.

Multiple favicons can technically be managed by hand — Chris has shown us how he uses two different favicons for development and production. But when you reach the scale of dozens or hundreds of variations, it’s time to dynamically generate them.

This was the situation I encountered on a recent WordPress project for a directory of colleges and universities. (I previously wrote about querying nearby locations for the same project.) When viewing a school’s profile, we wanted the favicon to use a school’s colors rather than our default blue, to give it that extra touch.

With over 200 schools in the directory and climbing, we needed to go dynamic. Fortunately, we already had custom meta fields storing data on each school’s visual identity. This included school colors, which were being used in the stylesheet. We just needed a way to apply these custom meta colors to a dynamic favicon.

In this article, I’ll walk you through our approach and some things to watch out for. You can see the results in action by viewing different schools.

Each favicon is a different color in the tabs based on the school that is selected.

SVG is key

Thanks to improved browser support for SVG favicons, implementing dynamic favicons is much easier than days past. In contrast to PNG (or the antiquated ICO format), SVG relies on markup to define vector shapes. This makes them lightweight, scaleable, and best of all, receptive to all kinds of fun.

The first step is to create your favicon in SVG format. It doesn’t hurt to also run it through an SVG optimizer to get rid of the cruft afterwards. This is what we used in the school directory:

Hooking into WordPress

Next, we want to add the favicon link markup in the HTML head. How to do this is totally up to you. In the case of WordPress, it could be added it to the header template of a child theme or echo’d through a wp_head() action.

function ca_favicon() {
  if ( is_singular( 'school' ) ) {
    $post_id = get_the_ID();
    $color = get_post_meta( $post_id, 'color', true );

    if ( isset( $color ) ) {
      $color = ltrim( $color, '#' ); // remove the hash
      echo '<link rel="icon" href="' . plugins_url( 'images/favicon.php?color=' . $color, __FILE__ ) . '" type="image/svg+xml" sizes="any">';
    }
  }
}
add_filter( 'wp_head' , 'ca_favicon' );

Here we’re checking that the post type is school, and grabbing the school’s color metadata we’ve previously stored using get_post_meta(). If we do have a color, we pass it into favicon.php through the query string.

From PHP to SVG

In a favicon.php file, we start by setting the content type to SVG. Next, we save the color value that’s been passed in, or use the default color if there isn’t one.

Then we echo the large, multiline chunk of SVG markup using PHP’s heredoc syntax (useful for templating). Variables such as $color are expanded when using this syntax.

Finally, we make a couple modifications to the SVG markup. First, classes are assigned to the color-changing elements. Second, a style element is added just inside the SVG element, declaring the appropriate CSS rules and echo-ing the $color.

Instead of a <style> element, we could alternatively replace the default color with $color wherever it appears if it’s not used in too many places.

<?php
header( 'Content-Type: image/svg+xml' );

$color = $_GET[ 'color' ] ?? '065281';
$color = sanitize_hex_color_no_hash( $color );

echo <<<EOL
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="1000">
  <style type="text/css">
  <![CDATA[
  .primary {
    fill: #$color;
  }
  .shield {
    stroke: #$color;
  }
  ]]>
  </style>
  <defs>
    <path id="a" d="M0 34L318 0l316 34v417.196a97 97 0 01-14.433 50.909C483.553 722.702 382.697 833 317 833S150.447 722.702 14.433 502.105A97 97 0 010 451.196V34z"/>
  </defs>
  <g fill="none" fill-rule="evenodd">
    <g transform="translate(183 65)">
      <mask id="b" fill="#fff">
        <use xlink:href="#a"/>
      </mask>
      <use fill="#FFF" xlink:href="#a"/>
      <path class="primary" mask="url(#b)" d="M317-37h317v871H317z"/>
      <path class="primary" mask="url(#b)" d="M0 480l317 30 317-30v157l-317-90L0 517z"/>
      <path fill="#FFF" mask="url(#b)" d="M317 510l317-30v37l-317 30z"/>
    </g>
    <g fill-rule="nonzero">
      <path class="primary" d="M358.2 455.2c11.9 0 22.633-.992 32.2-2.975 9.567-1.983 18.375-4.9 26.425-8.75 8.05-3.85 15.458-8.458 22.225-13.825 6.767-5.367 13.3-11.433 19.6-18.2l-34.3-34.65c-9.567 8.867-19.192 15.867-28.875 21-9.683 5.133-21.525 7.7-35.525 7.7-10.5 0-20.125-2.042-28.875-6.125s-16.217-9.625-22.4-16.625-11.025-15.167-14.525-24.5-5.25-19.25-5.25-29.75v-.7c0-10.5 1.75-20.358 5.25-29.575 3.5-9.217 8.4-17.325 14.7-24.325 6.3-7 13.825-12.483 22.575-16.45 8.75-3.967 18.258-5.95 28.525-5.95 12.367 0 23.508 2.45 33.425 7.35 9.917 4.9 19.658 11.667 29.225 20.3l34.3-39.55a144.285 144.285 0 00-18.2-15.4c-6.533-4.667-13.65-8.633-21.35-11.9-7.7-3.267-16.275-5.833-25.725-7.7-9.45-1.867-19.892-2.8-31.325-2.8-18.9 0-36.167 3.325-51.8 9.975-15.633 6.65-29.05 15.75-40.25 27.3s-19.95 24.967-26.25 40.25c-6.3 15.283-9.45 31.675-9.45 49.175v.7c0 17.5 3.15 33.95 9.45 49.35 6.3 15.4 15.05 28.758 26.25 40.075 11.2 11.317 24.5 20.242 39.9 26.775 15.4 6.533 32.083 9.8 50.05 9.8z"/>
      <path fill="#FFF" d="M582.35 451l22.4-54.95h103.6l22.4 54.95h56.35l-105-246.75h-49.7L527.4 451h54.95zM689.1 348.45H624L656.55 269l32.55 79.45z"/>
    </g>
    <path class="shield" stroke-width="30" d="M183 99l318-34 316 34v417.196a97 97 0 01-14.433 50.909C666.553 787.702 565.697 898 500 898S333.447 787.702 197.433 567.105A97 97 0 01183 516.196V99h0z"/>
  </g>
</svg>
EOL;
?>

With that, you’ve got a dynamic favicon working on your site.

Security considerations

Of course, blindly echo-ing URL parameters opens you up to hacks. To mitigate these, we should sanitize all of our inputs.

In this case, we‘re only interested in values that match the 3-digit or 6-digit hex color format. We can include a function like WordPress’s own sanitize_hex_color_no_hash() to ensure only colors are passed in.

function sanitize_hex_color( $color ) {
  if ( '' === $color ) {
    return '';
  }

  // 3 or 6 hex digits, or the empty string.
  if ( preg_match( '|^#([A-Fa-f0-9]{3}){1,2}$|', $color ) ) {
    return $color;
  }
}

function sanitize_hex_color_no_hash( $color ) {
  $color = ltrim( $color, '#' );

  if ( '' === $color ) {
    return '';
  }

  return sanitize_hex_color( '#' . $color ) ? $color : null;
}

You’ll want to add your own checks based on the values you want passed in.

Caching for better performance

Browsers cache SVGs, but this benefit is lost for PHP files by default. This means each time the favicon is loaded, your server’s being hit.

To reduce server strain and improve performance, it’s essential that you explicitly cache this file. You can configure your server, set up a page rule through your CDN, or add a cache control header to the very top of favicon.php like so:

header( 'Cache-Control: public, max-age=604800' );  // 604,800 seconds or 1 week

In our tests, with no caching, our 1.5 KB SVG file took about 300 milliseconds to process on the first load, and about 100 milliseconds on subsequent loads. That’s pretty lousy. But with caching, we brought this down to 25 ms from CDN on first load, and 1 ms from browser cache on later loads — as good as a plain old SVG.

Browser support

If we were done there, this wouldn’t be web development. We still have to talk browser support.

As mentioned before, modern browser support for SVG favicons is solid, and fully-supported in current versions of Chrome, Firefox, and Edge.

SVG favicons have arrived… except in Safari.

One caveat is that Firefox requires the attribute type="image/svg+xml" in the favicon declaration for it to work. The other browsers are more forgiving, but it‘s just good practice. You should include sizes="any" while you’re at it.

<link rel="icon" href="path/to/favicon.svg" type="image/svg+xml" sizes="any">

Safari

Safari doesn‘t support SVG favicons as of yet, outside of the mask icon feature intended for pinned tabs. In my experimentation, this was buggy and inconsistent. It didn’t handle complex shapes or colors well, and cached the same icon across the whole domain. Ultimately we decided not to bother and just use a fallback with the default blue fill until Safari improves support.

Fallbacks

As solid as SVG favicon support is, it‘s still not 100%. So be sure to add fallbacks. We can set an additional favicon for when SVG icons aren’t supported with the rel="alternative icon" attribute:

<link rel="icon" href="path/to/favicon.svg" type="image/svg+xml" sizes="any">
<link rel="alternate icon" href="path/to/favicon.png" type="image/png">

To make the site even more bulletproof, you can also drop the eternal favicon.ico in your root.

Going further

We took a relatively simple favicon and swapped one color for another. But taking this dynamic approach opens the door to so much more: modifying multiple colors, other properties like position, entirely different shapes, and animations.

For instance, here’s a demo I’ve dubbed Favicoin. It plots cryptocurrency prices in the favicon as a sparkline.

Implementing dynamic favicons like this isn’t limited to WordPress or PHP; whatever your stack, the same principles apply. Heck, you could even achieve this client-side with data URLs and JavaScript… not that I recommend it for production.

But one thing‘s for sure: we’re bound to see creative applications of SVG favicons in the future. Have you seen or created your own dynamic favicons? Do you have any tips or tricks to share?


The post Dynamic Favicons for WordPress appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/dynamic-favicons-for-wordpress/

To $ or Not to $: Displaying Terminal Code Snippets

It’s very popular to put a $ on lines that are intended to be a command in code documentation that involves the terminal (i.e. the command line).

Like this:

$ brew install somepackage

The point of that is that it mimics the prompt that you (may) see on your command line. Here’s mine:

So the dollar sign ($) is a little technique that people use to indicate this line of code is supposed to be run on the command line.

Minor trouble

The trouble with that is that I (and I’ll wager most other people too) will copy and paste commands like that from that documentation.

If I run that command above in my terminal exactly as it’s written…

…it doesn’t work. $ is not a command. How do you deal with this? You just have to know. You just need to have had this problem before and somehow learned that what the documentation is actually telling you is to run the command brew install somepackage (without the dollar sign) at the command line.

I say minor trouble as there are all sorts of stuff like this in every job in the world. When I put something like font-size: 2.2rem in a blog post, I don’t also say, “Put that declaration in a ruleset in a CSS file that your HTML file links to.” You just have to know those those things.

Fixing it with CSS

The fact that it’s only minor trouble and that tech is laden with things you just need to know doesn’t mean that we can’t try to fix this and do a little better.

The idea for this post came from this tweet that got way more likes than I thought it would:

To expand on that, I’d expect you’re probably marking up your docs something like:

<p>Install package like:</p>

<pre><code class="command">brew install package</code></pre>

Now you can insert the $ as a pseudo-element rather than as actual text:

code.command::before {
  content: "$ ";
}

Now you aren’t just saving yourself a character in the HTML, the $ cannot be selected, because that’s how pseudo-elements work. So now you’re now a bit better in the UX department. Even if the user double-clicks the line or tries to select all of it, they won’t get the $ screwing up the copy-paste.

Hopefully they aren’t equally frustrated by not being able to copy the $. 😬

So, anyway, something like this incredible design by me:

Fixing it with text

A lot of documentation for code-things are on a public git repo place like GitHub. You don’t have access to CSS to style what GitHub looks like, so while there is trickery available, you can’t just plop a line of CSS in there to style things.

We might have to (gasp) use our words:

<p>
  Install the package by entering this 
  command at your terminal:
</p>

<kbd class="command">brew install package</kbd>

Other thoughts

  • You probably wouldn’t bother syntax highlighting it at all. I don’t think I’ve ever seen a terminal that syntax highlights commands as you enter them.
  • Eric Meyer suggested the <kbd> element which is the Keyboard Input element. I like that. I’ve long used <code> but I think <kbd> is more appropriate here.
  • Tim Chase suggested using a <span> and including the prompt in the HTML so you can style it uniquely if you want, including making it not selectable with user-select: none;.
  • Justin Searls has a dotfiles trick where if you accidently copy/paste the $, it just ignores it and runs everything after it.
  • Jackson Bates suggests being very careful about what you copy and paste to a terminal.
  • I learned that $ is also a way of denoting “unprivileged” commands while # is for root commands. Part of that reason is that if you copy-paste a root command, it won’t run as it will be recognized as a comment.

The post To $ or Not to $: Displaying Terminal Code Snippets appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/to-or-not-to-displaying-terminal-code-snippets/

Thursday, May 27, 2021

How to Show Images on Click

Most images on the web are superfluous. If I might be a jerk for a bit, 99% of them aren’t event that helpful at all (although there are rare exceptions). That’s because images don’t often complement the text they’re supposed to support and instead hurt users, taking forever to load and blowing up data caps like some sort of performance tax.

Thankfully, this is mostly a design problem today because making images performant and more user-friendly is so much easier than it once was. We have better image formats like WebP (and soon, perhaps, JPEG XL). We have the magic of responsive images of course. And there are tons of great tools out there, like ImageOptim, as well as resources such as Addy Osmani’s new book.

Although perhaps my favorite way to improve image performance is with lazy loading:

<img href="image.webp" alt="Image description" loading="lazy">

This image will only load when a user scrolls down the page so it’s visible to the user — which removes it from the initial page load and that’s just great! Making that initial load of a webpage lightning fast is a big deal.

But maybe there are images that should never load at all. Perhaps there are situations where it’d be better if a person could opt-into seeing it. Here’s one example: take the text-only version of NPR and click around for a bit. Isn’t it… just so great?! It’s readable! There’s no junk all over the place, it respects me as a user and — sweet heavens — is it fast.

Did I just show you an image in a blog post that insults the very concept of images? Yep! Sue me.

So! What if we could show images on a website but only once they are clicked or tapped? Wouldn’t it be neat if we could show a placeholder and swap it out for the real image on click? Something like this:

Well, I had two thoughts here as to how to build this chap (the golden rule is that there’s never one way to build anything on the web).

Method #1: Using <img> without a src attribute

We can remove the src attribute of an <img> tag to hide an image. We could then put the image file in an attribute, like data-src or something, just like this:

<img data-src="image.jpg" src="" alt="Photograph of hot air balloons by Musab Al Rawahi. 144kb">

By default, most browsers will show a broken image icon that you’re probably familiar with:

Okay, so it’s sort of accessible. I guess? You can see the alt tag rendered on screen automatically, but with a light dash of JavaScript, we can then swap out the src with that attribute:

document.querySelectorAll("img").forEach((item) => {
  item.addEventListener("click", (event) => {
    const image = event.target.getAttribute("data-src");
    event.target.setAttribute("src", image);
  });
});

Now we can add some styles and ugh, oh no:

Ugh. In some browsers there’ll be a tiny broken image icon in the bottom when the image hasn’t loaded. The problem here is that browsers don’t give you a way to remove the broken image icon with CSS (and we probably shouldn’t be allowed to anyway). It’s a bit annoying to style the alt text, too. But if we remove the alt attribute altogether, then the broken image icon is gone, although this makes the <img> unusable without JavaScript. So removing that alt text is a no-go.

As I said: Ugh. I don’t think there’s a way to make this method work (although please prove me wrong!).

Method #2: Using links to create an image

The other option we have is to start with the humble hyperlink, like this:

<a href="image.jpg">Photograph of hot air balloons by Musab Al Rawahi. 144kb<a>

Which, yep, nothing smart happening yet — this will just render a link to an image:

That works accessibility-wise, right? If we don’t have any JavaScript, then all we have is just a link that folks can optionally click. Performance-wise, it can’t get much faster than plain text!

But from here, we can reach for JavaScript to stop the link from loading on click, grab the href attribute within that link, create an image element and, finally, throw that image on the page and remove the old link once we’re done:

document.querySelectorAll(".load-image").forEach((item) => {
  item.addEventListener("click", (event) => {
    const href = event.target.getAttribute("href");
    const newImage = document.createElement("img");
    event.preventDefault();
    newImage.setAttribute("src", href);
    document.body.insertBefore(newImage, event.target);
    event.target.remove();
  });
});

We could probably style this placeholder link to make it look a bit nicer than what I have below. But this is just an example. Go ahead and click the link to load the image again:

And there you have it! It isn’t groundbreaking or anything, and I’m sure someone’s done this before at some point or another. But if we wanted to be extremely radical about performance beyond the first paint and initial load, then I think this is an okay-ish solution. If we’re making a text-only website then I think this is definitely the way to go.

Perhaps we could also make a web component out of this, or even detect if someone has prefers-reduced-data and then only load images if someone has enough data or something. What do you think?


The post How to Show Images on Click appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/how-to-show-images-on-click/

Rethinking Postgres in a Post-Server World

Serverless architectures have brought engineering teams a great number of benefits. We get simpler deployments, automatic and infinite scale, better concurrency, and a stateless API surface. It’s hard to imagine going back to the world of managed services, broken local environments, and SSHing into servers. When I started doing web development, moving from servers in a closet to rackspace was a revolution.

It’s not just hosting and how we deploy applications that have changed under this new paradigm. These advantages of serverless have presented challenges to the traditional MVC architecture that has been so ubiquitous. Thinking back to those early days, frameworks like Zend, Laravel, Django, and Rails were incredible productivity boosters. They not only influenced the way we built applications, but also the way we think about solving problems with the web. These were your “majestic monoliths” and they solidified the MVC pattern as the defacto standard for most of the web applications we use today.

In many ways, the rise of microservices and with it the idea of hexagonal architectures (aka ports and adaptors) led naturally to this new serverless world. It started as creating and hosting standalone APIs organized by a shared context that were still backed by the classic frameworks we already knew and loved.

The popularity of NodeJS led to the express framework where we now had a less rigid microframework enabling us to more flexibly organize our code. The final metamorphosis of this pattern is individual pieces of business logic that can be executed on demand in the cloud. We no longer manage machines or even multiple API servers. Each piece of business logic only exists when it is needed, for as long as it’s needed and no longer. They are lightweight, and you only pay for the individual parts of your application that get used.

Today, we hardly realize there is a server at all–even the terminology, serverless, is a misnomer designed to highlight just how far we’ve come from the days of setting up XAMP or VirtualBox and Vagrant. The benefits are clear, the hours saved, the headaches avoided, and the freedom to just solve business problems with code bring building software closer than ever to the simple act of writing prose.

The Problem

The classic MVC frameworks codified not only the pattern of working in three distinct tiers (data, application, and presentation) but also the technology for each. You were able to choose some options at each layer, for instance Postgres or MySQL as the data layer, but the general idea is these decisions are made for you. You implicitly adopt the idea of convention over configuration.

Postgres as a data layer solution makes a lot of sense. It’s robust, fast, supports ACID transactions, and has over thirty years of development behind it. It is also open-source, can be hosted almost anywhere, and is likely to be around for another thirty years. You could do much worse than stake your company’s future on Postgres. Add to that all the work put into integrating it into these equally battle-tested frameworks and the story for choosing Postgres becomes very strong.

However, when we enter a serverless context, this type of architecture presents a number of challenges particularly when it comes to handling our data.

Common issues include:

  1. Maintaining stateful connections: when each user is a new connection to Postgres this can max out the number of connections Postgres can handle quickly.
  2. Provisioned scale: with Postgres we must be sure to provision the right size database for our application ahead of time, which is not ideal when our application layer can automatically scale to any workload.
  3. Traditional security model: this model does not allow for any client-side use and is vulnerable to SQL injection attacks.
  4. Data centralization: while our application may be deployed globally, this is of little use when our database is stuck in a single location potentially thousands of miles from where the data needs to be.
  5. High operational overhead: serverless promises to free us from complexity and remove barriers to solving business problems. With Postgres we return to needing to manage a service ourselves, dealing with sharding, scaling, distribution, and backups.

Traditional systems like Postgres were never designed for this purpose. To start, Postgres operates on the assumption of a stateful connection. What this means is that Postgres will hold open a connection with a server in order to optimize the response time. In a traditional monolithic application, if your server had to open a new connection every single time it requested data this would be quite inefficient. The actual network request would in many times be the primary bottleneck. By keeping this connection cached Postgres removes this bottleneck. As you scale your application you will likely have multiple machines running, and a single Postgres database can handle many such connections, but this number isn’t infinite. In fact, in many cases, you have to set this number at the time of provisioning the database.

In a serverless context, each request is effectively a new machine and a new connection to the database. As Postgres attempts to hold open these connections we can quickly run up against our connection limit and the memory limits of the machine. This also introduces another issue with the traditional Postgres use case, which is provisioned resources. 

With Postgres we have to decide the size of the database, the capacity of the machine it runs on, where that machine is located, and the connection limit at the time of creation. This puts us in a situation where our application can scale automatically but we must watch our database closely and scale it ourselves. This can be even trickier when we are dealing with spikes in traffic that are not consistent in both time and location. Ultimately by moving to serverless we have reduced the operational overhead of our application layer, but created some increased operational overhead in our database. Would it not be better if both our application and our data layer could scale together without us having to manage it?

The complexity required to make traditional systems like Postgres work in a serverless environment can often be enough to abandon the architecture all together. Serverless requires on-demand, stateless execution of business logic. This allows us to create lighter, more scalable programs but does not allow us to preserve things like network connections and can be slowed down by additional dependencies like ORMs and middleware. 

The Ideal Solution

It’s time we begin thinking about a new type of database, one more in line with the spirit of serverless and one that embraces iterative development and more unified tooling. We want this database to have the same automatic, on-demand scale as the rest of our application as well as handle global distribution that are hallmarks of the serverless promise. This ideal solution should be:

  1. Support for stateless connections with no limits.
  2. Auto-scaling both for the size of the machine and in the size of the database itself.
  3. Be securely accessible from both the client and the server to support both serverless APIs as well as Jamstack use cases.
  4. Globally distributed so data is closest to where it is needed always.
  5. Free of operational overhead so we don’t add complexity managing things like sharding, distribution, and backups.

If we are truly to embrace the serverless architecture, we need to ensure that our database scales along with the rest of the application. In this case, we have a variety of solutions some of which involve sticking with Postgres. Amazon Aurora is one example of a Postgres cloud solution that gives us automatic scalability and backups, and gives us some global distribution of data. However, Amazon Aurora is hardly easy to set up and doesn’t free us from all operational overhead. We also are not able to securely access our data from the client without building an accompanying API as it still follows the traditional Postgres security model.

Another option here are services like Hasura, that allow us to leverage Postgres but access our data by way of a GraphQL API. This solves our security issues when accessing data from the client and gets us much closer to the ease of use we have with many of our other serverless services. However, we are left to manage our database ourselves and this merely adds another layer on top of our database to manage the security. While the Hasura application layer is distributed, our database is not so we don’t get true global distribution with this system.

I think at this point we should turn toward some additional solutions that really hit all the points above. When looking at solutions outside of Postgres we have to add two additional requirements that put the solutions on par with the power of Postgres:

  1. Support for robust, distributed, ACID transactions.
  2. Support for relational modeling such that we can easily perform join operations on normalized data.

When we typically step outside of relational database systems into the world of schemaless solutions, ACID transactions and relational, normalized data are often things we sacrifice. So we want to make sure that when we optimize for serverless we are not losing the features that have made Postgres such a strong contender for so long.

Azure’s CosmosDB supports a variety of databases (both SQL and NoSQL) under the hood. CosmosDB also provides us with libraries that can work on both the client and server freeing us from an additional dependency like Hasura. We get some global distribution as well as automatic scale. However, we are still left with a lot of choices to make and are not free entirely from database management. We still have to manage our database size effectively and choose from many database options that all have their pros and cons.

What we really want is a fully managed solution where the operational overhead of choosing database size and the type of database can be abstracted away. In a general sense having to research many types of databases and estimate scale would be things that matter a lot less if we have all of the features we need. Fauna is a solution where we don’t have to worry about the size of the database nor do we have to select the type of database under the hood. We get the support of ACID transactions, global distribution, and no data loss without having to figure out the best underlying technology to achieve that. We also can freely access our database on the client or the server with full support for serverless functions. This allows us to flexibly create different types of applications in a variety of architectures such as JAMstack clients, serverless APIs, traditional long-running backends, or combinations of these styles.

When it comes to schemaless databases, we gain flexibility but are forced to think differently about our data model to most efficiently query our data. When moving away from Postgres this is often a subtle but large point of friction. With Fauna, we have to move into a schemaless design as you cannot opt into another database type. However, Fauna makes use of a unique document-relational database model. This allows us to utilize relational database knowledge and principles when modeling our data into collections and indexes. This is why I think it’s worth considering for people used to Postgres as the mental overhead is not the same as with other NoSql options.

Conclusion

Systems like Postgres have been powerful allies for building applications for over thirty years. The rise of agile and iterative development cycles led us to the serverless revolution before us today. We are able to build increasingly more complex applications with less operational overhead than ever before. That power requires us to think about databases differently and demand a similar level of flexibility and ease of management. We want to preserve the best qualities of a Postgres, like ACID transactions, but ditch the more unsavory aspects of working with the database like connection pooling, provisioning resources, security, distribution and managing scale, availability and reliability.

Solutions such as Amazon’s Aurora Serverless v2 create a serverless solution that works in this new world. There are also solutions like Hasura that sit on top of this to further fulfill the promise of serverless. We also have solutions like Cosmos DB and Fauna that are not based in Postgres but are built for serverless while supporting important Postgres functionality.

While Cosmos DB gives us a lot of flexibility in terms of what database we use, it still leaves us with many decisions and is not completely free of operational overhead. Fauna has made it so you don’t have to compromise on ACID transactions, relational modeling or normalized data — while still alleviating all the operational overhead of database management. Fauna is a complete rethinking of a database that is truly free of operational overhead. By combining the best of the past with the needs of the future Fauna has built a solution that behaves more like a data API and feels natural in a serverless future.


Follow Michael Rispoli on Twitter


The post Rethinking Postgres in a Post-Server World appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/rethinking-postgres-in-a-post-server-world/

Awesome Standalone (Web Components)

In his last An Event Apart talk, Dave made a point that it’s really only just about right now that Web Components are becoming a practical choice for production web development. For example, it has only been about a year since Edge went Chromium. Before that, Edge didn’t support any Web Component stuff. If you were shipping them long ago, you were doing so with fairly big polyfills, or in a progressive-enhancement style, where if they failed, they did so gracefully or in a controlled environment, say, an intranet where everyone has the same computer (or in something like Electron).

In my opinion, Web Components still have a ways to go to be compelling to most developers, but they are getting there. One thing that I think will push their adoption along is the incredibly easy DX of pre-built components thanks to, in part, ES Modules and how easy it is to import JavaScript.

I’ve mentioned this one before: look how silly-easy it is to use Nolan Lawson’s emoji picker:

That’s one line of JavaScript and one line of HTML to get it working, and another one line of JavaScript to wire it up and return a JSON response of a selection.

Compelling, indeed. DX, you might call it.

Web Components like that aren’t alone, hence the title of this post. Dave put together a list of Awesome Standalones. That is, Web Components that aren’t a part of some bigger more complex system1, but are just little drop-in doodads that are useful on their own, just like the emoji picker. Dave’s repo lists about 20 of them.

Take this one from GitHub (the company), a copy-to-clipboard Web Component:

Pretty sweet for something that comes across the wire at ~3KB. The production story is whatever you want it to be. Use it off the CDN. Bundle it up with your stuff. Self-host it be leave it a one-off. Whatever. It’s darn easy to use. In the case of this standalone, there isn’t even any Shadow DOM to deal with.

No shade on Shadow DOM, that’s perhaps the most useful feature of Web Components (and cannot be replicated by a library since it’s a native browser feature), but the options for styling it aren’t my favorite. And if you used three different standalone components with three different opinions on how to style through the Shadow DOM, that’s going to get annoying.

What I picture is developers dipping their toes into stuff like this, seeing the benefits, and using more and more of them in what they are building, and even building their own. Building a design system from Web Components seems like a real sweet spot to me, like many big names2 already do.

The dream is for people to actually consolidate common UI patterns. Like, even if we never get native HTML “tabs” it’s possible that a Web Component could provide them, get the UI, UX, and accessibility perfect, yet leave them style-able such that literally any website could use them. But first, that needs to exist.


  1. That’s a cool way to use Web Components, too, but easy gets attention, and that matters.
  2. People always mention Lightning Design System as a Web Components-based design system, but I’m not seeing it. For example, this accordion looks like semantic HTML with class names, not Web Components. What am I missing?

The post Awesome Standalone (Web Components) appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/awesome-standalone-web-components/

Links on Web Components

  • How we use Web Components at GitHub — Kristján Oddsson talks about how GitHub is using web components. I remember they were very early adopters, and it says here they released a <relative-time> component in 2014! Now they’ve got a whole bunch of open source components. So easy to use! Awesome! I wanted to poke around their HTML and see them in action, so I View’d Source and used the RegEx (<\w+-[\w|-|]+.*>) (thanks, Andrew) to look for them. Seven on the logged-in homepage, so they ain’t blowin’ smoke.
  • Using web components to encapsulate CSS and resolve design system conflicts — Tyler Williams says the encapsulation (Shadow DOM) of web components meant avoiding styling conflicts with an older CSS system. He also proves that companies that make sites for Git repos love web components.
  • Container Queries in Web Components — Max Böck shares that the :host of a web component can be the @container which is extremely great and is absolutely how all web components should be written.
  • Faster Integration with Web Components — Jason Grigsby does client work and says that web components don’t make integration fast or easy, they make integration fast and easy.
  • FicusJS — I remember being told once that native web components weren’t really meant to be used “raw” but meant to be low-level such that tooling could be built on top of them. We see that in competition amongst renderers, like lit-html vs htm. Then, in layers of tooling on top of that, like Ficus here, that adds a bunch of fancy stuff like state, methods, and events.
  • Shadow DOM and Its Effect on the Unofficial Styling API — Jim Nielsen expands on the idea I poked at on ShopTalk that the DOM is the styling API. It’s self-documenting, in a way. “As an author, you have to spend time and effort thinking about, architecting, and then documenting a styling API for your component. And as a consumer, you have to read, understand, and implement that API.” Yes. That’s why, to me, it feels like a good idea to have an option to “reach into the Shadow DOM from outside CSS” in an unencumbered way.
  • Awesome Standalones — I think Dave’s list here is exactly the kind of thing that gets developers feet wet and thinking about web components as actually useful.

Two years ago, hold true:


The post Links on Web Components appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/links-on-web-components/

Wednesday, May 26, 2021

A Thorough Analysis of CSS-in-JS

Wondering what’s even more challenging than choosing a JavaScript framework? You guessed it: choosing a CSS-in-JS solution. Why? Because there are more than 50 libraries out there, each of them offering a unique set of features.

We tested 10 different libraries, which are listed here in no particular order: Styled JSX, styled-components, Emotion, Treat, TypeStyle, Fela, Stitches, JSS, Goober, and Compiled. We found that, although each library provides a diverse set of features, many of those features are actually commonly shared between most other libraries.

So instead of reviewing each library individually, we’ll analyse the features that stand out the most. This will help us to better understand which one fits best for a specific use case.

Note: We assume that if you’re here, you’re already familiar with CSS-in-JS. If you’re looking for a more elementary post, you can check out “An Introduction to CSS-in-JS.”

Common CSS-in-JS features

Most actively maintained libraries that tackle CSS-in-JS support all the following features, so we can consider them de-facto.

Scoped CSS

All CSS-in-JS libraries generate unique CSS class names, a technique pioneered by CSS modules. All styles are scoped to their respective component, providing encapsulation without affecting any styling defined outside the component.

With this feature built-in, we never have to worry about CSS class name collisions, specificity wars, or wasted time spent coming up with unique class names across the entire codebase.

This feature is invaluable for component-based development.

SSR (Server-Side Rendering)

When considering Single Page Apps (SPAs) — where the HTTP server only delivers an initial empty HTML page and all rendering is performed in the browser — Server-Side Rendering (SSR) might not be very useful. However, any website or application that needs to be parsed and indexed by search engines must have SSR pages and styles need to be generated on the server as well.

The same principle applies to Static Site Generators (SSG), where pages along with any CSS code are pre-generated as static HTML files at build time.

The good news is that all libraries we’ve tested support SSR, making them eligible for basically any type of project.

Automatic vendor prefixes

Because of the complex CSS standardization process, it might take years for any new CSS feature to become available in all popular browsers. One approach aimed at providing early access to experimental features is to ship non-standard CSS syntax under a vendor prefix:

/* WebKit browsers: Chrome, Safari, most iOS browsers, etc */
-webkit-transition: all 1s ease;

/* Firefox */
-moz-transition: all 1s ease;

/* Internet Explorer and Microsoft Edge */
-ms-transition: all 1s ease;

/* old pre-WebKit versions of Opera */
-o-transition: all 1s ease;

/* standard */
transition: all 1s ease; 

However, it turns out that vendor prefixes are problematic and the CSS Working Group intends to stop using them in the future. If we want to fully support older browsers that don’t implement the standard specification, we’ll need to know which features require a vendor prefix.

Fortunately, there are tools that allow us to use the standard syntax in our source code, generating the required vendor prefixed CSS properties automatically. All CSS-in-JS libraries also provide this feature out-of-the-box.

No inline styles

There are some CSS-in-JS libraries, like Radium or Glamor, that output all style definitions as inline styles. This technique has a huge limitation, because it’s impossible to define pseudo classes, pseudo-elements, or media queries using inline styles. So, these libraries had to hack these features by adding DOM event listeners and triggering style updates from JavaScript,  essentially reinventing native CSS features like :hover, :focus and many more.

It’s also generally accepted that inline styles are less performant than class names. It’s usually a discouraged practice to use them as a primary approach for styling components.

All current CSS-in-JS libraries have stepped away from using inline styles, adopting CSS class names to apply style definitions.

Full CSS support

A consequence of using CSS classes instead of inline styles is that there’s no limitation regarding what CSS properties we can and can’t use. During our analysis we were specifically interested in:

  • pseudo classes and elements;
  • media queries;
  • keyframe animations.

All the libraries we’ve analyzed offer full support for all CSS properties.

Differentiating features

This is where it gets even more interesting. Almost every library offers a unique set of features that can highly influence our decision when choosing the appropriate solution for a particular project. Some libraries pioneered a specific feature, while others chose to borrow or even improve certain features.

React-specific or framework-agnostic?

It’s not a secret that CSS-in-JS is more prevalent within the React ecosystem. That’s why some libraries are specifically built for React: Styled JSX, styled-components, and Stitches.

However, there are plenty of libraries that are framework-agnostic, making them applicable to any project: Emotion, Treat, TypeStyle, Fela, JSS or Goober.

If we need to support vanilla JavaScript code or frameworks other than React, the decision is simple: we should choose a framework-agnostic library. But when dealing with a React application, we have a much wider range of options which ultimately makes the decision more difficult. So let’s explore other criteria.

Styles/Component co-location

The ability to define styles along with their components is a very convenient feature, removing the need to switch back-and-forth between two different files: the .css or .less/.scss file containing the styles and the component file containing the markup and behavior.

React Native StyleSheets, Vue.js SFCs, or Angular Components support co-location of styles by default, which proves to be a real benefit during both the development and the maintenance phases. We always have the option to extract the styles into a separate file, in case we feel that they’re obscuring the rest of the code.

Almost all CSS-in-JS libraries support co-location of styles. The only exception we encountered was Treat, which requires us to define the styles in a separate .treat.ts file, similarly to how CSS Modules work.

Styles definition syntax

There are two different methods we can use to define our styles. Some libraries support only one method, while others are quite flexible and support both of them.

Tagged Templates syntax

The Tagged Templates syntax allows us to define styles as a string of plain CSS code inside a standard ES Template Literal:

// consider "css" being the API of a generic CSS-in-JS library
const heading = css`
  font-size: 2em;
  color: ${myTheme.color};
`;

We can see that:

  • CSS properties are written in kebab case just like regular CSS;
  • JavaScript values can be interpolated;
  • we can easily migrate existing CSS code without rewriting it.

Some things to keep in mind:

  • In order to get syntax highlight and code suggestions, an additional editor plugin is required; but this plugin is usually available for popular editors like VSCode, WebStorm, and others.
  • Since the final code must be eventually executed in JavaScript, the style definitions need to be parsed and converted to JavaScript code. This can be done either at runtime, or at build time, incurring a small overhead in bundle size, or computation.
Object Styles syntax

The Object Styles syntax allows us to define styles as regular JavaScript Objects:

// consider "css" being the API of a generic CSS-in-JS library
const heading = css({
  fontSize: "2em",
  color: myTheme.color,
});

We can see that:

  • CSS properties are written in camelCase and string values must be wrapped in quotes;
  • JavaScript values can be referenced as expected;
  • it doesn’t feel like writing CSS, as instead we define styles using a slightly different syntax but with the same property names and values available in CSS (don’t feel intimidated by this, you’ll get used to it in no time);
  • migrating existing CSS would require a rewrite in this new syntax.

Some things to keep in mind:

  • Syntax highlighting comes out-of-the-box, because we’re actually writing JavaScript code.
  • To get code completion, the library must ship CSS types definitions, most of them extending the popular CSSType package.
  • Since the styles are already written in JavaScript, there’s no additional parsing or conversion required.
Library Tagged template Object styles
styled-components
Emotion
Goober
Compiled
Fela 🟠
JSS 🟠
Treat
TypeStyle
Stitches
Styled JSX

✅  Full support         ðŸŸ   Requires plugin          ❌  Unsupported

Styles applying method

Now that we know what options are available for style definition, let’s have a look at how to apply them to our components and elements.

Using a class attribute / className prop

The easiest and most intuitive way to apply the styles is to simply attach them as classnames. Libraries that support this approach provide an API that returns a string which will output the generated unique classnames:

// consider "css" being the API of a generic CSS-in-JS library
const heading_style = css({
  color: "blue"
});

Next, we can take the heading_style, which contains a string of generated CSS class names, and apply it to our HTML element:

// Vanilla DOM usage
const heading = `<h1 class="${heading_style}">Title</h1>`;

// React-specific JSX usage
function Heading() {
  return <h1 className={heading_style}>Title</h1>;
}

As we can see, this method pretty much resembles the traditional styling: first we define the styles, then we attach the styles where we need them. The learning curve is low for anyone who has written CSS before.

Using a <Styled /> component

Another popular method, that was first introduced by the styled-components library (and named after it), takes a different approach.

// consider "styled" being the API for a generic CSS-in-JS library
const Heading = styled("h1")({
  color: "blue"
});

Instead of defining the styles separately and attaching them to existing components or HTML elements, we use a special API by specifying what type of element we want to create and the styles we want to attach to it.

The API will return a new component, having classname(s) already applied, that we can render like any other component in our application. This basically removes the mapping between the component and its styles.

Using the css prop

A newer method, introduced by Emotion, allows us to pass the styles to a special prop, usually named css. This API is available only for JSX-based syntax.

// React-specific JSX syntax
function Heading() {
  return <h1 css=>Title</h1>;
}

This approach has a certain ergonomic benefit, because we don’t have to import and use any special API from the library itself. We can simply pass the styles to this css prop, similarly to how we would use inline styles.

Note that this custom css prop is not a standard HTML attribute, and needs to be enabled and supported via a separate Babel plugin provided by the library.

Library className <Styled /> css prop
styled-components
Emotion
Goober 🟠 2
Compiled 🟠 1
Fela
JSS 🟠 2
Treat
TypeStyle
Stitches 🟠 1
Styled JSX

✅  Full support          ðŸŸ  1  Limited support          ðŸŸ  2  Requires plugin          ❌  Unsupported

Styles output

There are two mutually exclusive methods to generate and ship styles to the browser. Both methods have benefits and downsides, so let’s analyze them in detail.

<style>-injected DOM styles

Most CSS-in-JS libraries inject styles into the DOM at runtime, using either one or more <style> tags, or using the CSSStyleSheet API to manage styles directly within the CSSOM. During SSR, styles are always appended as a <style> tag inside the <head> of the rendered HTML page.

There are a few key advantages and preferred use cases for this approach:

  1. Inlining the styles during SSR provides an increase in page loading performance metrics such as FCP (First Contentful Paint), because rendering is not blocked by fetching a separate .css file from the server.
  2. It provides out-of-the-box critical CSS extraction during SSR by inlining only the styles required to render the initial HTML page. It also removes any dynamic styles, thus further improving loading time by downloading less code.
  3. Dynamic styling is usually easier to implement, as this approach appears to be more suited for highly interactive user interfaces and Single-Page Applications (SPA), where most components are client-side rendered.

The drawbacks are generally related to the total bundle size:

  • an additional runtime library is required for handling dynamic styling in the browser;
  • the inlined SSR styles won’t be cached out-of-the-box and they will need to be shipped to the browser upon each request since they’re part of the .html file rendered by the server;
  • the SSR styles that are inlined in the .html page will be sent to the browser again as JavaScript resources during the rehydration process.
Static .css file extraction

There’s a very small number of libraries that take a totally different approach. Instead of injecting the styles in the DOM, they generate static .css files. From a loading performance point of view, we get the same advantages and drawbacks that come with writing plain CSS files.

  1. The total amount of shipped code is much smaller, since there is no need for additional runtime code or rehydration overhead.
  2. Static .css files benefit from out-of-the-box caching inside the browser, so subsequent requests to the same page won’t fetch the styles again.
  3. This approach seems to be more appealing when dealing with SSR pages or Static Generated pages since they benefit from default caching mechanisms.

However, there are some important drawbacks we need to take note of:

  • The first visit to a page, with an empty cache, will usually have a longer FCP when using this method compared to the one mentioned previously; so deciding if we want to optimize for first-time users or returning visitors could play a crucial role when choosing this approach.
  • All dynamic styles that can be used on the page will be included in the pre-generated bundle, potentially leading to larger .css resources that need to be loaded up front.

Almost all the libraries that we tested implement the first method, injecting the styles into the DOM. The only tested library which supports static .css file extraction is Treat. There are other libraries that support this feature, like Astroturf, Linaria, and style9, which were not included in our final analysis.

Atomic CSS

Some libraries took optimizations one step further, implementing a technique called atomic CSS-in-JS, inspired by frameworks such as Tachyons or Tailwind.

Instead of generating CSS classes containing all the properties that were defined for a specific element, they generate a unique CSS class for each unique CSS property/value combination.

/* classic, non-atomic CSS class */
._wqdGktJ {
  color: blue;
  display: block;
  padding: 1em 2em;
}

/* atomic CSS classes */
._ktJqdG { color: blue; }
._garIHZ { display: block; }
/* short-hand properties are usually expanded */
._kZbibd { padding-right: 2em; }
._jcgYzk { padding-left: 2em; }
._ekAjen { padding-bottom: 1em; }
._ibmHGN { padding-top: 1em; }

This enables a high degree of reusability because each of these individual CSS classes can be reused anywhere in the code base.

In theory, this works really great in the case of large applications. Why? Because there’s a finite number of unique CSS properties that are needed for an entire application. Thus, the scaling factor is not linear, but rather logarithmic, resulting in less CSS output compared to non-atomic CSS.

But there is a catch: individual class names must be applied to each element that requires them, resulting in slightly larger HTML files:

<!-- with classic, non-atomic CSS classes -->
<h1 class="_wqdGktJ">...</h1>

<!-- with atomic CSS classes -->
<h1 class="_ktJqdG _garIHZ _kZbibd _jcgYzk _ekAjen _ibmHGN">...</h1>

So basically, we’re moving code from CSS to HTML. The resulting difference in size depends on too many aspects for us to draw a definite conclusion, but generally speaking, it should decrease the total amount of bytes shipped to the browser.

Conclusion

CSS-in-JS will dramatically change the way we author CSS, providing many benefits and improving our overall development experience.

However, choosing which library to adopt is not straightforward and all choices come with many technical compromises. In order to identify the library that is best suited for our needs, we have to understand the project requirements and its use cases:

  • Are we using React or not? React applications have a wider range of options, while non-React solutions have to use a framework agnostic library.
  • Are we dealing with a highly interactive application, with client-side rendering? In this case, we probably aren’t very concerned about the overhead of rehydration, or care that much about extracting static .css files.
  • Are we building a dynamic website with SSR pages? Then, extracting static .css files may probably be a better option, as it would allow us to benefit from caching.
  • Do we need to migrate existing CSS code? Using a library that supports Tagged Templates would make the migration easier and faster.
  • Do we want to optimize for first-time users or returning visitors? Static .css files offer the best experience for returning visitors by caching the resources, but the first visit requires an additional HTTP request that blocks page rendering.
  • Do we update our styles frequently? All cached .css files are worthless if we frequently update our styles, thus invalidating any cache.
  • Do we re-use a lot of styles and components? Atomic CSS shines if we reuse a lot of CSS properties in our codebase.

Answering the above questions will help us decide what features to look for when choosing a CSS-in-JS solution, allowing us to make more educated decisions.


The post A Thorough Analysis of CSS-in-JS appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/a-thorough-analysis-of-css-in-js/

Creating Powerful Websites with Serverless-Driven CMS Development

Choosing the right tools to build a website for your organization is essential, but it can be tough to find the right fit. Simple site builders like Wix and Squarespace are easy for marketers to use, but severely limit developers when it comes to customizing site functionality. WordPress is a more robust content management system (CMS), but it requires clunky plugins with infrequent updates and potential security issues

Other site-building tools, such as Gatsby or Hexo, are developer-friendly, but make it very challenging for content creators without technical backgrounds to make even simple updates on their own. These tools often don’t meet the needs of large creative teams running corporate websites.

But there is an option that solves for both audiences. HubSpot’s CMS Hub is a content management system powered by a full CRM Platform that empowers developers to build advanced functionality and marketers to make updates and publish content on their own.

One of the features CMS Hub offers developers is the ability to create serverless functions. These functions make it possible to enhance a website’s backend functionality with integrated plugins that are much easier to develop, deploy, and maintain than third-party WordPress plugins. 

Throughout this article, you’ll get a hands-on look at how HubSpot serverless functions help you build custom websites that clients love. To provide a super-quick preview of what is possible, we’ll fetch news data using GET functions that could be used to populate a dynamic webpage. You’ll need to know some JavaScript to follow along. 

HubSpot Serverless Functions

Serverless architecture enables developers to build and run applications and services without managing the server’s infrastructure. You don’t need to provision, scale, and maintain servers or install and manage databases to host and serve your web applications. When your business grows, it is much easier to scale.

HubSpot’s serverless functions are as powerful as WordPress plugins. They are capable of interacting with HubSpot’s CRM platform as well as integrating with third-party services through APIs. You can use serverless functions to enhance your site, for example:

  • Getting data and storing it in HubDB or the HubSpot CRM
  • Integrating your website with third-party services like Google Forms
  • Creating event registration systems
  • Submitting forms that send data to other services

The functions’ code is stored in the developer file system and is accessed from the Design Manager user interface (UI) or the command-line interface (CLI). You can use the CLI to generate and edit the code locally using your preferred local development tools then upload these changes to HubSpot.

To try the example serverless function in the next section, you need to have access to a CMS Hub Enterprise account or sign up for a free developer testing account. We’ll deploy serverless functions into a site created based on the CMS Boilerplate.

(If you are not familiar with HubSpot development, you may want to check out the quick start guide before following along with the examples below.)

Fetching News Data Using GET Requests

Let’s start by implementing a serverless function that sends a GET request to a third-party REST API to fetch the latest news data using the Axios client. This API searches for online news articles that mention the keyword “HubSpot.”

Note: We’ll be using a third-party API available from NewsAPI.org to retrieve news data, so you first need to register for their API key.

APIs that require authentication or use API keys are not safe for a website’s frontend as they expose your credentials. Serverless functions are a good solution as an intermediary, keeping your credentials secret.

Head over to a CLI and run the following commands:

cd local-cms-dev
mkdir myfunctions
hs create function 

First, we navigate to our local CMS project, and we call the hs create function command to generate a simple boilerplate function.

You’ll be prompted for some information about your functions, such as:

  • Name of the folder where your function will be created. Enter myfunctions/getnews.
  • Name of the JavaScript file for your function. Enter getnews.
  • Select the HTTP method for the endpoint. Select GET.
  • Path portion of the URL created for the function. Enter getnews.

You should get a message saying that a function for the endpoint “/_hcms/API/getnews” has been created. This means, once uploaded, our function will be available from the /_hcms/API/getnews endpoint. 

Before uploading the function, let’s first implement our desired functionality.

Open the myfunctions\getnews.function\getnews.js file. You’ll find some boilerplate code for a serverless function that sends a GET request to the HubSpot search API. Remove the boilerplate code and leave only the following updated code:

const axios = require('axios');
const API_KEY = '<YOUR_API_KEY_HERE>';

exports.main = async (_, sendResponse) => {
   
};

Note that you should normally add your API key via the command-line interface hs secrets command, but adding it here is sufficient for the purpose of demonstrating the function.

We require the Axios library to send HTTP requests, and we export a main function that HubSpot executes when a request is made to the associated endpoint. We also define an API_KEY variable that holds the API key from the news API.

Next, inside the body of the main function, add the following code:

const response = await axios.get(`https://newsapi.org/v2/everything?q=HubSpot&sortBy=popularity&apiKey=${API_KEY}`);
sendResponse({ body: { response: response.data }, statusCode: 200 });

We call Axios to send a GET request to the API endpoint, then we call the sendResponse method to send the fetched data back to the client. We could call this API directly from the frontend code, but we would need to expose our API key, which should be secret. Thanks to the serverless function, fetching data happens on the server side, so we don’t have to expose the secret.

Finally, run the following command to upload your function:

hs upload myfunctions myfunctions

This command uploads files from the myfunctions local folder to a myfunctions folder (that will be created) in your account’s Design Manager.

Finally, run the method by visiting the /_hcms/API/getnews endpoint with your web browser. In our case, we need to visit this link. Here, you should see a list of news articles about HubSpot – albeit without any front-end design. 

While it is beyond the scope of this article, our next step would be to take the data from the NewsAPI and create a template that would allow us to output the news results onto a dynamic webpage. And with this, we’ll have a place where anyone can quickly catch up on all the latest news mentioning HubSpot or any other keyword you decide to include.  

Next Steps

When you need a small brochure-based website and won’t be making many updates, any CMS will do. However, when you are looking to create advanced digital experiences to grow your organization, HubSpot’s CMS Hub offers the functionality and flexibility you need. Plus, you can work with your preferred tools and modern workflows such as CLIs, integrated development environments (IDEs), and GitHub. 

Hopefully, this article has provided an initial glimpse of what is possible with HubSpot’s serverless functions. But don’t stop here, dive in and experiment with adding custom functionality to your own HubSpot-powered website. Your imagination is the limit. Sign up for a free developer test account to get started.

Further reading:


Ahmed Bouchefra is a developer and technical author with a BAC + 5 diploma in software development. Ahmed builds apps and authors technical content about JavaScript, Angular, Ionic, and more.


The post Creating Powerful Websites with Serverless-Driven CMS Development appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/creating-powerful-websites-with-serverless-driven-cms-development/