<?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>DEV Community: Jonas Gierer</title>
    <description>The latest articles on DEV Community by Jonas Gierer (@jgierer12).</description>
    <link>https://dev.to/jgierer12</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F18950%2Fbb63be4a-ef56-4020-8603-2a671f38a0e0.png</url>
      <title>DEV Community: Jonas Gierer</title>
      <link>https://dev.to/jgierer12</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jgierer12"/>
    <language>en</language>
    <item>
      <title>Astro + Storyblok: SSR Tips and Tricks</title>
      <dc:creator>Jonas Gierer</dc:creator>
      <pubDate>Fri, 10 Feb 2023 16:01:07 +0000</pubDate>
      <link>https://dev.to/jgierer12/astro-storyblok-ssr-tips-and-tricks-3j2k</link>
      <guid>https://dev.to/jgierer12/astro-storyblok-ssr-tips-and-tricks-3j2k</guid>
      <description>&lt;p&gt;This is a companion post to &lt;a href="https://dev.to/jgierer12/astro-storyblok-ssr-preview-for-instant-visual-editing-3g9m"&gt;Astro + Storyblok: SSR preview for instant visual editing&lt;/a&gt;. Please read it first if you haven't already!&lt;/p&gt;

&lt;p&gt;Below you'll find some extra tips and tricks I've discovered while developing my Astro + Storyblok site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove drafts from the production site
&lt;/h3&gt;

&lt;p&gt;To avoid loading draft content in production, I created a wrapper function for the Storyblok API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/storyblok/utils.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;sb&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;@storyblok/astro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storyblokApi&lt;/span&gt; &lt;span class="o"&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="kr"&gt;string&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;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ISbStoryParams&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useStoryblokApi&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&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="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&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;PUBLIC_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;published&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;draft&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;params&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;You can then use this wrapper wherever you would've used the Storyblok API, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/pages/[slug].astro&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;storyblokApi&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;../storyblok/utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;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="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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;storyblokApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cdn/links&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt; &lt;span class="o"&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;links&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;links&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;links&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;site-config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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="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="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;link&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prevent search engine indexing of the preview site
&lt;/h3&gt;

&lt;p&gt;You probably don't want your preview site containing drafts and unfinished content to be indexed by search engines. To prevent that, use the &lt;a href="https://github.com/alextim/astro-lib/tree/main/packages/astro-robots-txt#readme" rel="noopener noreferrer"&gt;&lt;code&gt;astro-robots-txt&lt;/code&gt;&lt;/a&gt; integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx astro add astro-robots-txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// astro.config.{mjs,ts}&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;robotsTxt&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;astro-robots-txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;integrations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;robotsTxt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;policy&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="na"&gt;userAgent&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="na"&gt;disallow&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;PUBLIC_ENV&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="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="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Disable &lt;code&gt;astro-imagetools&lt;/code&gt; image processing in SSR
&lt;/h3&gt;

&lt;p&gt;I found that my SSR pages loaded very slowly because I was using &lt;a href="https://github.com/RafidMuhymin/astro-imagetools" rel="noopener noreferrer"&gt;&lt;code&gt;astro-imagetools&lt;/code&gt;&lt;/a&gt; to process images. Since optimized images aren't necessary during editing anyways, I created a wrapper component to bypass image processing in the preview environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
import type { Picture } from 'astro-imagetools/components';

export type Props = Parameters&amp;lt;typeof Picture&amp;gt;[0];

let {
  breakpoints = [500, 900, 1800], // fallback breakpoints
  class: pictureClass = '',
  ...props
} = Astro.props;

let Component;
if (import.meta.env.PUBLIC_ENV === 'preview') {
  Component = 'img';
  props = {
    class: pictureClass,
    ...props,
  };
} else {
  Component = (await import('astro-imagetools/components')).Picture;
  props = {
    breakpoints,
    attributes: {
      picture: {
        class: pictureClass,
      },
    },
    ...props,
  };
}
---

&amp;lt;Component {...props} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>codereview</category>
      <category>agile</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Astro + Storyblok: SSR preview for instant visual editing</title>
      <dc:creator>Jonas Gierer</dc:creator>
      <pubDate>Fri, 10 Feb 2023 16:00:35 +0000</pubDate>
      <link>https://dev.to/jgierer12/astro-storyblok-ssr-preview-for-instant-visual-editing-3g9m</link>
      <guid>https://dev.to/jgierer12/astro-storyblok-ssr-preview-for-instant-visual-editing-3g9m</guid>
      <description>&lt;p&gt;Storyblok is one of the most popular new content management systems. Its visual editing and component-based workflow are intuitive for editors, while also being easy for developers to work with.&lt;/p&gt;

&lt;p&gt;While its &lt;a href="https://github.com/storyblok/storyblok-astro" rel="noopener noreferrer"&gt;&lt;code&gt;@storyblok/astro&lt;/code&gt;&lt;/a&gt; integration with the Astro framework seems fairly straight-forward at first, getting the most out of both Storyblok's visual editor and Astro's static site generation is not as simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Since Astro is (by default) a static site generator, which generates all pages at build time, editing content in Storyblok will not give your editors the instant feedback they might expect: Even if your Storyblok webhooks are set up correctly, it can take several minutes for the entire project to be rebuilt before the updated content appears. This makes for a very awkward and unintuitive editing experience.&lt;/p&gt;

&lt;p&gt;One way to solve this problem is to use Astro in SSR mode. This uses a Nodejs server or serverless functions to render pages whenever they are requested, rather than at build time. This means pages will update as soon as editors change their content. Unfortunately this also means that you'll lose all benefits of a static site, such as the significantly faster page load times and lower operating costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;In order to get the best of both worlds, we'll want to set up two separate deployments: One that uses Astro's default SSG mode for your users to visit, and one SSR environment which is used as the preview site in Storyblok. This way, editors get instant feedback while editing content, but users will still get a fast, static site.&lt;/p&gt;

&lt;p&gt;Assuming you followed the &lt;code&gt;storyblok-astro&lt;/code&gt; &lt;a href="https://github.com/storyblok/storyblok-astro#getting-started" rel="noopener noreferrer"&gt;Getting Started guide&lt;/a&gt;, here is a step-by-step guide to enable this dual environment:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Install Astro SSR adapter of your choice
&lt;/h3&gt;

&lt;p&gt;Astro supports several platforms for server-side rendering. For this guide I will use Vercel's serverless functions. Please refer to the &lt;a href="https://docs.astro.build/en/guides/server-side-rendering/#adding-an-adapter" rel="noopener noreferrer"&gt;Astro docs&lt;/a&gt; for other platforms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx astro add vercel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Conditionally enable SSR mode
&lt;/h3&gt;

&lt;p&gt;This is where the magic happens: Based on an environment variable, we switch between Astro's &lt;code&gt;server&lt;/code&gt; or &lt;code&gt;static&lt;/code&gt; mode. I chose to call the variable &lt;code&gt;PUBLIC_ENV&lt;/code&gt; because Astro makes environment variables prefixed with &lt;code&gt;PUBLIC_&lt;/code&gt; available in client-side code, which might come in useful. We also conditionally load the SSR adapter since it's not needed in static mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// astro.config.{mjs,ts}&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;vercel&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;@astrojs/vercel/serverless&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&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="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;output&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;PUBLIC_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preview&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;adapter&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;PUBLIC_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preview&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;vercel&lt;/span&gt;&lt;span class="p"&gt;()&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Conditionally enable the Storyblok bridge
&lt;/h3&gt;

&lt;p&gt;The Storyblok bridge is responsible for reloading the page when there are changes to Storyblok content, as well as making individual components clickable in the Storyblok editor. Since we will never open the production static site in Storyblok, we can reduce the bundle size a little by disabling the bridge in production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// astro.config.{mjs,ts}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="na"&gt;integrations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;storyblok&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;bridge&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;PUBLIC_ENV&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Create separate build scripts
&lt;/h3&gt;

&lt;p&gt;In order to build the two different deployments, we'll create two build scripts which set the &lt;code&gt;PUBLIC_ENV&lt;/code&gt; variable to the respective value. For the sake of completeness, we'll also set the variable to &lt;code&gt;development&lt;/code&gt; when using the dev server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="c1"&gt;// package.json&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PUBLIC_ENV=development astro dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build:production"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PUBLIC_ENV=production astro build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build:preview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PUBLIC_ENV=preview astro build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Deploy the two sites
&lt;/h3&gt;

&lt;p&gt;Next, we'll create two separate deployments which use the different build scripts. In my case, I'll create two Vercel projects, connect both to the project's GitHub repo and set the &lt;em&gt;Build Command&lt;/em&gt; under &lt;em&gt;Settings &amp;gt; General &amp;gt; Build &amp;amp; Development Settings&lt;/em&gt; to &lt;code&gt;npm run build:production&lt;/code&gt; for the static production site and to &lt;code&gt;npm run build:preview&lt;/code&gt; for the SSR preview site. You should be able to do the same for Netlify, Cloudflare or similar providers.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Use webhooks to trigger production deploys
&lt;/h3&gt;

&lt;p&gt;Now all that's left to do is to set up webhooks between Storyblok and your hosting provider so that the production site is rebuilt whenever content is published.&lt;/p&gt;

&lt;p&gt;First, create a webhook in your production site's admin interface. For Vercel, I did this under &lt;em&gt;Settings &amp;gt; Git &amp;gt; Deploy Hooks&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Then, copy the URL of the webhook you just created, and paste it in Storyblok under &lt;em&gt;Settings &amp;gt; Webhooks &amp;gt; Story published &amp;amp; unpublished&lt;/em&gt;. Now your production site should be rebuilt whenever your editors publish or delete content!&lt;/p&gt;

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

&lt;p&gt;This setup made Astro integrate with Storyblok much more nicely, and it is now one of my favorite framework-CMS pairings on the market. The awesome performance and developer experience of Astro static sites paired with the intuitive Storyblok visual editor is wonderful!&lt;/p&gt;

&lt;p&gt;I hope this guide was helpful if you're building a site with these two technologies. Let me know if you have any questions or ideas for improvement!&lt;/p&gt;

&lt;h2&gt;
  
  
  Extras
&lt;/h2&gt;

&lt;p&gt;There are a bunch of extra tips and tricks about Astro + Storyblok that I wanted to share, but since this guide is already getting long I decided to put them in a separate companion post, which you can find here: &lt;a href="https://dev.to/jgierer12/astro-storyblok-ssr-tips-and-tricks-3j2k"&gt;Astro + Storyblok: SSR Tips and Tricks&lt;/a&gt;. There I explain how to prevent drafts from showing up in your production site, disable search engine indexing of your preview site and more.&lt;/p&gt;

</description>
      <category>welcome</category>
    </item>
    <item>
      <title>How to publish packages to the GitHub Package Registry</title>
      <dc:creator>Jonas Gierer</dc:creator>
      <pubDate>Sat, 14 Sep 2019 02:00:36 +0000</pubDate>
      <link>https://dev.to/jgierer12/how-to-publish-packages-to-the-github-package-repository-4bai</link>
      <guid>https://dev.to/jgierer12/how-to-publish-packages-to-the-github-package-repository-4bai</guid>
      <description>&lt;p&gt;If you were lucky enough to get into this week's batch of beta invitations for the &lt;a href="https://github.com/features/package-registry"&gt;GitHub Package Registry&lt;/a&gt;, you might be wondering how to get started publishing your npm package there.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://help.github.com/en/articles/configuring-npm-for-use-with-github-package-registry"&gt;official docs&lt;/a&gt; do an OK job at explaining the basics, but aren't as straight forward as you might expect. And at some points, they are downright contradicting themselves. It is a beta, after all, and I'm sure GitHub will improve the docs as this new feature is moving closer to launch.&lt;/p&gt;

&lt;p&gt;In this article, I'm going to explain step by step how you can publish your first package on the GitHub Package Registry (I'll call it GPR from now on.) Then, I'll give you a quick explanation how your users can install the package from the GPR, while still being able to install packages from the "normal" npmjs.org registry alongside it.&lt;/p&gt;

&lt;p&gt;Keep in mind that the GPR is still in beta, so implementation details might change. Hopefully, I'll remember to keep this article updated, but if in doubt, better check against the official docs. And if you notice anything out-of-date, please let me know in the comments!&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminology
&lt;/h2&gt;

&lt;p&gt;The terms used for GitHub packages are mostly the same as for the npm registry. If you're already familiar with them, you can skip straight to the next section!&lt;/p&gt;

&lt;dl&gt;
  &lt;dt&gt;Registry&lt;/dt&gt;
  &lt;dd&gt;
    To resolve packages by name and version, npm (the CLI tool) talks to a registry website. The most popular registry is hosted by npm (the company) on &lt;a href="https://registry.npmjs.org"&gt;registry.npmjs.org&lt;/a&gt;.
  &lt;/dd&gt;

  &lt;dt&gt;GitHub Package Registry (GPR)&lt;/dt&gt;
  &lt;dd&gt;
    GitHub recently announced their own registry service, which is available on &lt;a href="https://npm.pkg.github.com"&gt;npm.pkg.github.com&lt;/a&gt;. This service will be tightly coupled to their other offerings, so you can expect your package to integrate well with your project's home on GitHub as well as GitHub Actions.
  &lt;/dd&gt;

  &lt;dt&gt;Scope&lt;/dt&gt;
  &lt;dd&gt;
    Scopes are a way of grouping related packages together. Both on the npm registry and the GPR, each user and organization has their own scope. While using a scope is optional on the npm registry, every package published to the GPR must be scoped.
  &lt;/dd&gt;
&lt;/dl&gt;

&lt;h2&gt;
  
  
  Authorizing npm
&lt;/h2&gt;

&lt;p&gt;These steps only have to be taken once per machine and GitHub user/org. You won't have to go through them again unless you want to publish from a new device or to a new scope.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a new &lt;a href="https://github.com/settings/tokens"&gt;personal access token&lt;/a&gt; for the account you want to publish the package to. It should have access to the &lt;code&gt;read:packages&lt;/code&gt; and &lt;code&gt;write:packages&lt;/code&gt; scopes.&lt;br&gt;
If the repository you want to publish is private, the token additionally needs the &lt;code&gt;repo&lt;/code&gt; permission.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create or edit the &lt;code&gt;.npmrc&lt;/code&gt; file in your home directory (&lt;code&gt;~/.npmrc&lt;/code&gt;) and add the following line, replacing &lt;code&gt;TOKEN&lt;/code&gt; with the personal access token created above:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//npm.pkg.github.com/:_authToken=TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Each package has to be explicitly told to publish to the GPR. Otherwise, npm will fall back to the npm registry.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create or edit the &lt;code&gt;.npmrc&lt;/code&gt; file in the root of your project. Add the following line and replace &lt;code&gt;OWNER&lt;/code&gt; with the username of the GitHub user or organization you want to publish to (i.e. the scope):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@OWNER:registry=https://npm.pkg.github.com
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(The &lt;code&gt;@&lt;/code&gt; is part of the config syntax and should not be replaced.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure your &lt;code&gt;package.json&lt;/code&gt; is properly configured:&lt;/p&gt;

&lt;p&gt;The package name should be prefixed with the scope. &lt;code&gt;PACKAGE&lt;/code&gt; here is the actual name of your package. (Again, keep the &lt;code&gt;@&lt;/code&gt;):&lt;br&gt;
&lt;/p&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@OWNER/PACKAGE"&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;p&gt;The &lt;code&gt;repository&lt;/code&gt; field should point to the GitHub repository you're publishing:&lt;br&gt;
&lt;/p&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;"repository"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/OWNER/REPO"&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;p&gt;It's also possible to publish multiple packages per repo, by changing only the package name but keep pointing the &lt;code&gt;repository&lt;/code&gt; field to the same repo.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Publish!
&lt;/h2&gt;

&lt;p&gt;All that's left to do is to create a GitHub repository for the package if it doesn't have one already, pushing the new changes, and running &lt;code&gt;npm publish&lt;/code&gt;! (As far as I can tell, Yarn doesn't currently support publishing to registries other than npm.) If everything went right, you should see the first version of your package being published on &lt;a href="https://github.com/OWNER/REPO/packages"&gt;https://github.com/OWNER/REPO/packages&lt;/a&gt; (check out &lt;a href="https://github.com/jgierer12/hooks/packages"&gt;one of my own packages&lt;/a&gt; for an example.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Consuming a GPR package
&lt;/h2&gt;

&lt;p&gt;Now that you published a package to the GPR, you or someone else might want to use it as a dependency in another project. To do so, you need to again add the relevant GPR URL to the project's &lt;code&gt;.npmrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@OWNER:registry=https://npm.pkg.github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An important thing to note is that you need to repeat this process for every different GPR scope you want to use. So if you want to install the packages &lt;code&gt;@facebook/react&lt;/code&gt;, &lt;code&gt;@facebook/react-dom&lt;/code&gt;, &lt;code&gt;@webpack/webpack&lt;/code&gt;, and &lt;code&gt;@babel/core&lt;/code&gt;, the &lt;code&gt;.npmrc&lt;/code&gt; should look 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;@facebook:registry=https://npm.pkg.github.com
@webpack:registry=https://npm.pkg.github.com
@babel:registry=https://npm.pkg.github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are just for demonstration purposes, at the time of writing none of these organizations have published any packages to the GPR yet. &lt;/p&gt;

&lt;p&gt;What's nice though is that without any further config, you can install any package from the npm registry alongside those. So if you were to &lt;code&gt;npm install lodash&lt;/code&gt; with the above config, it would still be able to resolve lodash from npm's registry. Just be careful if the package you want to install is scoped under the same user as a GPR package — you can't install &lt;code&gt;@foo/bar&lt;/code&gt; from the npm registry and &lt;code&gt;@foo/baz&lt;/code&gt; from the GPR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-publishing
&lt;/h2&gt;

&lt;p&gt;If you'd like to start publishing to the GPR, but don't want to force users into switching registries, it's very easy to setup a 'hybrid' approach that publishes to both the GPR and the npm registry. Just setup a &lt;code&gt;postpublish&lt;/code&gt; script in &lt;code&gt;package.json&lt;/code&gt; like so:&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;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"postpublish"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm publish --ignore-scripts --@OWNER:registry='https://registry.npmjs.org'"&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;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;Note the &lt;code&gt;--ignore-scripts&lt;/code&gt; flag which prevents the &lt;code&gt;postpublish&lt;/code&gt; script to call itself again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;As you can see, it isn't exactly trivial to publish and consume packages from/to the GPR. Both GitHub and the npm/yarn developers need to put in some work to make this experience smoother, especially for the package consumers. That being said, it's great having a serious competitor to the npm registry, and the integrations into the GitHub interface and Actions are already looking really useful. I'll certainly cross-publish my future packages to GitHub, and install from there whenever possible.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;&lt;a href="https://unsplash.com/photos/fyaTq-fIlro"&gt;Cover&lt;/a&gt; by &lt;a href="https://unsplash.com/@chuttersnap"&gt;chuttersnap&lt;/a&gt; on &lt;a href="https://unsplash.com"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>registry</category>
      <category>javascript</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
