<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Davide Panelli</title>
    <description>The latest articles on Forem by Davide Panelli (@dpanelli).</description>
    <link>https://forem.com/dpanelli</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F357827%2F11e915af-4f61-4572-a8be-f9accc16585a.jpeg</url>
      <title>Forem: Davide Panelli</title>
      <link>https://forem.com/dpanelli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dpanelli"/>
    <language>en</language>
    <item>
      <title>Generating static sites with Svelte and a headless cms</title>
      <dc:creator>Davide Panelli</dc:creator>
      <pubDate>Thu, 07 May 2020 09:38:05 +0000</pubDate>
      <link>https://forem.com/dpanelli/generating-static-sites-with-svelte-and-a-headless-cms-4e8g</link>
      <guid>https://forem.com/dpanelli/generating-static-sites-with-svelte-and-a-headless-cms-4e8g</guid>
      <description>&lt;p&gt;JAMStack is becoming more and more popular because &lt;strong&gt;it's easy to scale and manage&lt;/strong&gt; for devops and always offers &lt;strong&gt;optimal performances for end-users&lt;/strong&gt;. There are a lot of native options to generate static websites, like &lt;a href="https://www.gatsbyjs.org/" rel="noopener noreferrer"&gt;GatsbyJS&lt;/a&gt; or the new features introduced in &lt;a href="https://www.contentchef.io/blog/ssg-with-next-and-headless-cms" rel="noopener noreferrer"&gt;NextJS(check out how to create static sites with NextJs)&lt;/a&gt;. Today we want to explore how to add headless cms to a Svelte app and how we can generate a static version of it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up
&lt;/h2&gt;

&lt;p&gt;To get started, you need to have nodejs( &amp;gt;= 10), git installed, and an active account of &lt;a href="https://www.contentchef.io" rel="noopener noreferrer"&gt;ContentChef.(You can start a free 30-day trial here)&lt;/a&gt;&lt;br&gt;
ContentChef is the headless cms that we are going to use in this example, and of course, the same concepts apply to any headless cms or external API to fetch data.&lt;br&gt;
For this tutorial, we will need the spaceID and the online API key that you can easily find and note down in the dashboard home, as you can see below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fcontentchef%2Fimage%2Fupload%2Fv1%2Fchefsite-2910%2FI49Zi00Uf7S%2Fspaceid" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fcontentchef%2Fimage%2Fupload%2Fv1%2Fchefsite-2910%2FI49Zi00Uf7S%2Fspaceid" alt="ContentChef Dashboard - Home"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Starting the example Svelte application
&lt;/h2&gt;

&lt;p&gt;For this mini-tutorial, we'll use the &lt;a href="https://github.com/ContentChef/svelte-starter" rel="noopener noreferrer"&gt;Svelte Starter&lt;/a&gt; provided with ContentChef, and we begin by cloning the repo and installing all the dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    git clone git@github.com:ContentChef/svelte-starter.git
    &lt;span class="nb"&gt;cd &lt;/span&gt;svelte-starter
    npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starter is a Sapper starter app (&lt;a href="https://sapper.svelte.dev" rel="noopener noreferrer"&gt;learn more about Sapper here&lt;/a&gt;), where we added a couple of pages.&lt;br&gt;
Let's explore the starter.&lt;br&gt;
Open the &lt;code&gt;./src/contentChef.js&lt;/code&gt; file to create and configure the ContentChef client ( &lt;a href="https://github.com/ContentChef/contentchef-node" rel="noopener noreferrer"&gt;from the JS/Typescript SDK&lt;/a&gt; ) by adding our spaceID and online API key noted down before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;configure&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@contentchef/contentchef-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;spaceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;YOUR_SPACEID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onlineChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onlineChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;YOUR_ONLINE_API_KEY&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example-ch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's start it up with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open up your browser at &lt;a href="https://localhost:3000/sites" rel="noopener noreferrer"&gt;https://localhost:3000/sites&lt;/a&gt;, and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fcontentchef%2Fimage%2Fupload%2Fv1%2Fchefsite-2910%2FL7ERWwDSvkq%2Fssg%2Fsapper_site" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fcontentchef%2Fimage%2Fupload%2Fv1%2Fchefsite-2910%2FL7ERWwDSvkq%2Fssg%2Fsapper_site" alt="Svelte example app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great! It's working correctly!&lt;br&gt;
This is also a server-side rendered svelte app.&lt;br&gt;
Just open up the &lt;code&gt;src/routes/sites/index.svelte&lt;/code&gt; file to see how simple is the integration with ContentChef.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;context=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onlineChannel&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../contentChef.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;onlineChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;contentDefinition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;top-site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;take&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;sites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/Card.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;getImageUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../contentChef.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sites&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;figure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.8em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;text-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;uppercase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;700&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0.5em&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;figure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;480px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;svelte:head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Sites from ContentChef&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svelte:head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Sites&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;figure&amp;gt;&lt;/span&gt;
    {#each sites as site}
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"prefetch"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/sites/{site.publicId}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Card&lt;/span&gt; &lt;span class="na"&gt;thumbnail=&lt;/span&gt;&lt;span class="s"&gt;{getImageUrl(site.payload.image)}&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;{site.payload.title}&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;{site.payload.url}&lt;/span&gt; &lt;span class="na"&gt;description=&lt;/span&gt;&lt;span class="s"&gt;{site.payload.description}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    {/each}
&lt;span class="nt"&gt;&amp;lt;/figure&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the &lt;strong&gt;list of sites is fetched from the cms delivery API&lt;/strong&gt;, and there's also a detail page for each item, and therefore, &lt;strong&gt;the number of pages of this example site is dictated by the cms&lt;/strong&gt; contents and not statically configured in the app.&lt;/p&gt;

&lt;p&gt;But now &lt;strong&gt;we want to make this static&lt;/strong&gt;, not only server side rendered!&lt;br&gt;
How can we staticize it , if we don't know the number and paths of pages upfront?&lt;/p&gt;
&lt;h2&gt;
  
  
  Making it static
&lt;/h2&gt;

&lt;p&gt;Here's wehere the magic of Sapper will help us.&lt;br&gt;
What we have to do? Well... &lt;strong&gt;basically nothing!&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Sapper allows you to export a static site with a single zero-config sapper export command.&lt;/strong&gt;&lt;br&gt;
When you run sapper export, Sapper begins with a  build of a production version of your app, as you had run sapper build, and copies the contents of your static folder to the destination. It then starts the server, and navigates to the root of your app. From there, it follows any &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; elements it finds, and captures any data served by the app.&lt;br&gt;
&lt;strong&gt;Yes it basically crawl your app and generate static html from it!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's see it in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx sapper &lt;span class="nb"&gt;export&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fcontentchef%2Fimage%2Fupload%2Fv1%2Fchefsite-2910%2FL7ERWwDSvkq%2Fssg%2Fsapper_build" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fcontentchef%2Fimage%2Fupload%2Fv1%2Fchefsite-2910%2FL7ERWwDSvkq%2Fssg%2Fsapper_build" alt="Console Output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whoa! That was easy! And as we can see from the console output all the pages and subpages have been crawled and generated.&lt;br&gt;
And then serve it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx serve __sapper__/export
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are done!&lt;/p&gt;

&lt;p&gt;We have seen how it's straightforward to generate a static version of your svelte + sapper websites, and it's also effortless to manage content with headless cms like &lt;a href="https://www.contentchef.io" rel="noopener noreferrer"&gt;ContentChef&lt;/a&gt;.&lt;br&gt;
If you liked the article please share it with some fellow who might enjoy it too!&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The advantages of a Headless CMS for 2020</title>
      <dc:creator>Davide Panelli</dc:creator>
      <pubDate>Wed, 29 Apr 2020 11:04:13 +0000</pubDate>
      <link>https://forem.com/dpanelli/the-advantages-of-a-headless-cms-for-2020-49jm</link>
      <guid>https://forem.com/dpanelli/the-advantages-of-a-headless-cms-for-2020-49jm</guid>
      <description>&lt;p&gt;Are you planning to leverage a new system for managing your digital content in 2020? If so, be sure to &lt;strong&gt;check out headless CMSs&lt;/strong&gt;! &lt;br&gt;
These systems are a great help for your content management efforts and aid you in distributing quality content across all of your digital channels effortlessly. &lt;br&gt;
Let's find out what benefits you can expect from the best headless CMSs for 2020.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a headless CMS?
&lt;/h2&gt;

&lt;p&gt;Before we delve into the advantages of using a headless CMS, let's first talk about what headless or decoupled content management is.&lt;br&gt;
If you look at more &lt;strong&gt;traditional CMS&lt;/strong&gt; like WordPress, you can see that its back-end is directly connected with the front-end of your website. With a &lt;strong&gt;headless CMS&lt;/strong&gt;, you are usually &lt;strong&gt;free to choose how you want to build your UI&lt;/strong&gt; since the front-end is decoupled from the back-end.&lt;br&gt;
You enter content in a secured admin interface and store it in a central content repository from which developers access content via an API. &lt;br&gt;
This allows you to &lt;strong&gt;display content on any channel&lt;/strong&gt;, be it your website, e-commerce site, or native app. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JH0uT055--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/L7ERWwDSvkq/CC_advantages_01" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JH0uT055--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/L7ERWwDSvkq/CC_advantages_01" alt="How a traditional CMS differs from a headless CMS"&gt;&lt;/a&gt;&lt;br&gt;
Now that we've clarified what a headless CMS is, we can discover its benefits – especially for 2020 and the years to come!&lt;br&gt;
How can your business benefit from a headless CMS?&lt;/p&gt;

&lt;h2&gt;
  
  
  Shorten time-to-market
&lt;/h2&gt;

&lt;p&gt;A headless CMS enables you to release new features or entirely new apps and websites in less time. One reason is that you typically use APIs to retrieve content from your CMS, saving you the time of building things within the restrictions of a more traditional system. Besides, you can quickly redesign and add new features to your products the way you see fit. &lt;br&gt;
In 2020, the market for digital products will continue to grow, and companies will strive to be more innovative and progressive than the competition. A decoupled CMS lets you act fast in this ever-changing technical landscape and offer high-quality digital experiences to your customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create multi-channel experiences
&lt;/h2&gt;

&lt;p&gt;With all the different devices that users can use to experience your digital product, it is becoming increasingly important to deliver customized experiences of the same content. Using a headless CMS, you only need to create content once and then distribute it to all your connected channels. These channels can be anything, be it your blog, e-commerce site, native app, or IoT device. &lt;br&gt;
So if you plan to offer your service or product on new devices in 2020, a headless CMS will help you lay the perfect foundation. Simply connect a new channel to your content management system and start building!&lt;/p&gt;

&lt;h2&gt;
  
  
  Provide users with tailor-made products
&lt;/h2&gt;

&lt;p&gt;Naturally, every device and type of digital product has different requirements regarding looks and functionality. Hence, it's of utmost importance to provide your users and customers with UIs that fit the medium perfectly, increasing satisfaction and trust in your brand. As you already know, trends come and go quickly – especially in the technology industry. With a headless CMS, you stay flexible enough to react to changes, experiment with new tech, and make your business keep pace. &lt;/p&gt;

&lt;h2&gt;
  
  
  What advantages can developers expect from headless CMSs in 2020?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Focus on programming
&lt;/h2&gt;

&lt;p&gt;You probably have a pretty solid idea of what a perfect day as a front-end developer should look like. Working on an app's UI and then being disrupted by some CMS problems is most likely not part of this vision. Fortunately, with a headless CMS, you can spend your valuable time creating UIs hassle-free, without worrying about the limitations of a content management system. &lt;br&gt;
When you switch to a headless CMS in 2020, you can finally try out all the new technologies and experiment in a safe and open environment. Program as you see fit, and always work with real and accurate data from your headless CMS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create UIs using your favorite front-end stack
&lt;/h2&gt;

&lt;p&gt;Since you use APIs to retrieve content from a headless CMS, you can usually work with your beloved and proven front-end stack. Many headless CMSs also offer SDKs for various programming languages, which make working with the system even more straightforward. As a result, you don't need to learn a CMS-specific template language or use frameworks that you don't know or like. Also, if you want to try a new front-end framework or library in 2020, a headless CMS won't stop you! &lt;/p&gt;

&lt;h2&gt;
  
  
  Get things done faster
&lt;/h2&gt;

&lt;p&gt;Continually releasing new features and bug fixes is essential for your business to stay relevant to the market. As discussed above, a headless CMS can help you reduce time-to-market times by stripping away the complexity of more traditional content management systems. Another great advantage of headless CMSs is that you and your entire team can work with real and accurate data in all development environments right from the start. As a result, you don't have to rely on hardcoded dummy data during development and always see what your user interface will look like for your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of a headless CMS for designers in 2020
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Focus on designing
&lt;/h2&gt;

&lt;p&gt;Designers shouldn't have to worry about the CMS used and its restrictions. Therefore, a headless CMS is a perfect opportunity to take that burden off the shoulders of design experts. Get creative and think outside the box to come up with new and innovative ways to provide users with great experiences. In this way, your company can take a leading role in the market and deliver valuable products and services to your customers in 2020 – and in the years to come.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improve collaboration with developers
&lt;/h2&gt;

&lt;p&gt;The digital products we develop today require designers and developers to work closely together. Only then can companies publish the best digital solutions in terms of appearance and functionality. Both parties have valuable insights and expertise to share with one another that can take your products to the next level. A headless CMS relieves most of the operational burdens of conventional systems and gives you more time and freedom to innovate, design, and build with new technologies in 2020.&lt;/p&gt;

&lt;h2&gt;
  
  
  ContentChef helps you achieve your content goals in 2020
&lt;/h2&gt;

&lt;p&gt;A headless CMS can help you in several ways, whether you are a business stakeholder, developer, or designer.&lt;br&gt;
If you want to distribute content to multiple channels and release tailored digital experiences, our headless CMS may just be what you're looking for. &lt;br&gt;
Why not give ContentChef a try? We invite you to &lt;a href="https://contentchef.io"&gt;sign up for a 30-day trial&lt;/a&gt; and see for yourself how you can benefit from a headless CMS.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>headlesscms</category>
      <category>frontend</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Static site generation with NextJs and a headless CMS</title>
      <dc:creator>Davide Panelli</dc:creator>
      <pubDate>Tue, 21 Apr 2020 14:09:44 +0000</pubDate>
      <link>https://forem.com/dpanelli/static-site-generation-with-nextjs-and-a-headless-cms-4cj1</link>
      <guid>https://forem.com/dpanelli/static-site-generation-with-nextjs-and-a-headless-cms-4cj1</guid>
      <description>&lt;p&gt;In this article, we will briefly explore the difference between server-side rendering(SSR) and static site generation(SSG) and implement both of them in a simple NextJS application fetching data from a Headless CMS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What and why use SSR or SSG
&lt;/h2&gt;

&lt;p&gt;Modern websites to &lt;strong&gt;always stay performant&lt;/strong&gt; for users and search engines are employing SSR or SSG techniques.&lt;br&gt;
&lt;a href="https://nextjs.org/"&gt;NextJS&lt;/a&gt; is a great React framework to implement both of them quickly and straightforwardly, and we will use it to achieve them. But first, explore the differences between them and some pros and cons.&lt;/p&gt;

&lt;p&gt;SSR-enabled pages are generated runtime on the server at each user request(if not cached in someway!).Instead, SSG pages are created at build time and served to the users.&lt;/p&gt;

&lt;p&gt;The main advantages of SSR pages are that the content is always up-to-date, and there is no need to trigger a rebuild and redeploy of the website when some content changes in the CMS. The downside is that each request executes server-side code to create the HTML by fetching content from the cms Delivery API; this, of course, creates a slower response for the users.&lt;/p&gt;

&lt;p&gt;With SSG, all the pages are pre-generated at build-time. So they can easily be distributed through CDN, creating the fastest possible experience for the users and also making Google happy for SEO purposes. The main drawback is that each time content changes in the CMS, a new build it's needed to make content live, and this may be suboptimal if your website needs constant changes!&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up a example application with NextJS and Headless CMS support
&lt;/h2&gt;

&lt;p&gt;To complete this mini-tutorial, you will need git and Nodejs  ( v10.13 or above) installed and working in your machine and a trial account of &lt;a href="https://www.contentchef.io"&gt;ContentChef&lt;/a&gt;, the headless CMS that we are going to use in these examples.&lt;/p&gt;

&lt;p&gt;Let's start by cloning the repo of our &lt;a href="https://github.com/ContentChef/nextjs-starter"&gt;NextJS starter&lt;/a&gt; and installing all the dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:ContentChef/nextjs-starter.git
&lt;span class="nb"&gt;cd &lt;/span&gt;nextjs-starer
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is a brand-new NextJs application with the ContentChef SDK installed, as we will use to fetch content from the headless CMS API.&lt;/p&gt;

&lt;p&gt;It's a simple website that displays a list of websites and a detail page for each of them.All the sample data are pre-loaded on ContentChef account so you don't have to do nothing about that.&lt;/p&gt;

&lt;p&gt;Get your &lt;strong&gt;SpaceID and Online API key&lt;/strong&gt; from the dashboard. You will find them on the homepage of the dashboard like in the screenshot below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yC7rWTYg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/I49Zi00Uf7S/spaceid" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yC7rWTYg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/I49Zi00Uf7S/spaceid" alt="SpaceId &amp;amp; Online API Key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's open the file &lt;code&gt;./services/contentChefClient.js&lt;/code&gt; and fill the pieces of information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ContentChefClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createUrl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@contentchef/contentchef-node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ContentChef&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;targetDate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;defaultChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example-ch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;onlineChannel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ContentChefClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;spaceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-contentChef-spaceId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;targetDate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onlineChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onlineChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-contentChef-api-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultChannel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Try the application to be sure that everything is in place by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Open the browser and head to &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;, and you should see the list of the websites, and by clicking on one of them, you will access to the detail of that website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vGPzK3bW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/L7ERWwDSvkq/ssg/simple_app" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vGPzK3bW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/L7ERWwDSvkq/ssg/simple_app" alt="Examlpe app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great, this simple app has &lt;strong&gt;already SSR enabled!&lt;/strong&gt;&lt;br&gt;
In fact, NextJS makes it extremely easy to create applications with SSR because you just need to export a function named &lt;code&gt;getServerSideProps&lt;/code&gt; to instruct the framework that you want a page to be server-side rendered.&lt;br&gt;
This is the example of the list page where we load the contents from the CMS in a very straightforward way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;contentChef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../services/contentChefClient&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/layout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;topSites&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;
    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ContentChef Top Sites&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Welcome&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://contentchef.io&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;ContentChef&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&amp;gt; + &amp;lt;a href="https:/&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;nextjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;Next.js&amp;lt;/a&amp;gt; tutorial
      &amp;lt;/h1&amp;gt;
      &amp;lt;p className=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;
        Top Sites
      &amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div style={{ width: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; }}&amp;gt;
      {topSites.map((site, index) =&amp;gt; (
        &amp;lt;Link
          key={`top-site-${index}`}
          href={'/top-site/[publicId]'}
          as={`/top-site/${site.publicId}`}
        &amp;gt;
          &amp;lt;a style={{ textDecoration: 'initial' }}&amp;gt;
            &amp;lt;Card
              key={`top-site-${index}`}
              image={contentChef.getImageUrl(site.payload.image)}
              title={site.payload.title}
              description={site.payload.description}
              url={site.payload.url}
            /&amp;gt;
          &amp;lt;/a&amp;gt;
        &amp;lt;/Link&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  &amp;lt;/Layout&amp;gt;
);

//With this function we instruct Next to use SSR for this page!
export async function getServerSideProps() {
  const result = await contentChef.searchContents();
  return {
    props: { topSites: result }
  }
}

export default Home

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Enable SSG for static routes
&lt;/h2&gt;

&lt;p&gt;Now let's change the code to &lt;strong&gt;generate a static version&lt;/strong&gt; of the same website!&lt;/p&gt;

&lt;p&gt;We will start from the list page, which will be fairly easy. To instruct the framework to generate the page at build time, you need to export a function named &lt;code&gt;getStaticProps&lt;/code&gt;, and that's all!&lt;/p&gt;

&lt;p&gt;So let's change the code accordingly in the index page above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//SSR version&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getServerSideProps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contentChef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchContents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;topSites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//And Just rename it!&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticProps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contentChef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchContents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;topSites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And now verify that's working with a build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And let's look the output in console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---Ff8Nnud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/L7ERWwDSvkq/ssg/home_static" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---Ff8Nnud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/L7ERWwDSvkq/ssg/home_static" alt="Home is now static"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tada! &lt;strong&gt;The home page list is now static!&lt;/strong&gt;&lt;br&gt;
But we have not finished yet. We want to create a &lt;strong&gt;static version of all the pages&lt;/strong&gt;, including the detail pages, but now we see they're deployed as a lambda.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enable SSG for dynamic routes
&lt;/h2&gt;

&lt;p&gt;This step's a little bit trickier because we need to deal with the dynamic nature of the number of pages that we want to generate from our headless CMS, one for each website detail page.&lt;br&gt;
To do that, we need to implement the &lt;code&gt;getStaticProps&lt;/code&gt; function for the single page and also add a &lt;code&gt;getStaticPaths&lt;/code&gt; function to tell to NextJs the paths we want to be generated.&lt;br&gt;
Let's see the code to implement in &lt;code&gt;./pages/top-site/[publicId].js&lt;/code&gt; file by opening it and removing the old &lt;code&gt;getServerSideProps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We start by defining the &lt;code&gt;getStaticPaths&lt;/code&gt; function,  to read the list of contents PublicIDs from the Delivery API and creates a list of "Paths" to be processed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticPaths&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sites&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contentChef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchContents&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;publicIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sites&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;publicIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicId&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt; &lt;span class="na"&gt;publicId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;publicId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, adding the &lt;code&gt;getStaticProps&lt;/code&gt; function is pretty straightforward and similar to the one used for the list, we just need a content PublicID to fetch it from ContentChef.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStaticProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contentChef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;topSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;cloudName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloudName&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's try it by regenerating it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
npm run start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And check again the console output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RXxmHPIs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/L7ERWwDSvkq/ssg/all_static" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RXxmHPIs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/contentchef/image/upload/v1/chefsite-2910/L7ERWwDSvkq/ssg/all_static" alt="All static pages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yahoo! All the pages are now static and you can browse them at &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Triggering builds on a CI/CD pipeline
&lt;/h2&gt;

&lt;p&gt;As you can see, generating SSR or SSG sites with next and a Headless CMS like ContentChef is fast and straightforward. With ContentChef, you can also easily add &lt;strong&gt;webhooks&lt;/strong&gt;, so when you publish new content is easy to &lt;strong&gt;trigger a rebuild and redeploy&lt;/strong&gt; of your site on CI/CD.&lt;/p&gt;

&lt;p&gt;Why not give &lt;a href="https://www.contentchef.io"&gt;ContentChef&lt;/a&gt; and NextJS a try? Experience the benefits of a headless CMS  for SSR and SSG for yourself!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>node</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
