<?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: Kontent.ai</title>
    <description>The latest articles on Forem by Kontent.ai (@kontent_ai).</description>
    <link>https://forem.com/kontent_ai</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%2Forganization%2Fprofile_image%2F1748%2F147e49e7-90aa-4592-8456-409065b30da4.png</url>
      <title>Forem: Kontent.ai</title>
      <link>https://forem.com/kontent_ai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kontent_ai"/>
    <language>en</language>
    <item>
      <title>How To Check If Array Is Empty In TypeScript</title>
      <dc:creator>Ondrej Polesny</dc:creator>
      <pubDate>Wed, 08 Dec 2021 09:12:06 +0000</pubDate>
      <link>https://forem.com/kontent_ai/how-to-check-if-array-is-empty-in-typescript-573k</link>
      <guid>https://forem.com/kontent_ai/how-to-check-if-array-is-empty-in-typescript-573k</guid>
      <description>&lt;p&gt;When processing JSON responses in TypeScript, how do you safely check if a variable is an array and is not empty?&lt;/p&gt;

&lt;p&gt;Let's say we get a response from an API (in this example, it's &lt;a href="https://docs.kontent.ai/reference/kontent-apis-overview"&gt;Kontent API&lt;/a&gt;):&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogPosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;deliveryClient&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPost&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blog_post&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="nx"&gt;toPromise&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We expect that response to be an array of &lt;code&gt;BlogPost&lt;/code&gt; objects. Also, note the &lt;code&gt;?.&lt;/code&gt; notation that allows us to unwind the response and select just the data we need. If the response doesn't have the expected format, we will get &lt;code&gt;null&lt;/code&gt; instead of &lt;code&gt;undefined&lt;/code&gt; error.&lt;/p&gt;

&lt;p&gt;Therefore, we first need to check if the response is a defined array:&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogPosts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Response has a wrong format&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Array.isArray&lt;/code&gt; function will catch all possible values:&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="c1"&gt;// all these calls return false&lt;/span&gt;
&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;

&lt;span class="c1"&gt;// DON'T DO THIS&lt;/span&gt;
&lt;span class="c1"&gt;// as there is no need for checking the variable separately&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogPosts&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogPosts&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;// DO THIS&lt;/span&gt;
&lt;span class="c1"&gt;// Array.isArray() is doing the null and&lt;/span&gt;
&lt;span class="c1"&gt;// undefined check automatically&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogPosts&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;&lt;em&gt;Note: Check &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray"&gt;MDN Web Docs&lt;/a&gt; for more information.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then, we check if the array contains any items via &lt;code&gt;.length&lt;/code&gt; property:&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&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;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Response contains no items&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it. 💪&lt;/p&gt;

&lt;p&gt;The full code looks like this:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blogPosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BlogPost&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;deliveryClient&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogPost&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blog_post&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="nx"&gt;toPromise&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogPosts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;blogPosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No data&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="c1"&gt;// all good here&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blogPosts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also wrap the code in &lt;code&gt;try/catch&lt;/code&gt; block to make sure you also catch errors from network communication.&lt;/p&gt;

&lt;p&gt;If you need any help with processing your Kontent data, &lt;a href="https://bit.ly/kontent-discord"&gt;join our Discord&lt;/a&gt;! 😎&lt;/p&gt;

</description>
      <category>array</category>
      <category>empty</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Kontent Horizons developers news flash</title>
      <dc:creator>Ondrej Polesny</dc:creator>
      <pubDate>Tue, 09 Nov 2021 08:25:12 +0000</pubDate>
      <link>https://forem.com/kontent_ai/kontent-horizons-developers-news-flash-1c4</link>
      <guid>https://forem.com/kontent_ai/kontent-horizons-developers-news-flash-1c4</guid>
      <description>&lt;p&gt;Hey developers, thank you for attending Kontent Horizons! If you’re excited about our updates, find more information about them below or get in touch with us on &lt;a href="https://bit.ly/kontent-discord"&gt;Discord&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Documentation
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.kontent.ai/tutorials/develop-apps/overview?tech=javascript"&gt;New streamlined overview of tech stacks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  JavaScript + TypeScript
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Kentico/kontent-delivery-sdk-js/tree/vnext"&gt;Delivery SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Kentico/kontent-management-sdk-js"&gt;Management SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Kentico/kontent-model-generator-js"&gt;Model generator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  .NET
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Kentico/kontent-delivery-sdk-net"&gt;Delivery SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Kentico/kontent-management-sdk-net/tree/vNext"&gt;Management SDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Nuxt 3
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ondrabus/nuxt3-starter-kontent-lumen"&gt;Sample app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ondrabus/kontent-nuxt3-module"&gt;Kontent module&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Discord
&lt;/h1&gt;

&lt;p&gt;Join us on &lt;a href="https://bit.ly/kontent-discord"&gt;Discord&lt;/a&gt; to discuss other topics, like GraphQL :-)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What Gatsby v4 brings to your static site?</title>
      <dc:creator>Ondrej Polesny</dc:creator>
      <pubDate>Tue, 21 Sep 2021 15:11:33 +0000</pubDate>
      <link>https://forem.com/kontent_ai/what-gatsby-v4-brings-to-your-static-site-3bao</link>
      <guid>https://forem.com/kontent_ai/what-gatsby-v4-brings-to-your-static-site-3bao</guid>
      <description>&lt;p&gt;The new version of Gatsby is available in beta and brings many improvements. How are they going to affect you and the development and maintenance of your sites?&lt;/p&gt;

&lt;p&gt;In this article, I summarize the key new features that Gatsby v4 brings and explain how each of them will affect your daily work with a Gatsby site.&lt;/p&gt;

&lt;h1&gt;
  
  
  Gatsby v4 Improvements
&lt;/h1&gt;

&lt;p&gt;Gatsby v4 was officially introduced and made available as a public beta last week during Gatsby Camp and it brought major updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New rendering modes for pages&lt;/li&gt;
&lt;li&gt;Parallel query processing&lt;/li&gt;
&lt;li&gt;Improved Gatsby Cloud preview&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's start with the first and see what changes for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  New rendering modes for pages
&lt;/h2&gt;

&lt;p&gt;Gatsby introduced support for two additional modes and now lets you use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSG - static site generation = pages generated during a build&lt;/li&gt;
&lt;li&gt;DSG - deferred static generation&lt;/li&gt;
&lt;li&gt;SSR - server-side rendered&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SSG is the original concept of static site generators, so let's start with the second one - the deferred static generation. It's not a new concept. We've been successfully using it with &lt;a href="https://vercel.com/docs/next.js/incremental-static-regeneration" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; and Netlify had already introduced a similar improvement for other static site generators with their &lt;a href="https://www.netlify.com/blog/2021/04/14/distributed-persistent-rendering-a-new-jamstack-approach-for-faster-builds/" rel="noopener noreferrer"&gt;Distributed Persistent Rendering&lt;/a&gt; and &lt;a href="https://docs.netlify.com/configure-builds/on-demand-builders/" rel="noopener noreferrer"&gt;On-Demand Builders&lt;/a&gt;. The idea is, you pre-build only the core parts of a large site and leave the rest to be generated and cached (stored) only after the server receives a request for a specific page from the first visitor. In other words, on-demand.&lt;/p&gt;

&lt;p&gt;Having DSG now available in Gatsby is definitely a great improvement. In the past, it was challenging to use Gatsby for large sites as the build times grew with content significantly. Now, with DSG and Server-Side-Rendering mode (that we all saw coming with the introduction of serverless functions this spring), you now get full control over how each page of your site gets rendered.&lt;/p&gt;

&lt;p&gt;However, there is one downside. From my experience, Gatsby is often used by beginners. Don't get me wrong - many of them are experienced developers, just not with JavaScript. And what they value the most is the low entry barrier. They could get a site up and running very quickly, they didn't have to read any docs as the GraphQL data sourcing allowed them to see every content that's available, and for anything extra, there was always a plugin.&lt;/p&gt;

&lt;p&gt;While all of that is still true, the added rendering modes (SSR, DSG) require developers to make informed decisions that require them to learn more. The time they need to invest to see their new site live increases. And the same applies to onboarding developers.&lt;/p&gt;

&lt;p&gt;Now, you may argue here that they would need to learn that with any framework anyway and that's true. But Gatsby, until now, was a perfect stepping stone into Jamstack on React. Just like Gridsome is on Vue. I've seen many agencies tipping their toe in the Jamstack water with Gatsby and the low entry barrier was the biggest attraction for them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: See the full explanation of Gatsby's rendering modes in &lt;a href="https://youtu.be/6Eglvixg4eg?t=307" rel="noopener noreferrer"&gt;this video&lt;/a&gt; or in &lt;a href="https://v4.gatsbyjs.com/docs/conceptual/rendering-options/" rel="noopener noreferrer"&gt;their docs&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallel query processing
&lt;/h2&gt;

&lt;p&gt;Another great improvement towards decreasing the build time. It's actually not optimizing the build but distributes the computation of page queries to multiple processor cores that work in parallel. The Gatsby team made this possible by moving the content from the Redux store to &lt;a href="https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database" rel="noopener noreferrer"&gt;LMDB&lt;/a&gt; that supports concurrent access. So we're getting better build time by efficiently using the hardware. Good thing is, you don't need to take any action besides upgrading to the newest version of Gatsby.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gatsby Cloud preview update
&lt;/h2&gt;

&lt;p&gt;If you saw &lt;a href="https://www.youtube.com/watch?v=06K_lGH9hrY" rel="noopener noreferrer"&gt;my talk at Gatsby Conf&lt;/a&gt; this spring, you know that editors expect their CMS to generate previews of their content and they expect it to do it instantly. With Gatsby, this was made possible with incremental builds that took only a few seconds. Now, the Gatsby team took the preview experience on Gatsby Cloud one level further and implemented a UI panel that tells the editor in real-time that preview is coming.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4r07oymd4scsvtpyvl8l.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4r07oymd4scsvtpyvl8l.png" alt="New Gatsby Cloud Preview panel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, apart from that, the Gatsby team is constantly working on differentiating Gatsby Cloud from other hosting platforms and now claims that it is capable of 10x faster deploys.&lt;/p&gt;

&lt;h1&gt;
  
  
  Kontent and Gatsby v4
&lt;/h1&gt;

&lt;p&gt;If you're using &lt;a href="https://kontent.ai/" rel="noopener noreferrer"&gt;Kontent by Kentico&lt;/a&gt; as a content source for your Gatsby site, you're probably using both of these packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/Kentico/kontent-gatsby-packages/blob/master/packages/gatsby-source-kontent#readme" rel="noopener noreferrer"&gt;Gatsby Source Kontent Plugin&lt;/a&gt;&lt;/strong&gt;
Plugin providing data from Kontent REST API to Gatsby GraphQL model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/Kentico/kontent-gatsby-packages/blob/master/packages/gatsby-kontent-components#readme" rel="noopener noreferrer"&gt;Gatsby Kontent Components&lt;/a&gt;&lt;/strong&gt;
Package with React components that process Kontent data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We've prepared the new source plugin version ahead of the Gatsby v4 beta release. However, it will be merged only after the v4 is fully released, so until then, make sure to check out &lt;a href="https://github.com/Kentico/kontent-gatsby-packages/pull/192" rel="noopener noreferrer"&gt;this version&lt;/a&gt; of the source plugin.&lt;/p&gt;

&lt;p&gt;The Gatsby Kontent Components package is fully compatible with both the current and the new versions of the source plugin.&lt;/p&gt;

&lt;h1&gt;
  
  
  Should I upgrade?
&lt;/h1&gt;

&lt;p&gt;The presented changes have one thing in common - Gatsby is trying hard to enable large-scale applications. They constantly work on decreasing build times (which interestingly brought new potential with the move of the content store), providing options to avoid building everything, improving the Gatsby Cloud services, focusing more on the content editor experience, and working closely with strategic partners.&lt;/p&gt;

&lt;p&gt;If your site runs on Gatsby, I'd encourage you to try out the new features as they solve the problems of the majority of sites.&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>react</category>
      <category>jamstack</category>
      <category>javascript</category>
    </item>
    <item>
      <title>🎉 Weekly Win (27/2021)</title>
      <dc:creator>Michael Kinkaid</dc:creator>
      <pubDate>Wed, 30 Jun 2021 20:04:47 +0000</pubDate>
      <link>https://forem.com/kontent_ai/weekly-win-27-2021-3a2j</link>
      <guid>https://forem.com/kontent_ai/weekly-win-27-2021-3a2j</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Kentico Kontent support is fantastic. If you're stuck, reach out to them!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Did I Need Support?
&lt;/h2&gt;

&lt;p&gt;Web Spotlight.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Sorry—web what, now?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'm glad you asked (otherwise this would have been a very short post indeed).&lt;/p&gt;

&lt;h2&gt;
  
  
  Headless for Those with Heads
&lt;/h2&gt;

&lt;p&gt;Kentico Kontent is a 100% headless CMS. It ticks all the boxes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API-first&lt;/li&gt;
&lt;li&gt;Technology agnostic&lt;/li&gt;
&lt;li&gt;Channel agnostic&lt;/li&gt;
&lt;li&gt;Software-as-a-Service&lt;/li&gt;
&lt;li&gt;Has the word "&lt;em&gt;content&lt;/em&gt;" in its name, kinda.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All cool stuff, &lt;em&gt;but&lt;/em&gt;...&lt;/p&gt;

&lt;p&gt;If you're making websites with a headless CMS, then the fact you can't easily see what you're doing—outside of having the site open in another tab—can make updates a little tiring (a lot of clicking through nested content items to find that one bit of text you need to update).&lt;/p&gt;

&lt;p&gt;⚠️ Personal Opinion Alert: &lt;a href="https://dev.to/meandmyrobot/headless-cms-just-isn-t-good-enough-26a6"&gt;headless could be better&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kentico Kontent is Better
&lt;/h2&gt;

&lt;p&gt;A really great differentiator between Kentico Kontent and other headless CMS platforms is an app extension developed by Kentico called &lt;a href="https://webspotlight.kontent.ai/" rel="noopener noreferrer"&gt;Web Spotlight&lt;/a&gt;. Web Spotlight extends Kentico Kontent with visual page building.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbaenurt7wzhn0xfpz3td.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbaenurt7wzhn0xfpz3td.png" alt="Image shows the Web Spotlight user interface. A web page has edit buttons beside the text."&gt;&lt;/a&gt;&lt;/p&gt;
Click the edit button (pencil icon) beside the text in your web page to edit the content in your content inventory.



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;You can see the web page you're working on &lt;em&gt;within&lt;/em&gt; the Kentico Kontent app. This provides an easy visual way to find and edit content, versus digging through your content model. &lt;em&gt;Sweeeeet&lt;/em&gt; 🙌&lt;/p&gt;

&lt;h2&gt;
  
  
  Let Me Play with the New Features—NOW!
&lt;/h2&gt;

&lt;p&gt;Web Spotlight just released a bunch of new features. The biggest of these is the &lt;strong&gt;Add Button&lt;/strong&gt;. This swanky feature allows editors to add components into the page they're working on.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl1vsjlridktlx9fvg38.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl1vsjlridktlx9fvg38.png" alt="Image shows the updated Web Spotlight UI. The web page has circular add buttons that editors can press to add components to pages."&gt;&lt;/a&gt;&lt;/p&gt;
New orange buttons! Click them to add or create components into your web page.



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Needless to say, once I spied the announcement on the update, I was eager to get the Add Button working on our site (Kontent + Gatsby). We're doing a bit of a refactor with the content model, so I'm already knee-deep in migration scripts. Where to start? The homepage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Read &lt;a href="https://github.com/Kentico/kontent-smart-link" rel="noopener noreferrer"&gt;the docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Make a feature branch&lt;/li&gt;
&lt;li&gt;Make sure I'm on the latest version of the Kentico Kontent Smart Link SDK&lt;/li&gt;
&lt;li&gt;Add some code (new data attributes)&lt;/li&gt;
&lt;li&gt;Paranoid check I'm playing in the Kentico Kontent development environment and not production 😉&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gatsby develop -S&lt;/code&gt; because I'm impatient and can't be bothered with ngrok at this exact moment&lt;/li&gt;
&lt;li&gt;Update the homepage preview URL in Kentico Kontent to &lt;code&gt;https://localhost:8000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;See the new Add Button (#&lt;em&gt;win&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Click on the new Add Button (heart now racing)&lt;/li&gt;
&lt;li&gt;And...&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/ySpxjJmsq9gsw/source.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ySpxjJmsq9gsw/source.gif" title="WOMP WOMP" alt="WOMP WOMP"&gt;&lt;/a&gt;&lt;/p&gt;
WOMP WOMP.



&lt;h2&gt;
  
  
  Sad Face 🙁
&lt;/h2&gt;

&lt;p&gt;Nope. Error. Something about "&lt;em&gt;missing data attributes&lt;/em&gt;"—even though they were right there in the code. RIGHT THERE. I should be looking pretty. All other Web Spotlight features are working. The Kentico Kontent SmartLink SDK is hooked up correctly. Why?!&lt;/p&gt;

&lt;h2&gt;
  
  
  Support to the Rescue
&lt;/h2&gt;

&lt;p&gt;I was about to stomp off to the kitchen to comfort eat when I spotted the wee-help-thingamajig in Kentico Kontent's UI:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4qxkplkqv3w3xrqtw3m.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4qxkplkqv3w3xrqtw3m.png" alt="Support Button"&gt;&lt;/a&gt;&lt;/p&gt;
Talk to—and get support from—a REAL person.



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Yes. Yes, I do have questions. I quickly typed up the issue I was experiencing and within a minute a very polite and capable chap called Keith started helping me through the issue.&lt;/p&gt;

&lt;p&gt;I explained that I was trying to set up the Add Button with a Linked Item Element (supported). We talked through the model, and I mentioned that the Linked Item Element was coming from a Content Snippet, and that this was the only thing that stood out as maybe being unique to what I was trying to do.&lt;/p&gt;

&lt;p&gt;He agreed and said he'd go pester the developers to ensure that the use case of having the Add Button configured to a content element coming from a Content Snippet is actually supported.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Win?
&lt;/h2&gt;

&lt;p&gt;It wasn't supported. Wait, isn't that a #&lt;em&gt;fail&lt;/em&gt; and not a #&lt;em&gt;win&lt;/em&gt;? Isn't now the time to slink off into the shadows and just avoid using the Add Button on the homepage?&lt;/p&gt;

&lt;p&gt;Absolutely not! The #&lt;em&gt;win&lt;/em&gt; here is the support provided by Kentico Kontent. In less than a week the developers had coded, tested, and deployed a fix. Not only that, but Keith kept me up to date the entire time on their progress via the chat support feature in Kentico Kontent.&lt;/p&gt;

&lt;h2&gt;
  
  
  It Works!
&lt;/h2&gt;

&lt;p&gt;Behold. The first Add Button of many.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/G71NockBqdo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Adding a new component to the homepage. Refresh status and quick update thanks to Gatsby and incremental builds.



&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Onwards with the refactoring!&lt;/p&gt;

</description>
      <category>win</category>
      <category>gatsby</category>
      <category>development</category>
      <category>lessonlearned</category>
    </item>
    <item>
      <title>Python and Headless: How to make interactive, adaptable, affordable reports</title>
      <dc:creator>Michael Berry</dc:creator>
      <pubDate>Wed, 16 Jun 2021 19:31:01 +0000</pubDate>
      <link>https://forem.com/kontent_ai/python-and-headless-how-to-make-interactive-adaptable-affordable-reports-1gb3</link>
      <guid>https://forem.com/kontent_ai/python-and-headless-how-to-make-interactive-adaptable-affordable-reports-1gb3</guid>
      <description>&lt;p&gt;In this article, I'll show you how to pull data from a headless CMS and create a content type report using the Python framework: &lt;a href="https://dash.plotly.com/introduction" rel="noopener noreferrer"&gt;Dash&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seeing is believing
&lt;/h2&gt;

&lt;p&gt;I am a visual learner. I really appreciate when a graph or diagram accompanies data, or when a visual aid gets to "the point" in a presentation. Not everyone is as much of a fan of charts as I am, but representing data visually is universally helpful. For example, which is easier to understand in a presentation:&lt;/p&gt;

&lt;p&gt;these side-by-side numbers: &lt;em&gt;101 | 443 | 102 | 320 | 82&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;or &lt;/p&gt;

&lt;p&gt;this graph:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22txws4ogu1gyfdmbtok.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22txws4ogu1gyfdmbtok.png" alt="Sample visual learning graphic"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With just the delimited list of numbers, you don't get a good idea of how the values compare to one another. The graph makes differences and similarities more obvious. &lt;/p&gt;

&lt;p&gt;Let's say that you are a new manager or member of a marketing team that uses a headless CMS to produce content.  Knowing what types of content the team has been producing will be useful for better understanding their current content strategy. However, when you are looking at content models in a headless CMS, you're normally met with a long running list of names and numbers:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frafvk11x4rny7ab5h9a0.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frafvk11x4rny7ab5h9a0.png" alt="Kontent content type listing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To assess the kinds of content in the project, you're forced to scan the entire content type listing and mentally compare the values. Without a visual aid, it's hard to tell what topics are prevalent in your project. Furthermore, once you've finished your analysis, you can't easily share your findings with other members of your team. Making them believe your analysis is correct is much easier with a visual report.&lt;/p&gt;

&lt;p&gt;But what if you don't have the time or resources to integrate a commercial reporting tool into your project? Luckily, there are open source frameworks and libraries for building web analytic applications, like Dash.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Dash?
&lt;/h2&gt;

&lt;p&gt;Dash is framework built upon the popular &lt;a href="https://plotly.com/python/getting-started/#:~:text=Basic%20Charts%20tutorials.-,Overview,3%2Ddimensional%20use%2Dcases." rel="noopener noreferrer"&gt;Plotly&lt;/a&gt; graphing library, that allows you to build interactive visual applications and render them in a browser. Although it uses JavaScript libraries behind the scenes, Dash apps are written purely in Python and don't require familiarity with JavaScript. &lt;/p&gt;

&lt;p&gt;If you know some Python, Dash is well suited to create reports from headless CMS data because it supports a wide variety of &lt;a href="https://plotly.com/python/basic-charts/" rel="noopener noreferrer"&gt;well-documented&lt;/a&gt; graph types, and the open-source edition is completely free.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to create a report from a headless CMS
&lt;/h2&gt;

&lt;p&gt;Let's create a content report using the &lt;a href="https://kontent.ai/" rel="noopener noreferrer"&gt;Kentico Kontent headless CMS&lt;/a&gt;, the &lt;a href="https://github.com/kentico-michaelb/kontent-delivery-python-sdk" rel="noopener noreferrer"&gt;open source Kontent Python SDK&lt;/a&gt;, and &lt;a href="https://dash.plotly.com/introduction" rel="noopener noreferrer"&gt;Dash&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our sample scenario, we'll create three reports about a coffee shop website, and aggregate them in a tabbed report.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbk5v8gwkzzggx2f5xwcw.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbk5v8gwkzzggx2f5xwcw.png" alt="Sample tabbed report"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our report we want to show: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what type of content exists in the project&lt;/li&gt;
&lt;li&gt;the audiences our articles are targeting&lt;/li&gt;
&lt;li&gt;the timeline showing when they were published. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These reports will give us more insight into the "who, what, when" strategy surrounding our previously published articles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Application setup
&lt;/h2&gt;

&lt;p&gt;First we need to install Dash, our SDK, and dependencies. I recommend that you do this in a &lt;a href="https://docs.python.org/3/tutorial/venv.html" rel="noopener noreferrer"&gt;virtual environment&lt;/a&gt;. In the terminal run:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;pip install dash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pip install kontent_delivery&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pip install pandas&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alternatively, you can download and then install this &lt;a href="https://github.com/kentico-michaelb/kontent-dash-blog/blob/master/requirements.txt" rel="noopener noreferrer"&gt;requirements.txt&lt;/a&gt; using &lt;code&gt;pip install -r /path/to/requirements.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By the end of the exercise, we will have a file structure that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kontent-dash-blog (root)/
    reports/
        article_timeline.py
        content_types.py
        personas.py
    report_dashboard.py
    requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dash and Kontent Initialization
&lt;/h2&gt;

&lt;p&gt;Once we've installed the requirements, we need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup our Flask application for running Dash &lt;/li&gt;
&lt;li&gt;initialize our Kontent SDK delivery client using our &lt;a href="https://docs.kontent.ai/tutorials/develop-apps/get-content/get-content-items#a-getting-content-items" rel="noopener noreferrer"&gt;Kontent project ID&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;setup some methods to build our three reports &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll do this in a file called &lt;strong&gt;report_dashboard.py&lt;/strong&gt; and create it in the root of the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import dash
import flask
from kontent_delivery.client import DeliveryClient
# report methods
from reports.content_types import build_types_chart
from reports.personas import build_personas_pie
from reports.article_timeline import build_post_timeline

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

# dash
server = flask.Flask(__name__)
app = dash.Dash(server=server, external_stylesheets=external_stylesheets)

# kontent
client = DeliveryClient("your_Kontent_Project_ID")

# custom methods to create reports
bar = build_types_chart(client)
pie = build_personas_pie(client)
timeline = build_post_timeline(client)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Report 1: bar chart showing content types
&lt;/h2&gt;

&lt;p&gt;In this chart, we'll call the Kontent API and count how many content types exist of a given type. We'll create the file &lt;strong&gt;content_types.py&lt;/strong&gt; in a &lt;strong&gt;reports&lt;/strong&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import plotly.express as px

def build_types_chart(client):
    type_response = client.get_content_types()
    item_response = client.get_content_items()

    types = {}

    # add Kontent type counts to a dictionary
    for content_type in type_response.types:
        types[content_type.codename] = 0

    # increment content type count per item of respective type
    for item in item_response.items:
        types[item.content_type] += 1 

    data = {"content types":types.keys(), "count": types.values()}

    fig = px.bar(data, x="content types", y="count")

    return fig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;em&gt;build_types_chart&lt;/em&gt; method, we create key value pairs from the codename of our content types, and a count of how many items are published of that type. With that data, we use Plotly Express to create and return a bar graph to our Dash application.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxsrqi2b0pv8ks8fpj4n.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxsrqi2b0pv8ks8fpj4n.png" alt="Content types bar chart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Report 2: pie chart showing article personas
&lt;/h2&gt;

&lt;p&gt;In our second chart, we want to show what percentage of personas our article content targets. Let's assume we know that the article content type uses a &lt;a href="https://docs.kontent.ai/tutorials/manage-kontent/content-modeling/create-taxonomies" rel="noopener noreferrer"&gt;taxonomy group&lt;/a&gt; called &lt;em&gt;personas&lt;/em&gt;:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6faxv7a8rw0puz3w8dr6.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6faxv7a8rw0puz3w8dr6.png" alt="Kontent taxonomy group"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll create the file &lt;strong&gt;personas.py&lt;/strong&gt; in the &lt;strong&gt;reports&lt;/strong&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from kontent_delivery.builders.filter_builder import Filter
import plotly.express as px

def build_personas_pie(client):
    # only return "article" content items
    item_response = client.get_content_items(
        Filter("system.type", "[eq]", "article")
    )

    # get the taxonomy group that articles use
    personas_response = client.get_taxonomy("personas")
    chart_personas = {}

    # identify personas to be counted
    def get_taxonomy_terms(terms):
        for persona in terms:
            chart_personas[persona.name] = 0
            if persona.terms:
                get_taxonomy_terms(persona.terms)


    get_taxonomy_terms(personas_response.terms)

    # increment persona count per item
    for item in item_response.items:
        for persona in item.elements.personas.value:
            chart_personas[persona.name] += 1 

    data = {"personas":chart_personas.keys(), "count": chart_personas.values()}

    fig = px.pie(data, names="personas", values="count",
                title='Assigned article personas')
    return fig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;em&gt;build_personas_pie&lt;/em&gt; method, we pull all of our article content items.  We then create key value pairs from the name of taxonomy terms that exist in our Personas taxonomy group, and a count of how many items are tagged with a particular term. With that data, we use Plotly Express to create and return a pie graph to our Dash application.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5or1j7sz6dwu1iaq8laq.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5or1j7sz6dwu1iaq8laq.png" alt="Personas pie chart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Report 3: timeline showing date posted
&lt;/h2&gt;

&lt;p&gt;Information about when these articles were published could provide more context about what our content strategy was previously, or how it changed over time. Let's assume we have a "posted date" element on our articles that we can use to create our timeline:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frovnhw9v15tv3s4a5r0l.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frovnhw9v15tv3s4a5r0l.png" alt="Kontent content item posted date"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll create the file &lt;strong&gt;article_timeline.py&lt;/strong&gt; in the &lt;strong&gt;reports&lt;/strong&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from kontent_delivery.builders.filter_builder import Filter
import pandas as pd
import plotly.express as px

def build_post_timeline(client):
    # only return "article" content items
    item_response = client.get_content_items(
        Filter("system.type", "[eq]", "article")
    )

    # setup two arrays for Plotly scatter
    chart_items = []
    chart_post_date = []

    # populate arrays with respective item name and post date
    for item in item_response.items:
        chart_items.append(item.name)
        chart_post_date.append(item.elements.post_date.value)

    df = pd.DataFrame(dict(item=chart_items, post_date=chart_post_date))

    # use column names of df for the different parameters x, y, ...
    fig = px.scatter(df, x="post_date", y="item",
                    title="Article post timeline",
                    labels={"Post Date":"Date item posted"} # customize axis label
                    )

    return fig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like the other methods, we retrieve the article items from Kontent, but in this example we take an extra step to convert two arrays into a dictionary and pass them into a &lt;a href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html" rel="noopener noreferrer"&gt;pandas DataFrame&lt;/a&gt;. This is only for the sake of matching the &lt;a href="https://plotly.com/python/dot-plots/" rel="noopener noreferrer"&gt;basic dot plot example&lt;/a&gt; in the Plotly documentation. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlqtepnjpdkglrfzxgtp.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlqtepnjpdkglrfzxgtp.png" alt="Dash timeline report"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tying it all together in a tabbed report with Dash
&lt;/h2&gt;

&lt;p&gt;It's time to pull all the visual aids together in a single report and add some interactivity with Dash. We created the &lt;strong&gt;report_dashboard.py&lt;/strong&gt; file earlier to add the Kontent client and our chart building methods, and now we'll add a layout with some interactive components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ... other imports from before
# add these for components:
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

# dash
server = flask.Flask(__name__)
app = dash.Dash(server=server, external_stylesheets=external_stylesheets)

# kontent
client = DeliveryClient(config.project_id, options=config.delivery_options)

bar = build_types_chart(client)
pie = build_personas_pie(client)
timeline = build_post_timeline(client)

# -- end of "Dash and Kontent Initialization" code --

# -- start of "Tying it all together..." code --

# adding the dash layout
app.layout = html.Div([
    # dash tabs component that wraps individual tabs
    dcc.Tabs(id='tabs-example', value='tab-1', children=[
        dcc.Tab(label='Content Types', value='tab-1'),
        dcc.Tab(label='Article Personas', value='tab-2'),
        dcc.Tab(label='Article Post Timeline', value='tab-3'),
    ]),
    # div used as a canvas to show reports
    html.Div(id='tabs-example-content')
])

# onclick events that call our chart building methods
@app.callback(Output('tabs-example-content', 'children'),
              Input('tabs-example', 'value'))
def render_content(tab):
    if tab == 'tab-1':
        return html.Div([
            dcc.Graph(figure=bar)
        ])
    elif tab == 'tab-2':
        return html.Div([
             dcc.Graph(figure=pie)
        ])
    elif tab == 'tab-3':
        return html.Div([
             dcc.Graph(figure=timeline)
        ])

# run the application when report_dashboard.py is called
if __name__ == '__main__':
    app.run_server(debug=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the final code file of our report, we use &lt;a href="https://dash.plotly.com/dash-html-components" rel="noopener noreferrer"&gt;Dash's core HTML components&lt;/a&gt; to create a simple two div layout. The first div contains Dash "Tab" components that we use to toggle between graphs, and the second div acts as a canvas to show the graphs we generated.  &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftsg43f8p5r30ain4cpse.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftsg43f8p5r30ain4cpse.png" alt="Dash report with tabs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Following the layout, we use &lt;a href="https://dash.plotly.com/basic-callbacks" rel="noopener noreferrer"&gt;Dash callbacks&lt;/a&gt; to generate a different graph depending upon which tab we click. More information about Dash's core components, including "Graph" and "Tabs" can be seen in the &lt;a href="https://dash.plotly.com/dash-core-components" rel="noopener noreferrer"&gt;Dash documentation here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At this point, you can run &lt;code&gt;report_dashboard.py&lt;/code&gt; in your terminal and watch Dash spin up a localhost server for your newly created reporting application.  Follow the link in the terminal, and VOILA! You've created your own interactive, custom report for free.  &lt;/p&gt;

&lt;p&gt;You can check out a &lt;a href="https://kontent-dash-report.herokuapp.com" rel="noopener noreferrer"&gt;live hosted example&lt;/a&gt; or the &lt;a href="https://github.com/kentico-michaelb/kontent-dash-blog" rel="noopener noreferrer"&gt;full source code on GitHub&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article we discussed what Dash is, and how you can use it to create interactive reports from your headless CMS data. Now you know with a little Python knowledge, and an open-source framework like Dash, you don't have to miss out on having headless CMS reports.&lt;/p&gt;

&lt;p&gt;Want more Dash and headless samples? Check out this &lt;a href="https://github.com/kentico-michaelb/kontent-linked-report" rel="noopener noreferrer"&gt;Dash + Kontent app&lt;/a&gt; for making modular content graphs.&lt;/p&gt;

&lt;p&gt;Are you having issues with the samples from the article? &lt;a href="//bit.ly/kontent-discord"&gt;Get in touch on our Discord&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>headlesscms</category>
      <category>reports</category>
      <category>free</category>
    </item>
    <item>
      <title>Build and Deploy a Next.js Blog with Kentico Kontent and Vercel</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Fri, 11 Jun 2021 09:23:51 +0000</pubDate>
      <link>https://forem.com/kontent_ai/build-and-deploy-a-next-js-blog-with-kentico-kontent-and-vercel-5cp4</link>
      <guid>https://forem.com/kontent_ai/build-and-deploy-a-next-js-blog-with-kentico-kontent-and-vercel-5cp4</guid>
      <description>&lt;p&gt;&lt;a href="https://kontent.ai"&gt;Kentico Kontent&lt;/a&gt; delivers all the benefits of a headless CMS while empowering your marketing team to manage the experience across your digital channels.&lt;/p&gt;

&lt;p&gt;This guide showcases how to use Kontent with Next.js &lt;a href="https://nextjs.org/docs/basic-features/pages"&gt;Static Generation&lt;/a&gt; to generate static pages from your Kontent data, delivering a lightning-fast experience for your users.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Following text is an extended explanation of the &lt;a href="https://github.com/vercel/next.js/tree/canary/examples/cms-kontent#readme"&gt;Statically generated blog using Next.js and Kontent&lt;/a&gt; repository.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 1: Creating a Kontent + Next.js Project
&lt;/h2&gt;

&lt;p&gt;You can &lt;a href="https://next-blog-kontent.vercel.app/"&gt;view a working demo&lt;/a&gt;, the app you will create is shown in the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QKd7iw1r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggiq905brjnoz8fqjxi5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QKd7iw1r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggiq905brjnoz8fqjxi5.png" alt="Example screenshot" width="880" height="792"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Next.js + Kontent demo app.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Register Kontent project
&lt;/h3&gt;

&lt;p&gt;To get started, &lt;a href="https://app.kontent.ai/sign-up"&gt;create an account on Kontent.ai&lt;/a&gt;. After signing up, &lt;a href="https://docs.kontent.ai/tutorials/set-up-kontent/projects/manage-projects#a-creating-projects"&gt;create an empty project&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the content models and fill them with data
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://docs.kontent.ai/tutorials/set-up-kontent/content-modeling/what-is-content-modeling"&gt;content model&lt;/a&gt; defines the data structures of your application/websites. The structures are flexible and you can tailor them to your needs.&lt;/p&gt;

&lt;p&gt;For this example, you need to create a content model that defines an &lt;code&gt;author&lt;/code&gt; and a &lt;code&gt;post&lt;/code&gt; content type.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can &lt;a href="https://github.com/vercel/next.js/blob/canary/examples/cms-kontent/README.md#step-21-optionally-create-the-content-models-manually"&gt;create the content model and fill it with data manually&lt;/a&gt; to familiarize yourself with the Kontent user interface.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To import the content models with their data automatically, follow the next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter &lt;a href="https://app.kontent.ai"&gt;Kontent application&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Go to "Project Settings", select API keys&lt;/li&gt;
&lt;li&gt;Activate Management API&lt;/li&gt;
&lt;li&gt;Copy &lt;code&gt;Project ID&lt;/code&gt; and &lt;code&gt;Management API&lt;/code&gt; key&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://github.com/Kentico/kontent-backup-manager-js"&gt;Kontent Backup Manager&lt;/a&gt; and import data to newly created project from &lt;a href="https://github.com/vercel/next.js/raw/canary/examples/cms-kontent/kontent-backup.zip"&gt;kontent-backup.zip&lt;/a&gt; file (place appropriate values for &lt;code&gt;apiKey&lt;/code&gt; and &lt;code&gt;projectId&lt;/code&gt; arguments):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -g @kentico/kontent-backup-manager
kbm --action=restore --apiKey=&amp;lt;Management API key&amp;gt; --projectId=&amp;lt;Project ID&amp;gt; --zipFilename=kontent-backup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;💡 Alternatively, you can use the &lt;a href="https://kentico.github.io/kontent-template-manager/import"&gt;Template Manager UI&lt;/a&gt; for importing the content.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Go to your Kontent project and publish all the imported items.
&amp;gt; You could deactivate the Management API, it is not necessary anymore.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Application initialization
&lt;/h3&gt;

&lt;p&gt;Initialize the application locally with following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init next-app --example cms-kontent nextjs-kontent-app &amp;amp;&amp;amp; cd nextjs-kontent-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Initializing a Next.js + Kontent app and entering the project directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Step 2: Set up Environment Variables
&lt;/h2&gt;

&lt;p&gt;Copy the &lt;code&gt;.env.local.example&lt;/code&gt; file in this directory to &lt;code&gt;.env.local&lt;/code&gt; (which will be ignored by Git):&lt;/p&gt;



&lt;p&gt;Then set each variable on &lt;code&gt;.env.local&lt;/code&gt; using the keys &lt;code&gt;Project settings&lt;/code&gt; &amp;gt; &lt;code&gt;API keys&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;KONTENT_PROJECT_ID&lt;/code&gt; - Should be the Project ID in &lt;code&gt;Project settings&lt;/code&gt; &amp;gt; &lt;code&gt;API keys&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KONTENT_PREVIEW_API_KEY&lt;/code&gt; - One of the Preview API keys in &lt;code&gt;Project settings&lt;/code&gt; &amp;gt; &lt;code&gt;API keys&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KONTENT_PREVIEW_SECRET&lt;/code&gt; - Can be any random string (but avoid spaces), like &lt;code&gt;MY_SECRET&lt;/code&gt; - this is used for &lt;a href="https://nextjs.org/docs/advanced-features/preview-mode"&gt;Preview Mode&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After installing the required dependencies, you are now able to run and develop your Next.js + Kontent app locally.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn
yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 3: Understanding the Code
&lt;/h2&gt;

&lt;p&gt;To understand how the app works, there are three main areas to explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page Setup&lt;/li&gt;
&lt;li&gt;Retrieving Content&lt;/li&gt;
&lt;li&gt;Image Optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Page Setup
&lt;/h3&gt;

&lt;p&gt;Each page displays a single blog post with the dynamic Object &lt;code&gt;slug&lt;/code&gt; and two latest blog posts teasers from Kontent:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&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;useRouter&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;next/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ErrorPage&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;next/error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Container&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/container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PostBody&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/post-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MoreStories&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/more-stories&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Header&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/header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PostHeader&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/post-header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SectionSeparator&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/section-separator&lt;/span&gt;&lt;span class="dl"&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="s1"&gt;../../components/layout&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;getAllPostSlugs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getPostBySlug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getMorePostsForSlug&lt;/span&gt;&lt;span class="p"&gt;,&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;../../lib/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PostTitle&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/post-title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&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;next/head&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;CMS_NAME&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;../../lib/constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;morePosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;preview&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFallback&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;slug&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ErrorPage&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt; &lt;span class="na"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFallback&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PostTitle&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading…&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;PostTitle&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mb-32"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; | Next.js Blog Example with &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;CMS_NAME&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coverImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PostHeader&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;coverImage&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coverImage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PostBody&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SectionSeparator&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;morePosts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MoreStories&lt;/span&gt; &lt;span class="na"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;morePosts&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;&amp;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;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="nx"&gt;preview&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;getPostBySlug&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;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;getMorePostsForSlug&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;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;values&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="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;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&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;morePosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nx"&gt;preview&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="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="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;slugs&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;getAllPostSlugs&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slug&lt;/span&gt;&lt;span class="dl"&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;slugs&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&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="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;slug&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="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[])&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;The pages/posts/[slug].js file for your Next.js +&lt;br&gt;
  Kontent app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Retrieving Content
&lt;/h3&gt;

&lt;p&gt;Kontent data is retrieved in the &lt;code&gt;lib/api.js&lt;/code&gt; file making requests to the Kontent Delivery API using the &lt;a href="https://www.npmjs.com/package/@kentico/kontent-delivery"&gt;Kontent Delivery SDK&lt;/a&gt;.&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;DeliveryClient&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;@kentico/kontent-delivery&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;version&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;../package.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sourceTrackingHeaderName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-KC-SOURCE&lt;/span&gt;&lt;span class="dl"&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="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DeliveryClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;KONTENT_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;previewApiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;KONTENT_PREVIEW_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;globalHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_queryConfig&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="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sourceTrackingHeaderName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`@vercel/next.js/example/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&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="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;parseAuthor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;author&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;picture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;picture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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="nx"&gt;url&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;parsePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post.title.value,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;coverImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cover_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parseAuthor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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="p"&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="nx"&gt;getAllPostSlugs&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;postsResponse&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;client&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="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&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="nx"&gt;elementsParameter&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slug&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="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;postsResponse&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="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&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="nx"&gt;getMorePostsForSlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preview&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="nx"&gt;client&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="nx"&gt;queryConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;usePreviewMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;preview&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="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&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="nx"&gt;orderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;elements.date&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="nx"&gt;withParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;elements.slug[neq]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limitParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&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="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parsePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&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;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;getPostBySlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;preview&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;post&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;client&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="nx"&gt;queryConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;usePreviewMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;preview&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="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&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="nx"&gt;equalsFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;elements.slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&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="o"&gt;=&amp;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;getFirstItem&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parsePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;post&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="nx"&gt;getAllPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;preview&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="k"&gt;await&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;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;usePreviewMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;preview&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="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&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="nx"&gt;orderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;elements.date&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="nx"&gt;toPromise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;postsResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;postsResponse&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="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parsePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&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;blockquote&gt;
&lt;p&gt;The lib/api.js file for your Next.js + Kontent app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Image Transformation possibilities
&lt;/h2&gt;

&lt;p&gt;If you want to optimize the speed of your site, it is possible to use &lt;a href="https://docs.kontent.ai/reference/image-transformation"&gt;Kontent Image Transformation API&lt;/a&gt; to transform retrieved images and reduce the download time for images. This could be applied to the blog post's cover image or the author's profile picture. The easiest way is to use the &lt;a href="https://github.com/Kentico/kontent-delivery-sdk-js/blob/master/DOCS.md#image-transformation"&gt;Image transformation support in Kontent Delivery SDK&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cn&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;classnames&lt;/span&gt;&lt;span class="dl"&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="s1"&gt;next/link&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;ImageUrlBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ImageCompressionEnum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ImageFormatEnum&lt;/span&gt;&lt;span class="p"&gt;,&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;@kentico/kontent-delivery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;CoverImage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slug&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;transformedSrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ImageUrlBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withCompression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ImageCompressionEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lossless&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withAutomaticFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ImageFormatEnum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Webp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withQuality&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUrl&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;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;transformedSrc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`Cover Image for &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shadow-small&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hover:shadow-medium transition-shadow duration-200&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"-mx-5 sm:mx-0"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;as&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/posts/[slug]"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;aria-label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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="nx"&gt;image&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;blockquote&gt;
&lt;p&gt;Possible modification of &lt;code&gt;components/cover-image.js&lt;/code&gt; &lt;br&gt;
  component using Image Transformation API to get images in &lt;br&gt;
    &lt;a href="https://developers.google.com/speed/webp"&gt;modern WebP format&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Step 4: Using Preview Mode
&lt;/h2&gt;

&lt;p&gt;To add the ability to preview content from your Kontent project using &lt;a href="https://docs.kontent.ai/reference/delivery-api#section/Introduction"&gt;Preview Delivery API&lt;/a&gt;, open your Kontent project, go to &lt;strong&gt;Project Settings &amp;gt; Preview URLs&lt;/strong&gt;, and set a new preview URL for the &lt;code&gt;Post&lt;/code&gt; content type to:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000/api/preview?secret=&amp;lt;KONTENT_PREVIEW_SECRET&amp;gt;&amp;amp;slug={URLslug}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;lt;KONTENT_PREVIEW_SECRET&amp;gt;&lt;/code&gt; with its respective value in &lt;code&gt;.env.local&lt;/code&gt;:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CVFtDNKU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cotjcv6co14jf3sll4me.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CVFtDNKU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cotjcv6co14jf3sll4me.png" alt="The Preview URL setup for Post content type." width="880" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once saved, go to one of the posts you've created and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new version of the post&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update the title&lt;/strong&gt;. For example, you can add &lt;code&gt;[Draft]&lt;/code&gt; in front of the title.
&amp;gt; Mind the title also regenerates the URL slug, if you want to change any other field that does not influence the URL slug, feel free to do so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not&lt;/strong&gt; publish it. By doing this, the post will be in the draft workflow step.&lt;/li&gt;
&lt;li&gt;On the menu, you will see the &lt;strong&gt;Preview&lt;/strong&gt; button. Click on it!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0dsHjuEf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3pdnins9k1ycsct848w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0dsHjuEf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3pdnins9k1ycsct848w.png" alt="The new Preview button in post detail." width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will now be able to see the updated title. To exit preview mode, you can click on &lt;strong&gt;Click here to exit preview mode&lt;/strong&gt; at the top of the page.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Deploying Your App with Vercel
&lt;/h2&gt;

&lt;p&gt;To deploy your Next.js + Kontent site with a Vercel for Git Integration, make sure it has been pushed to a Git repository.&lt;/p&gt;

&lt;p&gt;During the import process, you will need to add the following environment variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;KONTENT_PROJECT_ID&lt;/li&gt;
&lt;li&gt;KONTENT_PREVIEW_API_KEY&lt;/li&gt;
&lt;li&gt;KONTENT_PREVIEW_SECRET&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Import the project into Vercel using your Git Integration of choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vercel.com/import/git?env=KONTENT_PROJECT_ID,KONTENT_PREVIEW_API_KEY,KONTENT_PREVIEW_SECRET"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/import/git?env=KONTENT_PROJECT_ID,KONTENT_PREVIEW_API_KEY,KONTENT_PREVIEW_SECRET"&gt;GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/import/git?env=KONTENT_PROJECT_ID,KONTENT_PREVIEW_API_KEY,KONTENT_PREVIEW_SECRET"&gt;Bitbucket&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After your project has been imported, all subsequent pushes to branches will generate Preview Deployments, and all changes made to the Production Branch (commonly "main") will result in a Production Deployment.&lt;/p&gt;

&lt;p&gt;Once deployed, you will get a URL to see your site live, such as the following: &lt;a href="https://next-blog-kontent.vercel.app/"&gt;https://next-blog-kontent.vercel.app/&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Set up a Next.js + Kontent site with a few clicks using the Deploy button, and create a Git repository for it in the process for automatic deployments for your updates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vercel.com/import/git?c=1&amp;amp;s=https://github.com/vercel/next.js/tree/canary/examples/cms-kontent&amp;amp;env=KONTENT_PROJECT_ID,KONTENT_PREVIEW_API_KEY,KONTENT_PREVIEW_SECRET&amp;amp;envDescription=Required%20to%20connect%20the%20app%20with%20Kontent.&amp;amp;envLink=https://github.com/vercel/next.js/tree/canary/examples/cms-kontent#step-3-set-up-environment-variables"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--45UgOyrE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://vercel.com/button" alt="Deploy with Vercel" width="92" height="32"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;If you want to explore a more complex example for Kentico Kontent and Next.js, check out this Corporate Starter.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Kentico"&gt;
        Kentico
      &lt;/a&gt; / &lt;a href="https://github.com/Kentico/kontent-starter-corporate-next-js"&gt;
        kontent-starter-corporate-next-js
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Next.js corporate starter site using Kentico Kontent as a data source.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;br&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>git</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Vue.js cheat sheet: Rendering data into HTML</title>
      <dc:creator>Ondrej Polesny</dc:creator>
      <pubDate>Fri, 07 May 2021 20:14:44 +0000</pubDate>
      <link>https://forem.com/kontent_ai/vue-js-cheat-sheet-rendering-data-into-html-4d8g</link>
      <guid>https://forem.com/kontent_ai/vue-js-cheat-sheet-rendering-data-into-html-4d8g</guid>
      <description>&lt;p&gt;Are you just starting out with Vue.js? Or has it been long since you’ve worked with Vue? This cheat sheet lists the nine most common tasks and solutions when outputting data to HTML.&lt;/p&gt;

&lt;p&gt;In all these samples, the first part shows the syntax, and the second part shows the usage with real data.&lt;/p&gt;

&lt;h1&gt;
  
  
  Outputting data into HTML
&lt;/h1&gt;

&lt;p&gt;The first test of your app or rendering data between HTML elements:&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="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="err"&gt;↓&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtitle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Adding the standard class attribute
&lt;/h1&gt;

&lt;p&gt;After testing the app, you want to make it look nice with styles:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;classname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&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="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sidebar__inner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Outputting data into HTML attributes
&lt;/h1&gt;

&lt;p&gt;When adding links or rendering images with alt tags, this is how you can fill the elements’ attributes:&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="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;variable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt;↓&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="p"&gt;:&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://twitter.com/${author.twitter.value}`&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Outputting HTML
&lt;/h1&gt;

&lt;p&gt;In certain cases, like when consuming rich texts from a headless CMS, you need to render already formatted HTML:&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="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;variable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/...&lt;/span&gt;&lt;span class="err"&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="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article.teaser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Iterating over data sets
&lt;/h1&gt;

&lt;p&gt;Iterating is useful for creating lists of items, like index pages of blogs or product catalogs:&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="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;item in collectionVariable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;item.uniqueKey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt;↓&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article in articles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article.id&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Iterating over data sets with index
&lt;/h1&gt;

&lt;p&gt;The same use case as before, but this way, you can access an index of each item:&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="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(item, index) in collectionVariable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;item.id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt;↓&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(article, index) in articles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article.id&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Rendering conditional markup
&lt;/h1&gt;

&lt;p&gt;Conditions allow you to hide or display specific parts of markup based on data:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;variable !== null&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&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="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data.length &amp;gt; 0&lt;/span&gt;&lt;span class="dl"&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="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Rendering conditional markup including else branch
&lt;/h1&gt;

&lt;p&gt;They can also be used to display preloaders in case of async data fetching to let your visitors know that something is happening:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;variable !== null&lt;/span&gt;&lt;span class="dl"&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="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&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="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data.length &amp;gt; 0&lt;/span&gt;&lt;span class="dl"&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="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Passing data to child components
&lt;/h1&gt;

&lt;p&gt;When you start using components, this is how you can provide them with data from the parent:&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;componentVariable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;variable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="err"&gt;↓&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;links&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also download this cheat sheet in &lt;a href="https://ondrabus.com/react-vue-angular-cheatsheet"&gt;printable form&lt;/a&gt; and check out its &lt;a href="https://ondrabus.com/react-vue-angular-cheatsheet"&gt;alternatives for React and Angular&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>html</category>
      <category>cheatsheet</category>
    </item>
    <item>
      <title>Animating multiple elements with Vue transitions (and CSS var() function)</title>
      <dc:creator>Ondrej Polesny</dc:creator>
      <pubDate>Thu, 29 Apr 2021 18:06:49 +0000</pubDate>
      <link>https://forem.com/kontent_ai/animating-multiple-elements-with-vue-transitions-and-css-var-function-5el2</link>
      <guid>https://forem.com/kontent_ai/animating-multiple-elements-with-vue-transitions-and-css-var-function-5el2</guid>
      <description>&lt;p&gt;Transitions are a great way to make your app interactive. Vue.js allows us to animate any dynamic events on elements with the &lt;code&gt;&amp;lt;transition&amp;gt;&lt;/code&gt; component. But what if you need to animate multiple elements that are related to each other?&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F633se7z9bj4xtgajrod2.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F633se7z9bj4xtgajrod2.gif" alt="Bars animation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codepen.io/ondrabus/pen/GRraYoo" rel="noopener noreferrer"&gt;TLDR: CodePen link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I stumbled upon this problem when I wanted to animate graph bars. Each bar needed to have a specific width and had to be animated right after the previous one. Also, I did not want to hardcode the number of bars, so it all needed to be data-driven.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the data and template
&lt;/h2&gt;

&lt;p&gt;So let's isolate the problem, this is how the bars are defined in a Vue app:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;data&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;bars&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&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="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 they are rendered in a for loop:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(bar, i) in bars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;%&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Animating the bars using 
&lt;/h2&gt;

&lt;p&gt;The first step in animating them is to add a  component and a single root as that's what Vue requires:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;transition&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;appear&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;div&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(bar, i) in bars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;%&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/transition&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

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

&lt;/div&gt;

&lt;p&gt;Note the &lt;code&gt;appear&lt;/code&gt; attribute. It instructs Vue to animate the first (and only) child element when it appears in the DOM. Vue is clever enough to search the applied styles for transition and it will add a few special classes to the element for the duration of the transition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bars-enter-active&lt;/code&gt; for the whole duration&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bars-enter-from&lt;/code&gt; at the start to define CSS to animate from, e.g. &lt;code&gt;width: 0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bars-enter-to&lt;/code&gt; at the end to define CSS to animate to, e.g. &lt;code&gt;width: 75%&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem is, we need to define these properties on a more granular level - for each bar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting data with CSS using var()
&lt;/h2&gt;

&lt;p&gt;The CSS &lt;code&gt;var()&lt;/code&gt; function allows us to nicely connect dynamic data with CSS. We configure the data just like any other style definition of the element:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--variableName: variableValue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

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

&lt;/div&gt;

&lt;p&gt;And use &lt;code&gt;var(variableName)&lt;/code&gt; in the actual stylesheet:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selector&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;CSS&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;variableName&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;In this case, we'll need each bar to define its width and calculate the animation delay using the item's index:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(bar, i) in bars&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;`--width: ${bar}%; --delay: ${i}s`&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;%&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

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

&lt;/div&gt;

&lt;p&gt;And add the accompanying styles:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;width&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="nx"&gt;bars&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;enter&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&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="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bars&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;enter&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;delay&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;The last thing to keep in mind is that Vue will only keep the special CSS classes on the root element for the amount of time defined in its transition. So let's add the expected animation time as transition duration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;`transition: all ${(bars.length-1)+2}s`&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The animation will take exactly N+2 seconds if N is the number of bars and each bar takes 2s to render. If you set it to a lower value than needed, the animation of some bars will not finish and just skip to the final position.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codepen.io/ondrabus/pen/GRraYoo" rel="noopener noreferrer"&gt;See the functional sample on CodePen.&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The combination of &lt;code&gt;--variableName: variableValue&lt;/code&gt; and &lt;code&gt;var(--variableName)&lt;/code&gt; is a nice way to avoid generating too many style definitions (that are even then limited) through &lt;code&gt;for&lt;/code&gt; loops.&lt;/p&gt;

&lt;p&gt;If you want to share your experience or get in touch, join the &lt;a href="https://bit.ly/kontent-discord" rel="noopener noreferrer"&gt;Kontent Discord&lt;/a&gt; and ping me a message 😊&lt;/p&gt;

</description>
      <category>css</category>
      <category>transition</category>
      <category>var</category>
      <category>vue</category>
    </item>
    <item>
      <title>How to use Kontent Delivery SDK with native ESM and Vite</title>
      <dc:creator>Ondrej Polesny</dc:creator>
      <pubDate>Wed, 31 Mar 2021 12:11:40 +0000</pubDate>
      <link>https://forem.com/kontent_ai/how-to-use-kontent-delivery-sdk-with-native-esm-and-vite-1j00</link>
      <guid>https://forem.com/kontent_ai/how-to-use-kontent-delivery-sdk-with-native-esm-and-vite-1j00</guid>
      <description>&lt;h2&gt;
  
  
  Why native ESM and Vite?
&lt;/h2&gt;

&lt;p&gt;When working on JavaScript projects, we are used to bundling every bit of functionality into a JS bundle that is then served to all visitors of our sites. With native ESM we can get around the bundling and serve modular JS code to modern browsers directly and dynamically.&lt;/p&gt;

&lt;p&gt;One of the tools that help us with this task is &lt;a href="https://vitejs.dev/guide/why.html"&gt;Vite&lt;/a&gt;. It effectively replaces Webpack and allows for instant cold-start of your development server as well as ensures optimal output for production. In turn, it asks for all code to be compatible with ES2015 and newer, so no CommonJS anymore.&lt;/p&gt;

&lt;p&gt;If you try to build your site with Vite and your code does not comply, you will most likely see the following error:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;❌ Uncaught ReferenceError: exports is not defined at ...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The error occurs after you generate the production build and comes from your Vite-optimized code bundle. It means there is some unsupported functionality left in your code or in the packages that you use.&lt;/p&gt;

&lt;p&gt;The Kontent JS Delivery SDK may be one of them. To configure it to work with Vite you need to do the following:&lt;/p&gt;

&lt;h2&gt;
  
  
  Target ESNext version of the Delivery SDK
&lt;/h2&gt;

&lt;p&gt;The Kontent JS Delivery SDK from version 10.4.1 comes with the ESNext version in a subfolder _esNext so you just need to ensure your code uses it. But to make it a bit more complicated, you also need to use _es2015 (the newest) version of &lt;code&gt;kontent-core&lt;/code&gt; package that the &lt;code&gt;kontent-delivery&lt;/code&gt; depends on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ywzZ1lC9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7lj3oh8vmll2azlcodke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ywzZ1lC9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7lj3oh8vmll2azlcodke.png" alt="ESNext version in a subfolder of the Kontent JS Delivery SDK"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So you see, you can't just adjust all your imports to use a subfolder _esNext. To solve this issue, you need to &lt;a href="https://vitejs.dev/config/#resolve-alias"&gt;tell Vite to redirect&lt;/a&gt; all relevant imports to that specific subfolder. Vite passes this information to Rollup - the module bundler it uses internally. The &lt;em&gt;vite.config.ts&lt;/em&gt; looks like this:&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;export&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vue&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;      &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kentico/kontent-core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kentico/kontent-core/_es2015&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="err"&gt;      &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kentico/kontent-delivery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kentico/kontent-delivery/_esNext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="err"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&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;We are redirecting all &lt;code&gt;kontent-core&lt;/code&gt; and &lt;code&gt;kontent-delivery&lt;/code&gt; imports to the respective subfolders.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: If you're not using Vite and need to do the same with Webpack, see &lt;a href="https://webpack.js.org/configuration/resolve/"&gt;this page in their docs&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add BrowserRichTextParser to DeliveryClient config
&lt;/h2&gt;

&lt;p&gt;The SDK may be used in both browser and Node environments. Because Node.js does not feature browser API, the SDK is capable of dynamically loading a (much larger) Node.js parser based on the runtime context. However, some compatibility issues with Angular required the use of CommonJS's &lt;code&gt;require&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You're building a website, so you can get around this by defining the browser-specific parser in the &lt;code&gt;DeliveryClient&lt;/code&gt; config:&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="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BrowserRichTextParser&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kentico/kontent-delivery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DeliveryClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="err"&gt;      &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;      &lt;/span&gt;&lt;span class="na"&gt;richTextParserAdapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BrowserRichTextParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&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 that's it. You're good to go 🤗 Try &lt;code&gt;npm run build&lt;/code&gt; and &lt;code&gt;npm run serve&lt;/code&gt; and your console should be nice and clean.&lt;/p&gt;

&lt;p&gt;If you're using only ES2015+ compatible packages, using Vite you can get a much better development experience with zero waits and more effective production bundles.&lt;/p&gt;

&lt;p&gt;Follow my &lt;a href="https://twitter.com/ondrabus"&gt;Twitter&lt;/a&gt; if you don't want to miss any new articles 🐤&lt;/p&gt;

</description>
      <category>kontent</category>
      <category>vite</category>
      <category>es2015</category>
      <category>esnext</category>
    </item>
    <item>
      <title>Get Kontent Project ID from the Management API key</title>
      <dc:creator>Ondřej Chrastina</dc:creator>
      <pubDate>Mon, 22 Mar 2021 14:00:03 +0000</pubDate>
      <link>https://forem.com/kontent_ai/get-kontent-project-id-from-the-management-api-key-71a</link>
      <guid>https://forem.com/kontent_ai/get-kontent-project-id-from-the-management-api-key-71a</guid>
      <description>&lt;p&gt;&lt;em&gt;It is possible to parse out Kontent Project ID out of the &lt;a href="https://docs.kontent.ai/reference/management-api-v2#tag/API-key-scope-and-validity" rel="noopener noreferrer"&gt;Management API Key&lt;/a&gt;. That means no more necessity to ask for two keys for your Kontent tools.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Do you develop any Kontent tool using &lt;a href="https://docs.kontent.ai/reference/management-api-v2#tag/API-key-scope-and-validity" rel="noopener noreferrer"&gt;Management API&lt;/a&gt; and still ask for both - Project ID and Management API key? Following lines will help you to improve your UX as well as cleanout your code.&lt;/p&gt;

&lt;p&gt;The management API key is just a &lt;a href="https://tools.ietf.org/html/rfc7519" rel="noopener noreferrer"&gt;JWT token&lt;/a&gt; containing the payload (in between header with signature). So you could decode it i.e. by using &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JWT.io&lt;/a&gt;, And as a payload, you could see this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jti"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"b6a9ee86bfdc41c89f20048c3baaba04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1612535158"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1958135158"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"project_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"06c2b8951700013e5f3160283aff1100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"uid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"usr_0vMrpCH2TkOK5oK3y3bKNS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"aud"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"manage.kenticocloud.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;project_id&lt;/code&gt; could be used to identify the project with one modification. It is necessary to add dashes on appropriate places to respect the &lt;a href="http://guid.one/guid" rel="noopener noreferrer"&gt;GUID format&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;To do all of that, the code would end up looking like that (or any other language alternative) - or you just use a library like &lt;a href="https://github.com/auth0/jwt-decode" rel="noopener noreferrer"&gt;jwt-decode&lt;/a&gt;. But it is always good to know what they do.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;managementApiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ew0KICAiYWxnIjogIkhTMjU2IiwNCiAgInR5cCI6ICJKV1QiDQp9.ew0KICAianRpIjogImI2YTllZTg2YmZkYzQxYzg5ZjIwMDQ4YzNiYWFiYTA0IiwNCiAgImlhdCI6ICIxNjEyNTM1MTU4IiwNCiAgImV4cCI6ICIxOTU4MTM1MTU4IiwNCiAgInByb2plY3RfaWQiOiAiMDZjMmI4OTUxNzAwMDEzZTVmMzE2MDI4M2FmZjExMDAiLA0KICAidmVyIjogIjIuMS4wIiwNCiAgInVpZCI6ICJ1c3JfMHZNcnBDSDJUa09LNW9LM3kzYktOUyIsDQogICJhdWQiOiAibWFuYWdlLmtlbnRpY29jbG91ZC5jb20iDQp9.aEqGajw7e9m13lnID0z9PBCL0MytqYlvoYg_rwPfEJo&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;payloadBase64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;managementApiKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&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;payloadBase64Cleared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payloadBase64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/-/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/_/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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;jsonPayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payloadBase64Cleared&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;%&lt;/span&gt;&lt;span class="dl"&gt;'&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;00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&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="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&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="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payloadObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonPayload&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;projectIdWithoutDashes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payloadObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project_id&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;projectId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&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="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-\
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-\
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-\
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;-\
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectIdWithoutDashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you want to play with it - &lt;a href="https://codepen.io/simply007-the-sasster/pen/xxRvNoX" rel="noopener noreferrer"&gt;check out this Codepen&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;...and of course, I invalidated the showcased API key 🤞&lt;/em&gt;&lt;/p&gt;

</description>
      <category>jwt</category>
      <category>api</category>
      <category>decode</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Reporting .NET 5 XUnit Code Coverage in Codecov via GitHub Actions and Coverlet</title>
      <dc:creator>Petr Švihlík</dc:creator>
      <pubDate>Fri, 05 Mar 2021 14:56:10 +0000</pubDate>
      <link>https://forem.com/kontent_ai/reporting-net-5-xunit-code-coverage-in-codecov-via-github-actions-and-coverlet-4h5i</link>
      <guid>https://forem.com/kontent_ai/reporting-net-5-xunit-code-coverage-in-codecov-via-github-actions-and-coverlet-4h5i</guid>
      <description>&lt;p&gt;You might remember my &lt;a href="https://dev.to/petrsvihlik/running-net-core-3-xunit-code-coverage-in-appveyor-using-opencover-and-codecov-1n7p"&gt;earlier post&lt;/a&gt; where I described how to set up code coverage reporting for .NET Core 3 using AppVeyor + OpenCover + Codecov.&lt;/p&gt;

&lt;p&gt;Time has moved on, .NET 5 has arrived, and the best practices have changed, so let's see how to collect code coverage for .NET projects in 2021.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;For some time, I have been intrigued by the &lt;code&gt;coverlet.collector&lt;/code&gt; that you can find in any new XUnit &lt;code&gt;.csproj&lt;/code&gt;. What it is? How can I use it? Can I replace OpenCover with it?&lt;/p&gt;

&lt;p&gt;Also, I started noticing people migrating to GitHub Actions and I didn't have any experience with it and kinda felt that I'm missing the train. This observation has been confirmed recently in the &lt;a href="https://about.codecov.io/resource/2020-state-of-open-source-code-coverage/" rel="noopener noreferrer"&gt;2020 State of Open Source Code Coverage&lt;/a&gt; report where GitHub Actions scored the #1 fastest growing CI used with Codecov (and also the #1 in absolute numbers).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://about.codecov.io/resource/2020-state-of-open-source-code-coverage/#sos-23" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahh5qegex307x5pf11c0.jpg" alt="2020 State of Open Source Code Coverage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was thinking I could modernize the stack that I use for .NET projects both at work and for my personal projects. Of the three tools that I've been using previously, I'll be keeping just Codecov (because it's awesome ❤). Let's get to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating coverage
&lt;/h2&gt;

&lt;p&gt;I like to use the &lt;code&gt;dotnet&lt;/code&gt; CLI for as many tasks as possible. The good news is that &lt;code&gt;coverlet&lt;/code&gt; offers deep integration with &lt;code&gt;msbuild&lt;/code&gt;. &lt;br&gt;
This is how you can generate code coverage for the whole solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/p:CollectCoverage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/p:CoverletOutputFormat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;opencover&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command will generate &lt;code&gt;coverage.opencover.xml&lt;/code&gt; files in all your test projects (if you run &lt;code&gt;dotnet test&lt;/code&gt; on the solution level).&lt;/p&gt;

&lt;p&gt;All you need to do to make the code coverage-related &lt;code&gt;/p:&lt;/code&gt; switches work is to install also the &lt;a href="https://www.nuget.org/packages/coverlet.msbuild/" rel="noopener noreferrer"&gt;&lt;code&gt;coverlet.msbuild&lt;/code&gt;&lt;/a&gt; NuGet package. So your &lt;code&gt;.csproj&lt;/code&gt;s will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"coverlet.collector"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"3.0.3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;IncludeAssets&amp;gt;&lt;/span&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;span class="nt"&gt;&amp;lt;/IncludeAssets&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PrivateAssets&amp;gt;&lt;/span&gt;all&lt;span class="nt"&gt;&amp;lt;/PrivateAssets&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/PackageReference&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"coverlet.msbuild"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"3.0.3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PrivateAssets&amp;gt;&lt;/span&gt;all&lt;span class="nt"&gt;&amp;lt;/PrivateAssets&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;IncludeAssets&amp;gt;&lt;/span&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;span class="nt"&gt;&amp;lt;/IncludeAssets&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/PackageReference&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to leave in the &lt;code&gt;/p:CoverletOutputFormat=opencover&lt;/code&gt; switch as this is the format that's accepted by Codecov. &lt;/p&gt;

&lt;p&gt;For more advanced configuration, I recommend reading the documentation on &lt;a href="https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/MSBuildIntegration.md" rel="noopener noreferrer"&gt;Coverlet's integration with MSBuild&lt;/a&gt;. This is especially useful when your solution or projects don't stick to naming conventions and you need to do some extra filtering, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating into GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Plugging the &lt;code&gt;dotnet test&lt;/code&gt; into the CI pipeline is just a matter of creating a new workflow step. No matter if you use the &lt;code&gt;ubuntu-latest&lt;/code&gt; or &lt;code&gt;windows-latest&lt;/code&gt; runner, it works flawlessly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Restore dependencies&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnet restore&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnet build --no-restore /p:ContinuousIntegrationBuild=true&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Collecting coverage by Codecov
&lt;/h2&gt;

&lt;p&gt;The last step is to upload the test coverage to Codecov. You can find an official &lt;a href="https://github.com/marketplace/actions/codecov" rel="noopener noreferrer"&gt;Codecov GitHub Action&lt;/a&gt; on the marketplace which makes the process super easy - no need to install the Codecov CLI, etc.&lt;/p&gt;

&lt;p&gt;Just add the following lines to your workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Codecov&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecov/codecov-action@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Codecov will search through the folder structure of your project and discover your coverage reports based on conventions. You don't even have to include the &lt;code&gt;CODECOV_TOKEN&lt;/code&gt; for public repos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;As you can see, this approach is much more convenient than &lt;a href="https://dev.to/petrsvihlik/running-net-core-3-xunit-code-coverage-in-appveyor-using-opencover-and-codecov-1n7p"&gt;the one I was using before&lt;/a&gt; - downloading and installing tools, running PowerShell scripts, etc.&lt;/p&gt;

&lt;p&gt;If you stick to standard .NET naming and folder structure conventions, setting up code coverage is actually very easy nowadays.&lt;/p&gt;

&lt;p&gt;To see the whole workflow in action, head to some of our &lt;a href="https://github.com/Kentico/kontent-delivery-sdk-net/actions/workflows/integrate.yml" rel="noopener noreferrer"&gt;SDK repos&lt;/a&gt;. You can also explore how we do releases using GitHub Actions. All code is in the &lt;a href="https://github.com/Kentico/kontent-delivery-sdk-net/tree/master/.github/workflows" rel="noopener noreferrer"&gt;&lt;code&gt;workflows folder&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my next article, I'll cover how to &lt;a href="https://dev.to/petrsvihlik/using-environment-protection-rules-to-secure-secrets-when-building-external-forks-with-pullrequesttarget-hci"&gt;secure secrets when building pull requests from forks&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>net5</category>
      <category>coverlet</category>
      <category>codecov</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Can you evolve your documentation from fossil to fantastic?</title>
      <dc:creator>Michael Berry</dc:creator>
      <pubDate>Tue, 22 Dec 2020 13:17:57 +0000</pubDate>
      <link>https://forem.com/kontent_ai/can-you-evolve-your-documentation-from-fossil-to-fantastic-2fa5</link>
      <guid>https://forem.com/kontent_ai/can-you-evolve-your-documentation-from-fossil-to-fantastic-2fa5</guid>
      <description>&lt;p&gt;&lt;strong&gt;We can all agree that repeating the same information over and over wastes time and that writing comprehensive and accessible documentation is essential. But have you thought about &lt;em&gt;how&lt;/em&gt; you’re creating that documentation? Are you still dusting off printed instructions or digging up ancient word documents? Is there a more modern approach?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In my opinion: "Boilerplates" are beautiful. They make using a new framework, language, or platform possible without starting from scratch, and can vastly simplify starting a new project.  To simplify my documentation creation process, I've made a &lt;em&gt;Kontent + Docusaurus&lt;/em&gt; boilerplate that will handle styling, navigation, and structure, while also allowing me to maintain my content using a headless CMS.&lt;/p&gt;

&lt;p&gt;In this article, I’ll talk about the benefits of using Kentico Kontent, Facebook’s Docusaurus, and my Kontent + Docusaurus boilerplate to create scalable, attractive, easy-to-manage documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why my documentation went “the way of the dinosaurs”
&lt;/h2&gt;

&lt;p&gt;I wear a lot of hats in my organization: I’m a manager, support engineer, content creator, internal trainer, to name a few. Shifting attention between varying tasks and functions is a common occurrence and can be pretty overwhelming. To save time (and my sanity), documenting my processes and responsibilities helps me stay organized and allows me to delegate tasks to my team more effectively. But until recently, I didn’t have a great way to create this resource. I’ve used our crowded company wiki, Word documents, PowerPoint presentations, and a lot of information is given verbally from memory. Something had to change as this approach locked me into a perpetual loop of updating static presentations and documents with no hope of delegation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it help you?
&lt;/h2&gt;

&lt;p&gt;Maybe you’re not managing a team or on-boarding anyone, but I’m confident at some point you’ve had to walk a teammate or multiple colleagues through a process a few times. &lt;strong&gt;Let’s be fair&lt;/strong&gt;: your colleagues don’t want to take valuable time away from you. They just need answers, and those answers happen to live in your head, are hiding in your notes, or are just not documented in an accessible location.&lt;/p&gt;

&lt;p&gt;Furthermore, updating and maintaining documentation or guides doesn’t &lt;em&gt;have&lt;/em&gt; to (and normally shouldn’t) rely upon developers, specialized, or senior team members. You should be able to write the original copy, hand-off the maintenance to a colleague or team, and move on to other tasks that are burning for your attention.&lt;/p&gt;

&lt;h3&gt;
  
  
  The boilerplate: Our cloning DNA
&lt;/h3&gt;

&lt;p&gt;Creating a new piece of documentation shouldn’t be an ordeal; you don’t need another project vying for your time. Using a template as a starting point is a good way to make sure starting the documentation isn’t a major line item blocking out your calendar. So clone this repository and save time—no prehistoric mosquitoes required (you knew a &lt;em&gt;Jurassic Park&lt;/em&gt; reference was coming).&lt;/p&gt;

&lt;p&gt;This boilerplate comes with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A navigation sidebar with collapsible sub-sections&lt;/li&gt;
&lt;li&gt;  Attractive pre-made styles, including light &amp;amp; dark mode&lt;/li&gt;
&lt;li&gt;  A minimal amount of content to act as a “starting point”&lt;/li&gt;
&lt;li&gt;  Quick and easy setup instructions in the &lt;a href="https://5fb2a7f3aec91f000740cba3--sad-clarke-a5925e.netlify.app/" rel="noopener noreferrer"&gt;Boilerplate’s documentation&lt;/a&gt; or &lt;a href="https://github.com/kentico-michaelb/kontent-docusaurus-boilerplate#readme" rel="noopener noreferrer"&gt;GitHub README&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&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%2Fassets-us-01.kc-usercontent.com%2Ff1c5bba1-dddc-00d2-e9ec-9d20ce57ea18%2F6cd0f682-c90c-45e9-9353-eb5d3028641a%2FdocusaurusBoilerplateExample.png" 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%2Fassets-us-01.kc-usercontent.com%2Ff1c5bba1-dddc-00d2-e9ec-9d20ce57ea18%2F6cd0f682-c90c-45e9-9353-eb5d3028641a%2FdocusaurusBoilerplateExample.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Kontent + Docusaurus boilerplate pictured above.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The headless CMS: Advancing our reptile brains
&lt;/h3&gt;

&lt;p&gt;When documentation is required, jumping into a simple word processor is second-nature to a lot of us. It’s comfortable, it’s quick, it’s familiar. This doesn’t mean it is the best approach for the job, though, and I argue that breaking this habit is key for making scalable and accessible documentation. Using a headless CMS addresses scalability head-on and future-proofs your documentation. &lt;/p&gt;

&lt;p&gt;I work in Kentico Kontent all the time, so it is a go-to comfort pick for me when choosing a CMS, but those who aren’t fluent in Kontent will still reap major benefits from using it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It’s a Software-as-a-Service platform, meaning no managing upgrades, hosting, or security patches.&lt;/li&gt;
&lt;li&gt;  Kontent’s search bar, filters, and “Home” allows you to quickly locate content.&lt;/li&gt;
&lt;li&gt;  Inserting code snippets into the Rich Text Editor using a WYSIWYG editor is easy.&lt;/li&gt;
&lt;li&gt;  Reusable content and content links mean no more copy-pasting swaths of documentation between sections.&lt;/li&gt;
&lt;li&gt;  Its features, API, and SDKs are &lt;a href="https://docs.kontent.ai/" rel="noopener noreferrer"&gt;well documented&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&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%2Fassets-us-01.kc-usercontent.com%2Ff1c5bba1-dddc-00d2-e9ec-9d20ce57ea18%2F4a97bade-9433-42d9-a2c0-a7ae305af58e%2FdocusaurusCalloutExample.png" 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%2Fassets-us-01.kc-usercontent.com%2Ff1c5bba1-dddc-00d2-e9ec-9d20ce57ea18%2F4a97bade-9433-42d9-a2c0-a7ae305af58e%2FdocusaurusCalloutExample.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Sample content item in Kentico Kontent pictured above.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These are just a few of the benefits when using Kentico Kontent, but if you need more proof, the official Kontent documentation uses Kontent, and there is a &lt;a href="https://kontent.ai/blog/content-as-a-service-for-documentation" rel="noopener noreferrer"&gt;two-part article series&lt;/a&gt; that talks about why.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docusaurus: More Barney than an apex predator
&lt;/h3&gt;

&lt;p&gt;In addition to the &lt;a href="https://v2.docusaurus.io/docs/#features" rel="noopener noreferrer"&gt;list of benefits from Docusaurus’ website&lt;/a&gt;, the plugins and presets provided by the Docusaurus team make getting up and running fast. Its creators’ focus on documentation sites, along with 20,000 GitHub stars and being backed by Facebook, is what really drew me to using Docusaurus as the front-end application for my documentation. It’s also a nice fit because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It’s a static site generator making it fast and secure.&lt;/li&gt;
&lt;li&gt;  It can be deployed and hosted virtually anywhere for free.&lt;/li&gt;
&lt;li&gt;  The Docusaurus team wrote easy-to-read documentation about everything from &lt;em&gt;Installation *to *Lifecycle APIs.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This React and MDX markdown powered project has T-Rex-level power in its extensibility and out-of-the-box functionality, but the features and configuration are intuitive, so its learning curve isn’t intimidating. For example, in just three terminal commands you can have their &lt;em&gt;classic&lt;/em&gt; preset site running. Docusaurus is definitely a friendly dinosaur.&lt;/p&gt;

&lt;h2&gt;
  
  
  So...is it &lt;em&gt;actually&lt;/em&gt; fantastic?
&lt;/h2&gt;

&lt;p&gt;For me personally, I’m a lot happier to point a colleague to up-to-date stylized on-boarding resources than having to muddle together PowerPoint presentations, but this depends on your use case. If you just need a few quick, static paragraphs to document something, Kontent + Docusaurus might be overkill. But, if you have living documentation that needs frequent updates, reusable content, and structured navigation, it could be a better choice than passing around Word documents or jamming information into overflowing wikis. &lt;/p&gt;

&lt;p&gt;Additionally, since the content is available over an API in a headless CMS, this documentation can &lt;em&gt;evolve&lt;/em&gt; with the times; Create a voice-app that pulls the documentation from Kontent, integrate personalization to better serve the visitor, add analytics or commenting with machine learning to gauge the helpfulness of a page. The possibilities and complexity can scale with the project needs. I’d say that’s pretty fantastic!&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%2Fassets-us-01.kc-usercontent.com%2Ff1c5bba1-dddc-00d2-e9ec-9d20ce57ea18%2F95aa0422-8451-4148-93cf-8aca59551b3e%2FKentico_Kontent.png" 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%2Fassets-us-01.kc-usercontent.com%2Ff1c5bba1-dddc-00d2-e9ec-9d20ce57ea18%2F95aa0422-8451-4148-93cf-8aca59551b3e%2FKentico_Kontent.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Kentico Kontent architecture possibilities pictured above.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I see this evolution in action?
&lt;/h2&gt;

&lt;p&gt;Absolutely! &lt;a href="https://5fb2a7f3aec91f000740cba3--sad-clarke-a5925e.netlify.app/" rel="noopener noreferrer"&gt;The documentation&lt;/a&gt; explaining how to set up the Kontent + Docusaurus Boilerplate was written using Kontent and Docusaurus. You can also set up your own project using the instructions in the &lt;a href="https://github.com/kentico-michaelb/kontent-docusaurus-boilerplate" rel="noopener noreferrer"&gt;Kontent + Docusaurus Boilerplate GitHub repository&lt;/a&gt;.&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%2Fassets-us-01.kc-usercontent.com%3A443%2Ff1c5bba1-dddc-00d2-e9ec-9d20ce57ea18%2F3f8dcb1b-d655-409c-8d74-a9f96e89c082%2FKontent_Docusaurus_FireFox.png" 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%2Fassets-us-01.kc-usercontent.com%3A443%2Ff1c5bba1-dddc-00d2-e9ec-9d20ce57ea18%2F3f8dcb1b-d655-409c-8d74-a9f96e89c082%2FKontent_Docusaurus_FireFox.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t wait for a meteorite
&lt;/h2&gt;

&lt;p&gt;In this article, we highlighted the benefits of replacing old documentation with Kontent and Docusaurus and how a boilerplate can streamline your documentation creation. So don’t wait for a cataclysmic event, blow up your ancient documentation habits, and give Kontent and Docusaurus a try!&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>headlesscms</category>
      <category>ssg</category>
      <category>docusaurus</category>
    </item>
  </channel>
</rss>
