<?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: Joost Jansky</title>
    <description>The latest articles on DEV Community by Joost Jansky (@styxlab).</description>
    <link>https://dev.to/styxlab</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%2F414320%2Fcc3adc4c-5dd3-4186-b9fe-fd2d1540b650.png</url>
      <title>DEV Community: Joost Jansky</title>
      <link>https://dev.to/styxlab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/styxlab"/>
    <language>en</language>
    <item>
      <title>Image Uploads with Blogody</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Thu, 30 Sep 2021 21:36:33 +0000</pubDate>
      <link>https://dev.to/styxlab/image-uploads-with-blogody-foa</link>
      <guid>https://dev.to/styxlab/image-uploads-with-blogody-foa</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GjyZt6H4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/e6196dfdb689c384219ac8231f347b75/upload-images-to-the-blogody-cloud-platform-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GjyZt6H4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/e6196dfdb689c384219ac8231f347b75/upload-images-to-the-blogody-cloud-platform-1.png" alt="Image Uploads with Blogody" width="880" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am really excited to announce a new &lt;strong&gt;integrated image upload feature&lt;/strong&gt; today! You can start adding your local images the same way as public images — with zero configuration. All images you see in this article have been added that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uploading Images
&lt;/h2&gt;

&lt;p&gt;Here is a small demo that shows how to upload images in the editor. The new function is included in the side-menu that you can reach over the &lt;em&gt;plus sign&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gXJL_Xfk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/96a92d00c4cf030191c5942dfff494e8/blogody-image-upload-demo-1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gXJL_Xfk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/96a92d00c4cf030191c5942dfff494e8/blogody-image-upload-demo-1.gif" alt="Image Uploads with Blogody" width="880" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this new feature, there is a small &lt;em&gt;breaking change&lt;/em&gt; that you’ll get quickly accustomed with. The image icon (first icon in the figure below) was previously used for &lt;em&gt;image links&lt;/em&gt; but it is now used for uploading images. The image link feature is still available under a new icon (second icon in the figure below) which better depicts the link nature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KFYtTXDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/09/blogody-side-menu-icons-for-images-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KFYtTXDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/09/blogody-side-menu-icons-for-images-1.png" alt="Image Uploads with Blogody" width="205" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have been asked why image uploads was not part of the initial release and the answer is twofold. First, many people already have their images stored in the cloud and in this case it’s easier to just add a public link to the already existing image. This prevents image duplication and allows to include what people are already used to.&lt;/p&gt;

&lt;p&gt;The second reason is that an image upload feature needs an image store and I wanted to take the time to find the best solution for Blogody. The chosen solution abstracts storage management away, so that you don’t need to think about the image store at all — &lt;strong&gt;everything is handled for you in the background&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting images with Blogody
&lt;/h2&gt;

&lt;p&gt;That’s right, when you upload an image it gets hosted on the &lt;strong&gt;Blogody platform&lt;/strong&gt;. You can upload &lt;strong&gt;up to 500 images&lt;/strong&gt; on the &lt;strong&gt;Free Plan&lt;/strong&gt; and &lt;strong&gt;up to 10.000 images&lt;/strong&gt; on the &lt;strong&gt;Pro Plan&lt;/strong&gt;. Many media blog posts have one feature image and more image heavy posts typically have less than 5 images per article. That translates to more than 500 posts on the free and 2.000 posts on the pro tier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that you can always include an &lt;strong&gt;unlimited number of image links&lt;/strong&gt; , so that you can fully utilize the cloud storage that you booked elsewhere.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While this is plenty for many use cases, it’s probably not enough if you plan a dedicated photo blog. Once you reach one of the limits, you’ll get notified the next time you try to upload a new image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BQpPhDN8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/09/blogody-image-limit-pro-plan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BQpPhDN8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/09/blogody-image-limit-pro-plan.png" alt="Image Uploads with Blogody" width="707" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Blogody image URLs and privacy
&lt;/h2&gt;

&lt;p&gt;When you upload an image, the full image data is compressed and transferred to the platform storage. The editor immediately displays a preview image and transitions to the stored image once the upload is completed. The final image URL follows the following pattern:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://assets.blogody.com/image/FrcZODKj5JCZM/your-image.png"&gt;https://assets.blogody.com/image/FrcZODKj5JCZM/your-image.png&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The fixed part is followed by a random 13 character unique identifier. The image name is taken from the selected filename and &lt;em&gt;slugified&lt;/em&gt; to improve search engine results. Thus, image links are designed to fulfill the following properties.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Links live on &lt;strong&gt;blogody.com&lt;/strong&gt; for excellent domain authority.&lt;/li&gt;
&lt;li&gt;Use a small identifier to get &lt;strong&gt;short URLs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized for search engines&lt;/strong&gt; through the asset and image keywords and further improved by the slugified name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard to discover&lt;/strong&gt; if you don’t know the link.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The last property is important to give your image &lt;strong&gt;moderate&lt;/strong&gt;  &lt;strong&gt;privacy.&lt;/strong&gt; Of course, once you publish your article, the link is public and everyone who can read your article can also access your image. Nonetheless, it’s hard to guess an image link _ &lt;strong&gt;before&lt;/strong&gt; _ your article is published.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search engine Optimization (SEO)
&lt;/h2&gt;

&lt;p&gt;As described before, image links are automatically generated, so there is nothing for you to configure. However, you can improve search engine results by giving your images descriptive names. That no only helps search engines, it’s also a good idea when it comes to organizing images on your local computer.&lt;/p&gt;

&lt;p&gt;Avoid giving images a generic name such as &lt;code&gt;image1.jpg&lt;/code&gt;, &lt;code&gt;image2.png&lt;/code&gt;, instead create the name from a short description such as: &lt;code&gt;blogody-image-upload-demo.gif&lt;/code&gt;. This would result in the following URL:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://assets.blogody.com/image/Az3BKFJt6EWCV/blogody-image-upload-demo.gif"&gt;https://assets.blogody.com/image/Az3BKFJt6EWCV/blogody-image-upload-demo.gif&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You’ll get the idea: Use the image name to tell something about its content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Image lifecycle on Blogody
&lt;/h2&gt;

&lt;p&gt;As we saw earlier, images are uploaded to the platform whenever you add an image to your post or page. But what happens if you delete an image in the editor? It may surprise you that it stays on the platform and is still available. It’s been designed that way so you don’t need to upload the same image a second time if needed.&lt;/p&gt;

&lt;p&gt;Internally, every uploaded image is connected to a post or page. That means all images associated with a post are deleted when you delete the post. The same is the case when you delete an entire project.&lt;/p&gt;

&lt;p&gt;The described image lifecycle ensures that we don’t pile up images that are not needed anymore, but also ensures images are uploaded only when needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;The new image upload feature is just the beginning of more image related functions in Blogody. It’s an important feature, because it opens the door for automatic image optimizations and cool image manipulations. Stay tuned for the next episode of working with images in Blogody.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This post was originally published at &lt;a href="https://www.blogody.com/news"&gt;Blogody News&lt;/a&gt; on September 30, 2021.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>images</category>
      <category>blogody</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to work with images in Blogody</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Fri, 17 Sep 2021 19:31:11 +0000</pubDate>
      <link>https://dev.to/styxlab/how-to-work-with-images-in-blogody-58og</link>
      <guid>https://dev.to/styxlab/how-to-work-with-images-in-blogody-58og</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3kVFJjUt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/d6887cb06b9ba7854c93902b1c9cbfe9/blogody_image_workflow-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3kVFJjUt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/d6887cb06b9ba7854c93902b1c9cbfe9/blogody_image_workflow-1.jpg" alt="How to work with images in Blogody" width="880" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Images are currently not hosted on Blogody, which means they need to be stored on external cloud providers. This is exactly what many users are used to as they already store their images in the cloud and are not interested in moving them somewhere else.&lt;/p&gt;

&lt;p&gt;You simply add a public link of your image and it gets embedded in your article. However, if you want to add an image that’s only locally available on your computer, you can’t just upload it to Blogody. You must upload it to your cloud storage first.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am currently working on a new feature that will allow uploading images directly to Blogody. This will open exciting new possibilities for image transformations, optimizations and SEO.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article focuses on how to best work with images in Blogody today and I’d like to start with the easiest way to add images by using the integrated &lt;a href="https://www.unsplash.com"&gt;Unsplash&lt;/a&gt; image library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add free Unsplash images
&lt;/h2&gt;

&lt;p&gt;An Unsplash widget has been integrated into the Blogody editor that you can reach over the side-menu. Unsplash provides a stunning library of free images that are hosted on their own CDN for fast image loading speeds. See how easily you can embed new images:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8XmhQK3w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/6e41bbb9b7633fddf21b974e2b6e1200/images_unsplash.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8XmhQK3w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/6e41bbb9b7633fddf21b974e2b6e1200/images_unsplash.gif" alt="How to work with images in Blogody" width="880" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The keyword search makes it easy to find images for almost any topic that you can think of. It’s really a professional tool - and once you watch out for the image attribution line at even the most reputable newspapers worldwide, you’ll see that many of them use exactly the same image library for their top news stories. You are definitely in good company!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding images with public URLs
&lt;/h2&gt;

&lt;p&gt;While Unsplash gives you access to a wide variety of images, you may also want to to add images of your own. A screenshot you made, an image from your camera or one that you purchased from another image library such as &lt;a href="https://www.istockphoto.com"&gt;istockphoto&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If these images are already accessible over a public URL (e.g. https://.../image.png), you can embed those right here in Blogody. There are a couple of different ways to do it — choose the method that feels most suitable for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy &amp;amp; Paste Image Link
&lt;/h3&gt;

&lt;p&gt;If you have an public image link copied to your clipboard, you can add it over the side-menu by clicking the image icon, pasting the link and pressing enter. Here is an example with the following link: &lt;strong&gt;&lt;a href="https://picsum.photos/seed/picsum/750/500"&gt;https://picsum.photos/seed/picsum/750/500&lt;/a&gt;&lt;/strong&gt; from another interesting image service that you can use to test it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uEmCe3vq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/ea54615c9a5979adaa00b64d5b434424/images_paste.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uEmCe3vq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/ea54615c9a5979adaa00b64d5b434424/images_paste.gif" alt="How to work with images in Blogody" width="880" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Drag &amp;amp; Drop images
&lt;/h3&gt;

&lt;p&gt;Let’s say you have a website where your public image is already published and you want to embed an image from that site into a new article that you author in Blogody. In this case, I like to open another browser window and simply drag and drop the image to Blogody. See how it works in the following screencast.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LIXiJ2u7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/372266535d31dd9b4418e94ff1e12608/images_drag.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LIXiJ2u7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/372266535d31dd9b4418e94ff1e12608/images_drag.gif" alt="How to work with images in Blogody" width="752" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice the different cursors? You can only drop the image when you see a cursor popping up when you hover your dragged image.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A really cool feature that you’ll love once you know how to use it is the so called &lt;strong&gt;gap cursor&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Drag &amp;amp; drop between content blocks
&lt;/h3&gt;

&lt;p&gt;The gap cursor is the one that shows a &lt;strong&gt;horizontal line&lt;/strong&gt; and it allows you to to insert images in between content blocks. While the above image is dropped on a regular cursor, here is an example that uses the gap cursor. Watch how to insert the image between the title and the paragraph although there is no empty line in between.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P-nbLu3i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/18e44061ec444de990b49afcde0333f8/images_gapcursor.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P-nbLu3i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/18e44061ec444de990b49afcde0333f8/images_gapcursor.gif" alt="How to work with images in Blogody" width="640" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy &amp;amp; Paste images directly
&lt;/h3&gt;

&lt;p&gt;If a website lets you select an image, you can usually copy the image directly (without copying the image link). All methods presented here also work &lt;em&gt;within&lt;/em&gt; the Blogody editor. So I can showcase it directly here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fYvkiiXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/7a02f72f62f428e75cdceb935f27724d/images_direct_copy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fYvkiiXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/7a02f72f62f428e75cdceb935f27724d/images_direct_copy.gif" alt="How to work with images in Blogody" width="640" height="337"&gt;&lt;/a&gt;Select, copy and paste images in Blogody&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pro Tip: Use &lt;code&gt;Ctrl + c&lt;/code&gt; and &lt;code&gt;Ctrl + v&lt;/code&gt; to copy/paste for a faster alternative to using the above shown right-click context menus.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The direct copy/paste feature is not exclusive to images. You can actually copy/paste entire articles — including images — from other content editors or websites directly into Blogody.&lt;/p&gt;

&lt;h2&gt;
  
  
  Image Cloud Providers
&lt;/h2&gt;

&lt;p&gt;All methods shown above have one thing in common: your image is already publicly available. A screenshot that you make on your computer or mobile, unless automatically synced with your cloud store, is usually not publicly accessible. Even if your images are already stored in the cloud, access restrictions are usually in place, so that it cannot be accessed publicly. Most providers allow you to generate public image URLs or create a public image folder.&lt;/p&gt;

&lt;p&gt;Just in case you do not yet have your images in the cloud or have trouble making them publicly accessible, I am going to show the general workflow with one image provider that I use. There are many other options available, so please take some time before deciding which one you want to settle with. Here are some high level criteria you may want to consider:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;reliability and reputation of the provider&lt;/li&gt;
&lt;li&gt;speed and distribution of CDN (make sure images reside on a CDN)&lt;/li&gt;
&lt;li&gt;costs (may not be easy to calculate)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s start by making a screenshot, save it to the local disk and upload it to &lt;a href="https://cloudinary.com"&gt;Cloudinary&lt;/a&gt;, the image provider that I chose for this demo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloudinary image service
&lt;/h3&gt;

&lt;p&gt;I am going to make a screenshot of my GitHub contribution graph, not very exciting but enough to demonstrate uploading images to Cloudinary. So the steps are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;make a screenshot and save it to local disk (not shown)&lt;/li&gt;
&lt;li&gt;upload the image to Cloudinary&lt;/li&gt;
&lt;li&gt;copy public image link into Blogody&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--igBS0k9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/34b2b31c8d2f8f0923493f6802352f55/images_cloudinary.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--igBS0k9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/34b2b31c8d2f8f0923493f6802352f55/images_cloudinary.gif" alt="How to work with images in Blogody" width="880" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thus, there is an extra step compared to the previous methods: uploading the image to the cloud provider. In addition to the public URL, Cloudinary gives you a fast CDN and a rich set of transformation tools. That in itself might be worth checking out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final notes
&lt;/h2&gt;

&lt;p&gt;Congrats for following through this guide about working with images in Blogody 🎉. The most important take-away is that your images must be publicly available before you can add them to your posts or pages in Blogody.&lt;/p&gt;

&lt;p&gt;As mentioned above, a new &lt;em&gt;image upload feature&lt;/em&gt; is in the pipeline and it will make adding local images much easier. Nonetheless, hosting images with an image cloud provider may still be of interest to you as it can be a great way to store, organize and enhance your images.&lt;/p&gt;

&lt;p&gt;Anything you want to share with me about your experience when it comes to working with images? Just use the &lt;em&gt;Feedback&lt;/em&gt; button in Blogody and shoot me a message.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This post was originally published at &lt;a href="https://www.blogody.com/news"&gt;Blogody News&lt;/a&gt; on September 17, 2021.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>images</category>
      <category>blogody</category>
      <category>guide</category>
    </item>
    <item>
      <title>How to export your Blogody blogs</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Thu, 26 Aug 2021 21:31:29 +0000</pubDate>
      <link>https://dev.to/styxlab/how-to-export-your-blogody-blogs-n0f</link>
      <guid>https://dev.to/styxlab/how-to-export-your-blogody-blogs-n0f</guid>
      <description>&lt;p&gt;Blogody is different than most other service platforms in that it obsessively cares about your content rights. The slogan “&lt;em&gt;You own your own words&lt;/em&gt;” has been well chosen to reflect the commitment to give you absolutely full control over you data.&lt;/p&gt;

&lt;p&gt;This promise applies to your published content, and equally important, it means that I do everything so that you can access and reuse your content just as you like. No barriers and no vendor lock-ins. That’s why I am delighted to announce a new &lt;em&gt;export feature&lt;/em&gt; today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blogody export feature
&lt;/h2&gt;

&lt;p&gt;This feature is now available on all plans, including the &lt;a href="https://www.blogody.com/pricing"&gt;Free Plan&lt;/a&gt;. To test it out, just go to &lt;em&gt;Settings -&amp;gt; Export&lt;/em&gt; and press the &lt;em&gt;Export&lt;/em&gt; button. This will generate a JSON file and initiate a file download in your browser.&lt;/p&gt;

&lt;p&gt;The export works on a per-project basis, which means that the file contains all the data associated with the currently active project. To export another project, just switch to that project and repeat the steps outlined above.&lt;/p&gt;

&lt;h3&gt;
  
  
  What data is exported?
&lt;/h3&gt;

&lt;p&gt;In short, all the data that you created in Blogody, from settings to posts and pages. The JSON key fields represent the different categories. The file is structured as follows:&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="err"&gt;blogody:&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="err"&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="err"&gt;settings:&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="err"&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="err"&gt;tags:&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="err"&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="err"&gt;authors:&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="err"&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="err"&gt;posts:&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="err"&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="err"&gt;pages:&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="err"&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="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 first &lt;code&gt;blogody&lt;/code&gt; section contains some meta data about the export, mainly the project name, exporter version and timestamp. The other sections contain the actual data that you created in Blogody.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why JSON?
&lt;/h3&gt;

&lt;p&gt;I have chosen &lt;a href="https://www.json.org/json-en.html"&gt;JSON&lt;/a&gt; as the export format for the following reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  it’s an open industry standard that is technology agnostic,&lt;/li&gt;
&lt;li&gt;  it’s human readable (in contrast to a binary file),&lt;/li&gt;
&lt;li&gt;  it’s lightweight and produces smaller file sizes than other formats.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These properties make it a perfect choice for Blogody. That said, I do recognize that you may want to work with other formats. That’s, of course, possible by converting the JSON to your desired format. I’ll discuss one of these possible conversions further below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your sensitive data remains protected
&lt;/h3&gt;

&lt;p&gt;For security reasons, your API tokens are not included in the export file. Access to your tokens will always remain in the platform interface in order to protect you from accidental proliferation of secrets.&lt;/p&gt;

&lt;p&gt;Note that your Google Measurement ID is included in the file. Everyone who visits your site can see this ID, that’s why it is not considered sensitive information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blogody API Export
&lt;/h2&gt;

&lt;p&gt;If you are a developer and want to access Blogody programmatically, we have you covered as well. This feature is currently available for all users on the &lt;a href="https://www.blogody.com/pricing"&gt;Pro Plan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All the data that is exported into the above mentioned JSON file, can also be fetched directly from the API. You can either directly introspect and use the GraphQL API or use the &lt;a href="https://www.blogody.com/news/blogody-api-client-released"&gt;Blogody API Client&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As exporting data is such a common use case, I’ve also build an open-source package &lt;a href="https://github.com/blogody/export"&gt;@blogody/export&lt;/a&gt; that you can use to produce different output formats. Currently it supports generating a JSON file containing all data.&lt;/p&gt;

&lt;p&gt;To showcase the power of the API and because some users requested an easy method to generate Markdown, the exporter lets you convert your posts and pages into Markdown as an alternative to HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The new export feature — although small — is another milestone in delivering data sovereignty to all users. When you create your articles with Blogody, your data remains under your full control. Making it easy for you to access your data, so that you can do everything with it as you like, continues to be one of Blogody’s top priorities.&lt;/p&gt;




&lt;p&gt;This post was originally published at &lt;a href="https://www.blogody.com/news"&gt;Blogody News&lt;/a&gt; on August 26, 2021.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>beginners</category>
      <category>blogger</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Google Analytics + Blogody</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Thu, 26 Aug 2021 21:19:45 +0000</pubDate>
      <link>https://dev.to/styxlab/google-analytics-blogody-54n</link>
      <guid>https://dev.to/styxlab/google-analytics-blogody-54n</guid>
      <description>&lt;p&gt;A new &lt;strong&gt;Google Analytics integration feature&lt;/strong&gt; has been added to Blogody today. Just log on to your Blogody account and you’ll find the new integration under &lt;strong&gt;&lt;em&gt;Settings &amp;gt; Analytics&lt;/em&gt;&lt;/strong&gt;. That’s the beauty of &lt;em&gt;Software as a Service&lt;/em&gt;: no need to worry about updating or installing anything — &lt;strong&gt;new features are instantly available to you&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Google Analytics is the most widely used web analytics service on the web. The new &lt;strong&gt;Blogody integration allows you to track page views, user scroll, outbound clicks and other user engagements.&lt;/strong&gt; The only prerequisite is a free Google Analytics account. The following six, easy-to-follow steps show how to create a new Google &lt;em&gt;measurement ID&lt;/em&gt; and use it in Blogody to start tracking your site.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that you can track different Blogody blogs individually with different measurement IDs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1: Navigate to your Analytics Dashboard
&lt;/h2&gt;

&lt;p&gt;I assume that you have already created a Google Account and are able to log on to your &lt;a href="https://analytics.google.com"&gt;Google Analytics dashboard&lt;/a&gt;. For your Blogody blog, you’ll typically want to create a new analytics view. This is done by creating a new &lt;em&gt;account (not to be confused with your Google Analytics account that you earlier logged on to).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create a new account
&lt;/h2&gt;

&lt;p&gt;Click on the gear icon in the lower left corner of your dashboard which opens the &lt;em&gt;Admin&lt;/em&gt; section. This is the place where you create a &lt;em&gt;new account&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zOaY7DSa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qwd5ukrt5xf8qmu7hr5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zOaY7DSa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qwd5ukrt5xf8qmu7hr5u.png" alt="create account"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking the &lt;em&gt;Create Account&lt;/em&gt; button, you’ll see a new setup view, where you need to give your &lt;em&gt;account&lt;/em&gt; a new &lt;em&gt;name&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--icr8z-yP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nm5x844q3rludsv37ssp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--icr8z-yP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nm5x844q3rludsv37ssp.png" alt="account name"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s the only information required on this page, but it’s interesting to spend a minute to review the &lt;em&gt;Account Data Sharing&lt;/em&gt; settings. The settings &lt;strong&gt;do not influence your traffic measurement&lt;/strong&gt;, but they do influence what data Google is allowed to share with others (including its own services).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Best privacy is achieved by deactivating all checkboxes in the section entitled &lt;strong&gt;account data sharing settings&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Click the &lt;em&gt;Next button&lt;/em&gt; when your are done on this page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Create a new property
&lt;/h2&gt;

&lt;p&gt;As long as you do not need to use different &lt;em&gt;data sharing settings,&lt;/em&gt; you can have one account for all your web sites. You can separate your sites through *properties *as an account can contain one or more properties. Thus, your *property name *should represent the website or blog that you want to measure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ziS_IuP6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7s5vln6hmj26xeegdgld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ziS_IuP6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7s5vln6hmj26xeegdgld.png" alt="create property"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Optionally, you can set your timezone and local currency. Advanced settings are only for legacy options and can be ignored. Click &lt;em&gt;Next&lt;/em&gt; to get to the next view where you are asked to provide your business information. This section does not need to be filled out and can be left empty. Just make sure to click the &lt;em&gt;Create&lt;/em&gt; &lt;em&gt;button&lt;/em&gt; at the end and accept the terms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Create a data stream
&lt;/h2&gt;

&lt;p&gt;The Google set up flow redirects you to the &lt;em&gt;Data Streams&lt;/em&gt; section which is part of your newly created property. To start collecting data for your blog, you must choose the &lt;em&gt;web platform&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IjPqCnyt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxu948jqopjb05tihgo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IjPqCnyt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxu948jqopjb05tihgo9.png" alt="data stream"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill in the blog URL which can be either your &lt;em&gt;blogody.com&lt;/em&gt; domain (e.g. of the form https://&lt;em&gt;subdomain&lt;/em&gt;.blogody.com) or &lt;strong&gt;your custom domain&lt;/strong&gt;, if you configured one in Blogody.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qyT5ka1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tokt8nrrjs7g9r25yegp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qyT5ka1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tokt8nrrjs7g9r25yegp.png" alt="web stream"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;stream name&lt;/strong&gt; serves a stream identifier and can be chosen arbitrarily. It’s a good idea is to take the subdomain for your stream name. Finally, hit the *Create stream *button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Disable history events
&lt;/h2&gt;

&lt;p&gt;As you can see, a &lt;em&gt;measurement ID&lt;/em&gt; has been created. That is the token you need to add to your blog in the Blogody platform. Before we do so, &lt;strong&gt;you must deactivate history event detection, otherwise you will get incorrect measurement results.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1uRZixof--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ntweso25sg53n1v027y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1uRZixof--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ntweso25sg53n1v027y.png" alt="history settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the gear icon and a side menu opens. The history events options is hidden under &lt;em&gt;advanced settings&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AO3JHrBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ed069ryuxsekwhd0ovqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AO3JHrBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ed069ryuxsekwhd0ovqq.png" alt="advanced settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deselect &lt;em&gt;Page changes based on browser history events *and press&lt;/em&gt; Save.*&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Blogody is build on NextJS which has a pushState in place for state management purposes. This push populates the history stack and would cause an additional page view fired if you leave the history event option toggled on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 6: Add your measurement ID to Blogody
&lt;/h2&gt;

&lt;p&gt;Finally, you can connect the generated &lt;em&gt;measurement ID&lt;/em&gt; to your blog. Copy the ID to your clipboard, in the above example it would be &lt;strong&gt;G-ER92JRD0S5&lt;/strong&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Log into your Blogody account, choose the blog project you want to start tracking and add the &lt;em&gt;measurment ID&lt;/em&gt; under &lt;em&gt;Settings &amp;gt; Analytics &amp;gt; Google Analytics&lt;/em&gt; as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2c4J1n2W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9fmj08yfebgrt1n5s1qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2c4J1n2W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9fmj08yfebgrt1n5s1qh.png" alt="measurement ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now everything is set up and you can start monitoring your analytics data 🎉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;Are you looking for another integration or favor another analytics provider? Send me a message via the &lt;em&gt;Feedback button&lt;/em&gt; in Blogody and let me know!&lt;/p&gt;




&lt;p&gt;This post was originally published at &lt;a href="https://www.blogody.com/news"&gt;Blogody News&lt;/a&gt; on August 18, 2021.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>blogger</category>
    </item>
    <item>
      <title>Blogody API Client 🔥</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Thu, 26 Aug 2021 21:08:08 +0000</pubDate>
      <link>https://dev.to/styxlab/blogody-api-client-2pmk</link>
      <guid>https://dev.to/styxlab/blogody-api-client-2pmk</guid>
      <description>&lt;p&gt;The Blogody API Client makes pulling data from headless Blogody a breeze. It serves two major purposes: easy data fetching from Blogody into your JavaScript/TypeScript projects and demonstrating the use of the Blogody GraphQL interface.&lt;/p&gt;

&lt;p&gt;I am excited to release the &lt;a href="https://github.com/Blogody/api-client"&gt;Blogody API Client&lt;/a&gt; today on a free open-source license. It is &lt;strong&gt;for developers&lt;/strong&gt; who want to &lt;em&gt;programmatically fetch&lt;/em&gt; data from &lt;a href="https://www.blogody.com"&gt;Blogody&lt;/a&gt;. The API client is a tiny, isomorphic &lt;em&gt;TypeScript package&lt;/em&gt; that communicates with Blogody over it’s built-in &lt;strong&gt;GraphQL interface&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Note that there will be other export mechanisms coming to Blogody soon, that don’t require any programming skills. However, if you like to play around with code, you can use this client to &lt;em&gt;backup your published articles&lt;/em&gt;, &lt;em&gt;feed other systems&lt;/em&gt; or even make your &lt;em&gt;own front-end theme&lt;/em&gt;. There are so many possibilities!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You need to be on the Blogody Pro Plan in order to be able to use the API&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;I assume that you are familiar with Javascript/TypeScript and know how to write code that can be executed with NodeJS or in the browser. First you need to install the client from &lt;code&gt;npm&lt;/code&gt;:&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="nx"&gt;yarn&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;blogody&lt;/span&gt;&lt;span class="sr"&gt;/api-clien&lt;/span&gt;&lt;span class="err"&gt;t
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will download the package from &lt;code&gt;npm&lt;/code&gt; and add the client to your &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Usage
&lt;/h3&gt;

&lt;p&gt;Using the package and fetching data is dead simple. After importing the &lt;code&gt;BlogodyAPI&lt;/code&gt; class, you simply instantiate it with your API key. You can then call the &lt;code&gt;async&lt;/code&gt; functions like &lt;code&gt;api.settings()&lt;/code&gt; or &lt;code&gt;api.posts()&lt;/code&gt; to fetch the data.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BlogodyAPI&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;@blogody/api-client&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;api&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;BlogodyAPI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR BLOGODY API ACCESS KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// make an API calls&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;settings&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;posts&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;()&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;posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many more functions available, so you can fetch &lt;code&gt;authors&lt;/code&gt; and &lt;code&gt;tags&lt;/code&gt; as well. As the client is written in &lt;em&gt;TypeScript&lt;/em&gt; all available functions and options are shown to you when you hover in an editor that supports intelisense.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where to find the API key?
&lt;/h3&gt;

&lt;p&gt;You need to generate your key in Blogody under &lt;em&gt;Settings -&amp;gt; Developers&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OxqowE8h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dai7gzkbgllntrg0mtqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OxqowE8h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dai7gzkbgllntrg0mtqr.png" alt="blogody screenshot"&gt;&lt;/a&gt;&lt;br&gt;
Substitute &lt;code&gt;YOUR BLOGODY API ACCESS KEY&lt;/code&gt; in the above code snippet with the newly generated key.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s next?
&lt;/h3&gt;

&lt;p&gt;Let me know if you have created something cool with it and I’ll be more than happy to share with the world.&lt;/p&gt;




&lt;p&gt;This post was originally published at &lt;a href="https://www.blogody.com/news"&gt;Blogody News&lt;/a&gt; on August 11, 2021.&lt;/p&gt;

</description>
      <category>blogging</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>saas</category>
    </item>
    <item>
      <title>On-demand Static Regeneration: How Blogody serves multi-zone blog sites</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Sun, 16 May 2021 15:38:00 +0000</pubDate>
      <link>https://dev.to/styxlab/on-demand-static-regeneration-how-blogody-serves-multi-zone-blog-sites-3oll</link>
      <guid>https://dev.to/styxlab/on-demand-static-regeneration-how-blogody-serves-multi-zone-blog-sites-3oll</guid>
      <description>&lt;p&gt;Never heard of On-demand Static Regeneration, or OSR? No wonder! It's a new acronym that we invented for this article in order to describe an exciting new evolution of how we can generate and publish blazing fast static web sites on the web.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jP5e4WoA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/86aae77d5a58288b24ab3844770a5822/Regeneration-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jP5e4WoA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/86aae77d5a58288b24ab3844770a5822/Regeneration-3.png" alt="On-demand Static Regeneration: How Blogody serves multi-zone blog sites"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is currently a lot of heated debate about new ways of building Jamstack sites, with new approaches that are called &lt;em&gt;beyond Jamstack&lt;/em&gt;, &lt;em&gt;hybrid web development&lt;/em&gt; or &lt;em&gt;hybrid serverless + static&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I am introducing a new addition to the existing hybrid approaches, that I call &lt;strong&gt;On-demand Static Regeneration (OSR)&lt;/strong&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On-demand Static Regeneration
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;OSR&lt;/strong&gt; is based on &lt;strong&gt;Incremental Static Regeneration (ISR)&lt;/strong&gt; that was invented by &lt;a href="https://nextjs.org/"&gt;NextJS&lt;/a&gt;. Consider a web page that has not been statically built. With ISR, the first visitor sees a fallback page, for example a skeleton of the real site. The cool thing about ISR is that this first request triggers a &lt;strong&gt;static regeneration&lt;/strong&gt; , which means all &lt;strong&gt;subsequent requests&lt;/strong&gt; receive a fully built static site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On-demand Static Regeneration&lt;/strong&gt; is an extension to that process, in that the first request is not made by a visitor, it is &lt;strong&gt;automatically triggered by a web hook&lt;/strong&gt;. We'll see later in this article, that there are always natural events that can be used as a trigger.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In effect, &lt;strong&gt;every visitor&lt;/strong&gt; to your site &lt;strong&gt;always receives a static built, blazing fast, up-to-date site&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before going into more details, let's take a step back and put everything into context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jamstack &amp;amp; Static Site Generation
&lt;/h2&gt;

&lt;p&gt;The modern way to build websites that deliver blazing fast performance is based on the so called &lt;a href="https://jamstack.org/"&gt;Jamstack&lt;/a&gt; architecture. It's main conceptional principles can be summarized as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decouple the front-end from the back-end.&lt;/li&gt;
&lt;li&gt;Build as much as possible up-front through static site generation (SSG).&lt;/li&gt;
&lt;li&gt;Publish to the content-delivery-network (CDN), so it serves your content as pre-built assets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is fundamentally different from a traditional web server, where web sites are rendered on &lt;strong&gt;every page request&lt;/strong&gt; (SSR). A page that is SSR rendered cannot be put on a fast CDN edge.&lt;/p&gt;

&lt;p&gt;That's why &lt;em&gt;static site generators (SSG)&lt;/em&gt; have become so popular: pre-built content can be distributed globally through a CDN and serve pages from &lt;em&gt;edge gateways&lt;/em&gt; closest to where you are requesting the site. This allows for a much faster user experience and has a positive effect on Google page rankings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomic &amp;amp; Immutable Deployments
&lt;/h2&gt;

&lt;p&gt;While the previously outlined Jamstack principles do not say anything about the deployment process, most CDN providers use the method of &lt;strong&gt;atomic deployments&lt;/strong&gt; similar to Git commits. This means the entire site (code, assets, and configuration) is updated together at the same time.&lt;/p&gt;

&lt;p&gt;Atomic deployments are &lt;strong&gt;immutable&lt;/strong&gt; with sealed content and guaranteed integrity. Every atomic deployment gets an identifier that's never going to change. Any update will therefore produce a new deployment, similar to state-driven development where any change produces a new state in your application.&lt;/p&gt;

&lt;p&gt;Why would you want atomic and immutable deployments? It allows you &lt;strong&gt;instantly rollback your site to a previous state&lt;/strong&gt; without the need to re-build your site. For example, when you discover a mistake on your site after deployment, be it a typo or mixed-up brand color, you can instantly revert back to your any of your previous deploys. It's as easy as a &lt;code&gt;git reset&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites with Dynamic Content
&lt;/h2&gt;

&lt;p&gt;While pure static sites have their use cases, most web sites need some app-like features, that is, dynamic changes during runtime. A simple example for such a dynamic feature would be the number of likes of an article. Of course, you can statically re-build your site on a pre-defined schedule, but it's much nicer if the user giving a like, instantly sees it updated on the website.&lt;/p&gt;

&lt;p&gt;Dynamic runtime features of this kind are possible even with SSG, namely by utilizing client-side JavaScript code. When a user clicks the like button, it fires an event to a backend-API which updates the number of likes in the database. The client subsequently re-fetches the data to be displayed on the web site.&lt;/p&gt;

&lt;p&gt;While your deployment stays immutable as such, the content presented to the user (including the number of likes) is not defined by the unique deployment identifier anymore. It's total state now also depends upon the current state of your database.&lt;/p&gt;

&lt;p&gt;In this contrived example, this is probably exactly what you want: Even when reverting to a previous deployment, you certainly wish the site to show the latest number of likes. However, the more app-like content you introduce into your site, the more it looses the property pf immutability.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your web site uses app-like features with client-side dynamic content, atomic and immutable deployments do not guarantee an immutable web site.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The take-away from these examples is that the total state of an app-like static web site is governed by &lt;strong&gt;both your deployment state and the dynamic back-end&lt;/strong&gt; states resulting in a combined state that cannot be controlled by a unique identifier. As such, &lt;em&gt;supercharged&lt;/em&gt; Jamstack sites break that model of immutability to the degree of integrated app-like features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Site Generation Drawbacks
&lt;/h2&gt;

&lt;p&gt;When you read about all the benefits of the Jamstack and static site generators, its drawbacks are easily overlooked. One of the very early criticisms has been missing dynamic features, but this limitation is easily overcome with supercharging your site with JavaScript + APIs, although it does mean you need to loosen up the property of immutability as we saw earlier.&lt;/p&gt;

&lt;p&gt;Another drawback of pure static site builders is the time it takes to build an entire web site. While this is certainly not a problem for a handful of pages, it becomes near impossible to re-build a web site with thousands of pages, especially if paired with image optimizations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jg8ePHmf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/05/Build-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jg8ePHmf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/05/Build-1.png" alt="On-demand Static Regeneration: How Blogody serves multi-zone blog sites"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.gatsbyjs.com/"&gt;GatsbyJS&lt;/a&gt;' answer to this problem is called &lt;a href="https://www.jamify.org/2020/06/13/incremental-builds-with-jamify/"&gt;Incremental Builds&lt;/a&gt;, the idea being that you only re-build sites that changed since last deployment. While the idea sounds simple enough, it's a non-trivial task to assess possible dependencies between your pages and the GatsbyJS incremental build feature turned out very flaky (I was among the first users, so I hope it has improved by now). In principle, atomic deployments can be retained with this technique.&lt;/p&gt;

&lt;p&gt;Apart from the stability issues that may be overcome in the future, incremental builds have another, more severe drawback: It doesn't give you any benefit when you build your site for the first time. Depending on your site, it can take many hours to complete. Just imagine, you'll find a bug in between that initial build process. Only subsequent builds can leverage the previous build process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With all the recent advances of pure static site builders one challenge still remains: Building large web sites with many pages and heavy assets (images, videos, etc.) for the first time is an extremely time consuming process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Incremental Static Regeneration
&lt;/h2&gt;

&lt;p&gt;While incremental builds need a first static build, NextJS came up with another clever idea. Incremental Static Regeneration (ISR) extends the power of static sites with traditional server-side rendering (SSR).&lt;/p&gt;

&lt;p&gt;Instead of starting with a full static build, you start with a handful, critical static pages. This gives you more control over the initial build times.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZmBcTyIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/05/Cache-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZmBcTyIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/05/Cache-1.png" alt="On-demand Static Regeneration: How Blogody serves multi-zone blog sites"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whenever a user requests a pre-build static page, it'll receive a super fast static web site. But what happens, if the page has not been pre-build? In this case NextJS will use SSR to render the page for you, but in the background it will fire a static-site generation of the same page, so all subsequent visits to the same page will result in serving a static site again. Note that it is only the very first user that triggers the regeneration and that all subsequent visitors will see the static page.&lt;/p&gt;

&lt;p&gt;This approach is called &lt;em&gt;hybrid,&lt;/em&gt; because you (nearly) get the performance benefits of pure static site builders combined with the power of fully dynamic SSR sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Distributed Persistent Rendering
&lt;/h2&gt;

&lt;p&gt;Recently, Cassidy Williams (Netlify) has criticized the ISR approach in article entitled &lt;a href="https://www.netlify.com/blog/2021/03/08/incremental-static-regeneration-its-benefits-and-its-flaws/"&gt;&lt;em&gt;Incremental Static Regeneration: Its Benefits and Its Flaws&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt; While she acknowledges the benefits of ISR, the main argument against it is that &lt;strong&gt;ISR breaks the model of immutable deployments&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you read the argument carefully, you'll find out that it does not go against the core idea of ISR, it simply points towards the &lt;strong&gt;difficulty of purging the cache when you loose the property of immutable deployments.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While I agree that this is a difficult problem to solve, I do think this can be overcome and I am pretty sure &lt;a href="https://www.netlify.com/events/product-reveal/"&gt;Netlify has something up in their sleeve that is soon to be announced&lt;/a&gt;. My bet is that the newly introduced concept of &lt;a href="https://www.smashingmagazine.com/2021/05/evolution-jamstack/"&gt;&lt;strong&gt;Distributed Persistent Rendering (DPR)&lt;/strong&gt; that Matt Billmann talked about in Smashing Magazine&lt;/a&gt; just a few days ago, plays a fundamental role in tackling those challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  On-demand Static Regeneration
&lt;/h2&gt;

&lt;p&gt;How does On-demand Static Regeneration fit into this landscape? It solves the following two challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All visitors always get a super-fast statically built site.&lt;/li&gt;
&lt;li&gt;There are no up-front static built times, deploys complete within seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Too good to be true, what's the catch? First and foremost your deploys loose the property of immutability. Formally, immutability still exists for a single deployment, but as your deployment only consists of skeleton pages, its benefits have become only of minor importance.&lt;/p&gt;

&lt;p&gt;Thus, the state of your web site is governed mainly by the state of your database, which holds the content from which the static pages are generated on-demand.&lt;/p&gt;

&lt;p&gt;Let's take a look into how OSR achieves near zero deploy times. The skeleton pages do not contain much content, that's why a deploy can be so fast. The burden on generating static sites has been split into many small pieces (pages) and spread over a larger time-span. &lt;strong&gt;In contrast to ISR, regeneration does not occur on first visitor request, for OSR it occurs on&lt;/strong&gt; _ &lt;strong&gt;creation time.&lt;/strong&gt; _&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q-w1urvH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/05/Regeneration-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q-w1urvH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/05/Regeneration-4.png" alt="On-demand Static Regeneration: How Blogody serves multi-zone blog sites"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creation time&lt;/strong&gt; is the first event when your content is ready to be shown to the world. For a blog article, it is the time when you hit the &lt;strong&gt;publish&lt;/strong&gt; button and that's when OSR sends an automatic first request to your new or updated page, effectively regenerating your static site.&lt;/p&gt;

&lt;p&gt;If you sum up all the regeneration times of all the web pages of a web site it should equal the build times of a static site generator that builds all sites in a single build step. However, due to slicing your page into smaller units (i.e. pages) and spread the build process over time (i.e. creation times), you easily overcome the &lt;em&gt;static build walls&lt;/em&gt; present in traditional static site builders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Zone On-demand Static Regeneration
&lt;/h2&gt;

&lt;p&gt;While OSR has come immediately to my mind when I first learned about ISR, there was still one technical challenge that I was not able to overcome easily.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://www.blogody.com/landing"&gt;Blogody&lt;/a&gt;, the new SaaS blogging platform I am currently creating, I need a multi-zone set-up, also known as a multi-host or multi-tenant architecture. Users of this platform will receive a dedicated sub-domain for every blog they are creating.&lt;/p&gt;

&lt;p&gt;For example, one user may have a blog on &lt;code&gt;https://eager-einstein.blogody.com&lt;/code&gt;, another user on &lt;code&gt;https://vibrant-williams.blogody.com&lt;/code&gt;. Thus, blog pages are organized on different subdomains. As user's can create new blogs all the time, those subdomains are not known up-front.&lt;/p&gt;

&lt;p&gt;The problem is that NextJS static site generation functions do not capture the subdomains, or host information. While you can use OSR techniques to regenerate sites, I couldn't find a way to fetch data based on the varying subdomains. Of course, you could make a new deployment for every new subdomain created in the back-end, but this would let the number of deployments explode: not a scalable solution.&lt;/p&gt;

&lt;p&gt;Luckily, NextJS made &lt;a href="https://nextjs.org/blog/next-10-2#header-cookie-and-query-matching-for-rewrites-and-redirects"&gt;rewrites more flexible in the latest 10.2 release&lt;/a&gt;. I didn't notice the power of these additions until &lt;a href="https://twitter.com/acorcutt"&gt;Anthony Corcutt&lt;/a&gt; demonstrated in an &lt;a href="https://github.com/acorcutt/next-multi-host"&gt;open-source example&lt;/a&gt;, how the host information can be mapped into paths with rewrites.&lt;/p&gt;

&lt;p&gt;Once your static build functions can grab the subdomain info, combining it with OSR is easy.&lt;/p&gt;

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

&lt;p&gt;By integrating the latest hybrid approaches of building modern web sites into an event driven content workflow, and thanks to the more flexible rewrite capabilities of NextJS, it is now possible to deliver on-demand static regeneration on multi-zone sites.&lt;/p&gt;

&lt;p&gt;The benefits are striking: Always up-to-date, flaring fast static sites that can be served globally from the CDN edge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.blogody.com/landing"&gt;Interested to learn more about Blogody? Just sign-up to get notified.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;p&gt;If you want to learn more about this topic, here are some good starting points.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.smashingmagazine.com/2021/04/incremental-static-regeneration-nextjs/"&gt;A Complete Guide To Incremental Static Regeneration (ISR) With Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/66995817/next-js-static-regeneration-on-demand"&gt;Stackoverflow: Next.js Static Regeneration on demand&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://css-tricks.com/distributed-persistent-rendering-dpr/"&gt;CSS Tricks: Distributed Persistent Rendering&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This post was originally published at Jamify.org on May 16, 2021.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>react</category>
      <category>saas</category>
    </item>
    <item>
      <title>Building a Rich-Text Editor for Modern Publishers</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Fri, 30 Apr 2021 21:13:47 +0000</pubDate>
      <link>https://dev.to/styxlab/building-a-rich-text-editor-for-modern-publishers-3fmb</link>
      <guid>https://dev.to/styxlab/building-a-rich-text-editor-for-modern-publishers-3fmb</guid>
      <description>&lt;p&gt;An inside look into the making of a flexible Rich-Text editor that will be shipped as an integral part of Blogody - the new blogging platform I am building. It's been a bumpy path to choose the editor technology best suited for modern publishers. Sneak preview into the final result...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PF1oO8Qz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/594d8244f591a013177bb68ce61b3b5b/building-richtext.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PF1oO8Qz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/594d8244f591a013177bb68ce61b3b5b/building-richtext.png" alt="Building a Rich-Text Editor for Modern Publishers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are like most people in this digital age, you use text editors every day and more likely every other minute. Just a quick message to your friend, an email to your colleague or a document for your boss: most electronic text is written with an editor.&lt;/p&gt;

&lt;p&gt;The ubiquity of editors may lead you to believe that you are dealing with fairly simple technology, but that's far from reality. The illusion of a smooth, natural feeling editor experience can only be created by an extremely advanced piece of technology that takes all possible user interactions into account while remaining extremely fast and amazingly responsive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1RhC1wK8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1496171367470-9ed9a91ea931%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fHJlc3BvbnNpdmV8ZW58MHx8fHwxNjE5ODIwMjQ3%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1RhC1wK8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1496171367470-9ed9a91ea931%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fHJlc3BvbnNpdmV8ZW58MHx8fHwxNjE5ODIwMjQ3%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" alt="Building a Rich-Text Editor for Modern Publishers"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@domenicoloia?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Domenico Loia&lt;/a&gt; / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is even more true for web editors, which need to deal with different browser technologies, alleviate their quirks, compensate slow network speeds and silently master all state and user interaction intricacies.&lt;/p&gt;

&lt;p&gt;Modern writers and publishers demand an editor that produces clean, semantically meaningful documents, that let them focus on writing and article composition. The best editors of this trade are the ones that are not overly rigid but still use some constraints that don't feel constraining for that specific use case. These editors artfully bridge the gap between unambiguous and rigid Markdown editors and full-fledged WYSIWYG editors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rich-text editors for the web
&lt;/h2&gt;

&lt;p&gt;Picking the right editor technology for the web is not easy. As the browser understands JavaScript natively, the editor should be written in that language or in a framework like React that uses JavaScript under the hood. While there are a number of open-source editor frameworks available, it still surprises me how much work you need to put into building a great an meaningful editor in 2021.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://www.https://www.blogody.com"&gt;Blogody&lt;/a&gt;, I required primitive building blocks to be included by the framework &lt;em&gt;and&lt;/em&gt; the ability to customize the editor to match exactly the main target group: modern content publishers and writers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--igqciQGN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1554227231-54aa5db01c51%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDI3fHxsZWdvJTIwd2hpdGV8ZW58MHx8fHwxNjE5Nzk4MzAz%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--igqciQGN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1554227231-54aa5db01c51%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDI3fHxsZWdvJTIwd2hpdGV8ZW58MHx8fHwxNjE5Nzk4MzAz%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" alt="Building a Rich-Text Editor for Modern Publishers"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@celle_a_belle?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Marcella Marcella&lt;/a&gt; / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I started by looking at the &lt;a href="https://github.com/TryGhost/Admin/tree/main/lib/koenig-editor"&gt;König editor&lt;/a&gt; from Ghost because it is available open-source. It uses &lt;a href="https://github.com/bustle/mobiledoc-kit"&gt;Mobiledoc&lt;/a&gt; in connection with &lt;a href="https://emberjs.com"&gt;EmberJS&lt;/a&gt;. There is also a React Mobiledoc variant that I intended to use, but the König editor turned out to be too tightly coupled to EmberJS and the Ghost's NodeJS Admin interface. I figured, that carving it out would require more work than starting anew. Starting from scratch also gives me more freedom to choose a better technology stack from the get-go.&lt;/p&gt;

&lt;p&gt;As &lt;a href="https://www.blogody.com"&gt;Blogody&lt;/a&gt; is built with React, a more sensible choice would be to look for a native React editor framework. That's how I got to know &lt;a href="https://github.com/ianstormtaylor/slate"&gt;Slate&lt;/a&gt; which was recommended to me by one of the full-stack developers at &lt;a href="https://www.republik.ch/"&gt;Republik&lt;/a&gt;, a renown Swiss online newspaper. Slate looked very promising, with clear principles, a vibrant open-source community and outstanding React integration. Inspired by the success stories from the Republik team, I spent more than one month building a new editor based on Slate.&lt;/p&gt;

&lt;p&gt;While I still think Slate has the best React interface, it turned out to be lacking in some unexpected ways: when you need to construct sensible boundaries for primitive elements, you don't get much tooling. For example, if you want to ensure a picture element is always followed by a paragraph, you have do define that yourself in a so called &lt;a href="https://docs.slatejs.org/concepts/11-normalizing"&gt;normalizer&lt;/a&gt; function. While this is possible, you'll soon find out that you need to develop a content schema from scratch, not something easily done over a weekend. What turned out to be even more surprising for me: pasting long documents would freeze the UI for more than seven seconds on a fast desktop computer. That's when I literally lost patience with Slate.&lt;/p&gt;

&lt;p&gt;If you ever need to pick an editor framework for one of your own projects, the following advice would have saved me a lot of time:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before you decide for a technology, make some simple end-user tests with demanding test data. For an editor, copy &amp;amp; paste large amounts of text, write text with high speeds, etc. and see if it the technology can still impress you when stressed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Entering ProseMirror
&lt;/h2&gt;

&lt;p&gt;With these findings, I found myself back on square zero. Is a slow editor the price for getting seamless React integration? Are there alternatives out there which I didn't come across yet?&lt;/p&gt;

&lt;p&gt;While looking further around, I stumbled upon an article about &lt;a href="https://prosemirror.net"&gt;ProseMirror&lt;/a&gt;, another highly acclaimed editor framework used in the digital news room of the &lt;a href="https://open.nytimes.com/building-a-text-editor-for-a-digital-first-newsroom-f1cb8367fc21"&gt;New Your Times&lt;/a&gt;. Open-sourced with a more traditional yet helpful forum community, thoroughly maintained by the creator and master mind. The project is supported by some well-known companies, so it captured my attention. First end-user tests showed stunning performance characteristics. The above mentioned example that took over seven seconds in Slate would complete in 150 milliseconds in ProseMirror - which immediately electrified me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b2vN9BwE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/04/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b2vN9BwE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/04/image.png" alt="Building a Rich-Text Editor for Modern Publishers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There was just one problem with ProseMirror. How could I possibly integrate ProseMirror into the Blogody React app? All ProseMirror-React boilerplate implementations I found looked really complicated and I hardly understood what they were doing: Communicating state between React and ProseMirror neither seemed to be straight forward nor easy.&lt;/p&gt;

&lt;p&gt;With some help from people of the the ProseMirror forum community I started with trying to make a simple React bridge. Firsts steps were really difficult and I was constantly thinking of dropping out from that experiment. How much time would I need to get even simple things working, like integrating a simple paragraph React component?&lt;/p&gt;

&lt;p&gt;While I learned a lot about all the ProseMirror lego pieces and the well designed interfaces that you can hook into, I had almost abandoned ProseMirror when I was suddenly struck by a sparkling idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let ProseMirror handle primitive elements like paragraphs, figures, etc. with its native JavaScript framework and use React only for interactive overlay elements, such as hover-bars or drop-down menus.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With this clear conceptional distinction, I was able to make progress much faster and secure ProseMirror's nice performance characteristics while being able to integrate the editor into the main React app.&lt;/p&gt;

&lt;p&gt;Looking back after another month, I am convinced that this was finally the right choice. ProseMirror is extremely efficient in handling the basic editor elements, it is easily extended with a plugin approach and ensures document integrity with a flexible schema design system. Furthermore it allows me to amend it with complex React overlay components through my custom built React bridge.&lt;/p&gt;

&lt;p&gt;Itching to see some demo results? Here we go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hover toolbar
&lt;/h2&gt;

&lt;p&gt;I have always been a fan of contextual toolbars that offer exactly the editing choices that make sense at this very moment. Just select some text and an inline formatting toolbar opens:&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hvc7oIlh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/1e5e2cda71f5c83c9db8579790a30a0b/Peek-2021-04-30-17-08.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hvc7oIlh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/1e5e2cda71f5c83c9db8579790a30a0b/Peek-2021-04-30-17-08.gif" alt="Building a Rich-Text Editor for Modern Publishers"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Side menu
&lt;/h2&gt;

&lt;p&gt;A side menu lets you insert block level content, such as horizontal lines or images. A plus button will show up on every new line as you can see below:&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QRNJwakz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/88bea5580b7941e0c68376f4020923c4/Peek-2021-04-30-17-32.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QRNJwakz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/88bea5580b7941e0c68376f4020923c4/Peek-2021-04-30-17-32.gif" alt="Building a Rich-Text Editor for Modern Publishers"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Keyboard Shortcuts
&lt;/h2&gt;

&lt;p&gt;One of the early design goals for the Blogody editor has been to make the keyboard a first class input method. While every action can be invoked with your mouse, the keyboard is an equally good alternative.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;b&lt;/code&gt; toggles the selection &lt;strong&gt;bold&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;i&lt;/code&gt; toggles the selection &lt;em&gt;italic.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl&lt;/code&gt; + backtick toggles the selection &lt;code&gt;inline code&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl&lt;/code&gt; &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;1...3&lt;/code&gt; changes the text-block to heading at a level.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl&lt;/code&gt; &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;8&lt;/code&gt; wraps the selection in an ordered list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl&lt;/code&gt; &lt;code&gt;Shift&lt;/code&gt; + &lt;code&gt;9&lt;/code&gt; wraps the selection in a bullet list.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Input Rules
&lt;/h2&gt;

&lt;p&gt;You can also use Markdown inspired input rules. The side-menu can always be opened by pressing &lt;code&gt;/&lt;/code&gt; and you can move the current selection with your arrow keys, confirm with &lt;code&gt;Enter&lt;/code&gt; or leave with &lt;code&gt;Esc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The following screen-cast demonstrates how easy it is to structure your text without leaving the keyboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B0TrNlAr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/5fa5bbabc5522af401c2870a1ff43e1f/Peek-2021-04-30-22-10.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B0TrNlAr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/5fa5bbabc5522af401c2870a1ff43e1f/Peek-2021-04-30-22-10.gif" alt="Building a Rich-Text Editor for Modern Publishers"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;#&lt;/code&gt; followed by a space, to start the line as a heading.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;##&lt;/code&gt; followed by a space, to start the line a sub-heading.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;###&lt;/code&gt; followed by a space, to make the line a sub-sub-heading.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&lt;/code&gt; or &lt;code&gt;*&lt;/code&gt; followed by a space, to create a bullet list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1.&lt;/code&gt; followed by a space, to create an ordered list.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;gt;&lt;/code&gt; followed by a space, to create a quote.&lt;/li&gt;
&lt;li&gt;3 backticks: to create a code block.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unsplash Widget&lt;/p&gt;

&lt;h2&gt;
  
  
  Unsplash Widget
&lt;/h2&gt;

&lt;p&gt;More complex features are also possible with the ProseMirror React bridge. I have partnered with &lt;a href="https://unsplash.com"&gt;Unsplash&lt;/a&gt; to be able to integrate a royalty-free image picker into the Blogody editor:&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vqBoyUuI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/2c1df439e4938f3a7abbe985bcf9d83b/Peek-2021-04-30-17-37.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vqBoyUuI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.jamify.org/static/2c1df439e4938f3a7abbe985bcf9d83b/Peek-2021-04-30-17-37.gif" alt="Building a Rich-Text Editor for Modern Publishers"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;Blogody's richt-text editor is ideally suited for the modern web and will help writers and publishers focus on producing stunning content for their audience. Powered by ProseMirror under the hood, the editor is extremely stable and fast. With the newly developed React bridge for Blogody, even complex widgets like the Unsplash image picker are easily integrated and you can expect more eye-catching features coming in future &lt;a href="https://www.blogody.com/news"&gt;Blogody releases&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.blogody.com/landing"&gt;Do you want early access to Blogody, the brand new blogging platform that I am creating? Just sign-up on the new Blogody landing page and be among the first to get notified!&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;This post was originally published at Jamify.org on April 30, 2021.&lt;/p&gt;

</description>
      <category>richttexteditor</category>
      <category>prosemirror</category>
      <category>nextjs</category>
      <category>react</category>
    </item>
    <item>
      <title>Blogody - Tune into the melody of a new blogging platform</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Sat, 13 Mar 2021 17:07:20 +0000</pubDate>
      <link>https://dev.to/styxlab/blogody-tune-into-the-melody-of-a-new-blogging-platform-c0l</link>
      <guid>https://dev.to/styxlab/blogody-tune-into-the-melody-of-a-new-blogging-platform-c0l</guid>
      <description>&lt;p&gt;It's official now. The new blogging platform that I am creating is called Blogody. Learn how I came up with that name and what might help you in creating great names for your own product ideas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--szwc3a30--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/1e0a99c59a75619ba9e235f31f3eecbe/blogody.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--szwc3a30--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/1e0a99c59a75619ba9e235f31f3eecbe/blogody.png" alt="Blogody - Tune into the melody of a new blogging platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I announced creating a new blogging platform early this year, the name for the new platform was still up in the air. Coming up with a sticky name that gives you an idea about the product's intend is not that easy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://landing.blogody.com"&gt;Want to get early access to Blogody? Just sign-up on the new Blogody landing page and be the first to get notified.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can pay thousands of dollars for a professional marketing firm just to come up with a single product name. Is it worth that money? Probably yes. Do you need to pay that much? Probably not.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to find the best product name?
&lt;/h3&gt;

&lt;p&gt;If you ever searched for a good name for a product idea or website, you may have experienced that feeling of unlimited possibilities that make it so hard to pick exactly the right one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XaxmJ_Sn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1535054820380-92c41678b087%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDI3fHxvfGVufDB8fHx8MTYxNTY0MzEwOQ%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XaxmJ_Sn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1535054820380-92c41678b087%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDI3fHxvfGVufDB8fHx8MTYxNTY0MzEwOQ%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" alt="Blogody - Tune into the melody of a new blogging platform"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@kristianstrand?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Kristian Strand&lt;/a&gt; / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can be a limiting thought, and that's why I started with a little mind hack:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;There is no single best name.&lt;/strong&gt; You don't pick the best, you just pick the one that &lt;strong&gt;best fits&lt;/strong&gt; your criteria.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While I do think _ &lt;strong&gt;Blogody&lt;/strong&gt; _ is just the perfect name after all, I also know there are hundreds of other names that would fit equally good. With this golden rule, I deliberately shift my focus from &lt;em&gt;the only one&lt;/em&gt; to the one that &lt;em&gt;best fits my search criteria.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A trustworthy top level domain name
&lt;/h3&gt;

&lt;p&gt;As the blogging platform needs a dedicated domain name, I want the name to be available on one of the most credible top level domains. You can make your own research about domain credibility, but to cut things short, the number one is still &lt;em&gt;.com&lt;/em&gt;. It's also the one most people would search for, if they had forgotten the full domain name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b3aDwj-A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/photo-1534345297779-87af8f3a4455-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b3aDwj-A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/photo-1534345297779-87af8f3a4455-1.jpg" alt="Blogody - Tune into the melody of a new blogging platform"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@jeluar?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;jesus luna71&lt;/a&gt; / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the explosion of websites I know it's hard to find a free &lt;em&gt;.com&lt;/em&gt; address as so many combinations are already taken. On the other hand, it also helps me eliminating possible choices, which leads to my second rule of thumb:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The name must be available for the .com top level domain.&lt;/strong&gt; This likely means the name must be an artificial name, because common dictionary words are usually taken already.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, making rules is fun, but how does that bring me closer to a name? I need some name ideas first in order to be able to test if they are available on the &lt;em&gt;.com&lt;/em&gt; domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Brainstorm for name snippet
&lt;/h3&gt;

&lt;p&gt;As the platform is about creating blogs, it would be cool if the product name includes "blog" in it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WdCw47nA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/photo-1589322421213-b8dfe01d4873-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WdCw47nA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/photo-1589322421213-b8dfe01d4873-1.jpg" alt="Blogody - Tune into the melody of a new blogging platform"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@dasdawidt?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;David Maier&lt;/a&gt; / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the point where I write down a word list with words related to "blog":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;blog &lt;/li&gt;
&lt;li&gt;write&lt;/li&gt;
&lt;li&gt;publish&lt;/li&gt;
&lt;li&gt;text&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A keyword search is also a good tactic at this point. As I know this will be only one part of the final word, I want to go with the most obvious word that is also the shortest possible. Like for &lt;em&gt;.com&lt;/em&gt; before, &lt;em&gt;blog&lt;/em&gt; sticks out both in terms of being to the point and in terms of shortness. This rule can be summarized as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Find a short word that characterizes your product.&lt;/strong&gt; Use it as a first step in composing the final name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Fixing the maximum character length
&lt;/h3&gt;

&lt;p&gt;I would always prefer a shorter name over a longer one, at least if the short one is also easy to memorize. Looking at big tech company names, such as Google, Amazon or Twitter a name with a maximum of 7 characters would be ideal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z38zLNZd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/photo-1589666776877-01bb997251ec-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z38zLNZd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/photo-1589666776877-01bb997251ec-1.jpg" alt="Blogody - Tune into the melody of a new blogging platform"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@polarmermaid?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Anne Nygård&lt;/a&gt; / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have seen great long names too, but let's be a bit ambitious here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The final name should be 7 characters or less. No one likes to type long names.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With 4 characters already taken, we are only left with &lt;em&gt;3 remaining characters&lt;/em&gt;. You can do the math, with 26 possible charterers of the English alphabet, you have limited your possibilities to 26 to the power of 3 = 17.576 combinations. Not millions, but still quite a lot of possibilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choose sensible character constraints
&lt;/h3&gt;

&lt;p&gt;Among the 3 possible characters, I want at least one vowel, preferably one that is already in "blog", which would be an "o". Why? because vowel repetition usually leads to nice sounding words.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jl99OlA2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/photo-1581431886303-0ec49ef43b4f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jl99OlA2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/photo-1581431886303-0ec49ef43b4f.jpg" alt="Blogody - Tune into the melody of a new blogging platform"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@kellysikkema?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Kelly Sikkema&lt;/a&gt; / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This choice reduces the number of possibilities to 678.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Narrow your possibilities with some meaningful character constraints.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While you can now write a computer program that generates all 678 words and then limit the ones for which there is a ".com" domain available, I started to make a new word list with ones that came to my mind immediately&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;blogost&lt;/li&gt;
&lt;li&gt;blogrod&lt;/li&gt;
&lt;li&gt;blogido&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I usually type those directly in a domain search system, to see if they are available. This last step can be a bit frustrating, because most choices were taken already... until I finally got a satisfactory hit with&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;blogody.com&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Google Search on Blogody
&lt;/h3&gt;

&lt;p&gt;The name is great, but what other websites exist with the same name? I do not want other high ranking blogging platforms to collide with that name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6sh25sZb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6sh25sZb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/image-2.png" alt="Blogody - Tune into the melody of a new blogging platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It turns out that when you type "Blogody" into a Google search, there is not one with an exact match:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GO4ZSQva--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/image-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GO4ZSQva--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2021/03/image-3.png" alt="Blogody - Tune into the melody of a new blogging platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is great, because it is not occupied with similar content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Falling in love with a name
&lt;/h3&gt;

&lt;p&gt;While the described strategy of choosing a name seems quite technical, there is still a lot of creativity involved when testing the different variants. The system mostly helps in narrowing your possible choices but still leaves you with a large amount of names to choose from.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2UxdAaTP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1520531598735-f4a90a7ccc4f%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDI4fHx3b3JkJTIwbG92ZXxlbnwwfHx8fDE2MTU2NDE3MTc%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2UxdAaTP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1520531598735-f4a90a7ccc4f%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDI4fHx3b3JkJTIwbG92ZXxlbnwwfHx8fDE2MTU2NDE3MTc%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" alt="Blogody - Tune into the melody of a new blogging platform"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@alexblock?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Alex Block&lt;/a&gt; / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, what makes _ &lt;strong&gt;Blogody&lt;/strong&gt; _ the best name of all the variants that I considered? First and foremost, &lt;em&gt;I like the sound of the the name&lt;/em&gt;. It rimes with &lt;em&gt;Melody&lt;/em&gt;, &lt;em&gt;Rhapsody&lt;/em&gt; and a lot of other melodic words.&lt;/p&gt;

&lt;p&gt;It is short, easy to pronounce and remember, gives hindsight to the product value and is available on the highest ranking top level domain: &lt;em&gt;Lovely!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Names are likely overrated
&lt;/h3&gt;

&lt;p&gt;After the initial excitement it's important to touch base again. After all, the best name does not make a good product. So, it's important to focus on the product again, such that it fills the great sounding name with a resonating product.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.blogody.com/landing"&gt;Interested to learn more about Blogody? Just sign-up to get notified.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;This post was originally published at jamify.org on March 13, 2021.&lt;/p&gt;

</description>
      <category>blogging</category>
      <category>webdev</category>
      <category>saas</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Creating a new blogging platform</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Sat, 09 Jan 2021 23:30:13 +0000</pubDate>
      <link>https://dev.to/styxlab/creating-a-new-blogging-platform-586b</link>
      <guid>https://dev.to/styxlab/creating-a-new-blogging-platform-586b</guid>
      <description>&lt;p&gt;I am going to create a new blogging platform in 2021! It will allow publishing articles with Jamstack benefits built in: namely extremely secure and blazing fast sites. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.blogody.com/landing"&gt;Want to get early access to Blogody? Just sign-up on the new Blogody landing page and be the first to get notified.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No code or development skills needed. For publishers who want to focus on writing and care about their content ownership.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2vlrRsGw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/df97868cdc7f53009927e5d265116b5b/e4875/photo-1545239351-ef35f43d514b.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2vlrRsGw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/df97868cdc7f53009927e5d265116b5b/e4875/photo-1545239351-ef35f43d514b.webp" alt="Creating a new blogging platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;About year ago, I got fascinated by the Jamstack approach of building blogs and websites. Just pick a headless content management system (CMS) of your liking, turn it into a static site and serve it globally from a content delivery network (CDN edge). &lt;strong&gt;Publishing content this way is more secure, extremely flexible and produces super fast sites with low maintenance costs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This approach inspired building the &lt;a href="https://github.com/styxlab/next-cms-ghost"&gt;Jamify static site generator&lt;/a&gt; based on &lt;a href="https://nextjs.org/"&gt;NextJS&lt;/a&gt;, which rapidly transforms your content from a headless &lt;a href="https://ghost.org/"&gt;Ghost CMS&lt;/a&gt; into a flaring fast site.&lt;/p&gt;

&lt;p&gt;This site can be globally served from a CDN provider such as &lt;a href="https://vercel.com"&gt;Vercel&lt;/a&gt; or &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;. &lt;strong&gt;I got really nice feedback from both contributors and users&lt;/strong&gt; , so I am truly excited to support and improve the open-source &lt;a href="https://github.com/styxlab"&gt;Jamify tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a web creator and developer, &lt;strong&gt;I always envision something better&lt;/strong&gt; and I realize that the Jamify tools appeal mostly to developers and tech-savvy people. That does not come as a surprise. In order to appreciate the benefits of the &lt;a href="https://jamstack.org/"&gt;Jamstack&lt;/a&gt;, &lt;strong&gt;you must bring an understanding of how the web works.&lt;/strong&gt; Furthermore, you must be comfortable with using git(hub), setting up developer tools, installing packages and compiling code. &lt;strong&gt;It got me thinking:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How can the Jamstack benefits for content publishing be made available to a wider audience?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After trying many different platforms, I am convinced that a &lt;strong&gt;new, independent blogging platform must be invented&lt;/strong&gt; in order to bring the Jamstack benefits to &lt;strong&gt;all article publishers.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Existing blogging platforms
&lt;/h2&gt;

&lt;p&gt;When it comes to blogging platforms, &lt;a href="https://wordpress.org/"&gt;WordPress&lt;/a&gt; is by far the most popular content management system holding 60% of the market share. This translates to a stunning &lt;strong&gt;33% share of all the websites online&lt;/strong&gt;. With popularity comes a lot of complexity most people don't need.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It may sound paradoxical, but the most popular system is most likely a system that does &lt;strong&gt;not&lt;/strong&gt; fit your needs the &lt;strong&gt;best way possible&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why? Because, a widely used system tends to grow in complexity and must try to find the least common denominator.&lt;/p&gt;

&lt;p&gt;Admittedly, I am not the first one to realize this opportunity and that's why you can find many other blogging systems, each with it's own benefits and drawbacks.&lt;/p&gt;

&lt;p&gt;However, as the &lt;strong&gt;Jamstack is a relatively new approach&lt;/strong&gt; and still mostly targeting developers, there &lt;strong&gt;is potential for a new blogging platform in 2021&lt;/strong&gt; that integrates those benefits and at the same time hides the complexities from the end users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benefits of a new platform
&lt;/h2&gt;

&lt;p&gt;With so many choices available, establishing a new blogging system is completely naïve. Yet, &lt;strong&gt;I will just do it for the &lt;em&gt;fun of it!&lt;/em&gt;&lt;/strong&gt; So, I am going to share my vision with you here. The new blogging platform should &lt;strong&gt;stand out&lt;/strong&gt; in the following four areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;CDN performance&lt;/strong&gt; : Producing the fastest sites on the planet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ease of use&lt;/strong&gt; : Intuitive design focused on writing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Own your articles&lt;/strong&gt; : Don't pay with your content, pay a small platform fee instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Syndication&lt;/strong&gt; : Made dead simple.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In other words, the new system should produce optimized, blazing fast sites similar to &lt;a href="https://github.com/styxlab/next-cms-ghost"&gt;next-cms-ghost&lt;/a&gt;, but not require any developer skills or tools. The system should be as easy to use as &lt;a href="https://medium.com/"&gt;Medium&lt;/a&gt;, but without giving away your publication rights or other meta data to third parties.&lt;/p&gt;

&lt;p&gt;Syndication will not be part of the first release, but will be an important long term goal: as &lt;strong&gt;syndication is most crucial for making your content discoverable&lt;/strong&gt; on the web, it should be better supported here than elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimalistic system
&lt;/h2&gt;

&lt;p&gt;The most important and difficult part is to &lt;strong&gt;start out really small, yet with a useful system that can be easily extended&lt;/strong&gt;. I already have a number of useful React components scattered around various projects that I can easily tap into, but I do know the complexities involved.&lt;/p&gt;

&lt;p&gt;For a project like this, it's important not to get intimidated by existing systems and the set of features they now offer. I truly believe that the &lt;strong&gt;tools for building a SaaS application in 2021 are so much more effective&lt;/strong&gt; than the legacy tools used in Wordpess and alike (if you ever tried to install Wordpress on your own computer, this may resonate with you). Which brings me to the tech stack.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;core technologies&lt;/strong&gt; the blogging platform will be based upon are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NextJS&lt;/strong&gt; for the platform (an exceptional React framework)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt; for styling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slate&lt;/strong&gt; for the editor component&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt; for the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The platform will be hosted on Vercel as it supports Next.js perfectly. While the platform itself will not be open-source, I expect to open-source key components and make them available on Github.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;To cover operating costs and sustain future development, I will ask for a small platform fee. The &lt;strong&gt;starter plan&lt;/strong&gt; will be offered for &lt;strong&gt;$3/month&lt;/strong&gt; and a &lt;strong&gt;pro plan&lt;/strong&gt; with more capabilities will cost &lt;strong&gt;$5/month&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once available, early adopters will be promoted to the pro plan at no additional costs. Thus, there are &lt;strong&gt;two incentives for being among the first users:&lt;/strong&gt; pro capabilities at a low, all time price of $3/month as well as some &lt;strong&gt;additional influence on feature prioritizations&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Release date...
&lt;/h2&gt;

&lt;p&gt;... is not yet fixed, but I expect first light in &lt;strong&gt;Q4 2021&lt;/strong&gt;. Given that I will start the platform as a side project, it is an &lt;strong&gt;ambitious but realistic goal.&lt;/strong&gt; By the way, the name is already fixed but I will not reveal it until later this year!&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;If you want to discuss the new system with me or just be among the first people to be notified, &lt;strong&gt;drop me a line on twitter: &lt;a href="https://twitter.com/jamifyjs"&gt;@jamifyjs&lt;/a&gt;&lt;/strong&gt;. I am soooooo excited...&lt;/p&gt;




&lt;p&gt;This post was originally published at &lt;a href="https://www.jamify.org/2021/01/09/building-a-new-blogging-platform/"&gt;jamify.org&lt;/a&gt; on January 9, 2021.&lt;/p&gt;

</description>
      <category>blogging</category>
      <category>platform</category>
      <category>wordpress</category>
      <category>blogger</category>
    </item>
    <item>
      <title>Gatsby or Next?</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Tue, 15 Dec 2020 00:04:49 +0000</pubDate>
      <link>https://dev.to/styxlab/gatsby-or-next-21k</link>
      <guid>https://dev.to/styxlab/gatsby-or-next-21k</guid>
      <description>&lt;p&gt;This year has seen overwhelming advances in static site builders which makes choosing the right system harder. Most comparisons on the web are outdated. That's why we take a fresh look at Gatsby versus NextJS. Take advantage of the lessons we learned in 2020 and make your own choice!&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%2Fwww.jamify.org%2Fstatic%2Fbd50138a96e5009498273febb5385eb6%2Fe4875%2FWhich-one-to-choose-.webp" 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%2Fwww.jamify.org%2Fstatic%2Fbd50138a96e5009498273febb5385eb6%2Fe4875%2FWhich-one-to-choose-.webp" alt="Gatsby or Next?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first &lt;a href="https://github.com/styxlab/gatsby-starter-try-ghost" rel="noopener noreferrer"&gt;Jamify Blog starter&lt;/a&gt; was built on Gatsby. At the beginning of 2020, this seemed like a safe bet for a static site builder: A highly acclaimed React framework with a large ecosystem and vibrant open-source community. Looking back, this wasn't a bad choice: we still love the the Gatsby Jamify Blog system with it's plugins and certainly continue to support them. Read the &lt;a href="https://www.jamify.org/2020/05/19/getting-started-with-jamify/" rel="noopener noreferrer"&gt;Getting started with Jamify&lt;/a&gt; tutorial to learn more about Jamify.&lt;/p&gt;

&lt;p&gt;Many comparisons between &lt;a href="https://www.gatsbyjs.com/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt; and &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; at the time were also making clear recommendations: if you need a static site builder go with Gatsby, if you need on-demand server rendering and serverless functions go with Next.js. With this distinction, a blog would typically better built with Gatsby whereas an e-commerce site with a lot of product changes would better fit to Next.js. Easy!&lt;/p&gt;

&lt;p&gt;This simple decision making became more difficult nine months ago, when Next.js released &lt;a href="https://nextjs.org/blog/next-9-3" rel="noopener noreferrer"&gt;Version 9.3&lt;/a&gt; that introduced an hybrid approach. Hybrid means that you can choose between &lt;em&gt;server side rendering&lt;/em&gt; (SSR) and &lt;em&gt;static site generation&lt;/em&gt; (SSG) on a per page basis. Over night, Gatsby's SSG feature became available in Next.js and the &lt;em&gt;above distinction fell apart&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Suddenly, Next.js was able to do what Gatsby was doing, but at the same time providing many more possibilities with SSR and serverless. Would it be worth switching to Next.js for a blog site that mainly uses SSG?&lt;/p&gt;

&lt;h2&gt;
  
  
  The case for Gatsby
&lt;/h2&gt;

&lt;p&gt;In March 2020, when Next.js Version 9.3 was released, I did not pay too much attention to it. Of course, Next was now also capable of SSG, but Gatsby is certainly more experienced in its core SSG feature, I presumed.&lt;/p&gt;

&lt;p&gt;Above all, you do not choose a framework based on one feature alone. Gatsby's main promises seemed still intact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blazing fast sites out-of-the box&lt;/li&gt;
&lt;li&gt;Tools for image optimization&lt;/li&gt;
&lt;li&gt;A plugin API that enables component shadowing&lt;/li&gt;
&lt;li&gt;An integrated GraphQL layer for structured data fetching&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%2Fcms.jamify.org%2Fcontent%2Fimages%2F2020%2F12%2Fimage-2.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%2Fcms.jamify.org%2Fcontent%2Fimages%2F2020%2F12%2Fimage-2.png" alt="Gatsby or Next?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adding to these key Gatsby features are an integrated cache that can be used to make developer life easier and many third-party plugins to choose from that already solve a lot of common use cases.&lt;/p&gt;

&lt;p&gt;At the time, Next.js could not compete in any of these areas. Thus, I was holding strongly to Gatsby. Of course, there were some annoyances with the GraphQL layer such as foreign-key linking issues popping up more often than expected. Also, component shadowing is a concept our users had difficulties grasping. But hey, you don't expect a perfect world. At least not as a developer!&lt;/p&gt;

&lt;h2&gt;
  
  
  Gatsby loosing ground
&lt;/h2&gt;

&lt;p&gt;One of the biggest pain points with Gatsby has always been build times. The reasons for it is also one of its acclaimed features: &lt;em&gt;image optimization&lt;/em&gt;. As Gatsby is doing these optimizations during SSG, every image you add to your site will increase build times.&lt;/p&gt;

&lt;p&gt;For a blog with many images, these optimizations are absolutely essential for a fast loading site, but it never seemed right to do this during SSG. Image optimizations should be completely decoupled from site generations as you could do this as soon as you add a new image to your content management system, typically way ahead of building your site.&lt;/p&gt;

&lt;p&gt;Gatsby is trying to cure these issues with two medicines: (1) utilizing a cache and (2) with &lt;a href="https://www.jamify.org/2020/06/13/incremental-builds-with-jamify/" rel="noopener noreferrer"&gt;incremental builds&lt;/a&gt;. The first medicine only works for sub-sequent builds which is a huge drawback and the second has two other downsides: it only works when deploying to Gatsby Cloud and – unfortunately –  it turned out to be notoriously unstable.&lt;/p&gt;

&lt;p&gt;You may argue that as image optimizations should be better done elsewhere, therefore it is not a Gatsby issue. This may be true, but wasn't Gatsby promising to make developer life easier with some awesome image optimization plugins?&lt;/p&gt;

&lt;h3&gt;
  
  
  When faith falls apart
&lt;/h3&gt;

&lt;p&gt;While the described pain points could be solved with external solutions, a much more devastating &lt;a href="https://github.com/gatsbyjs/gatsby/issues/24332" rel="noopener noreferrer"&gt;Gatsby performance issue&lt;/a&gt; popped up in &lt;em&gt;May 2020&lt;/em&gt; that Gatsby wasn't able to solve _ &lt;strong&gt;until today&lt;/strong&gt; &lt;em&gt;. With Google changing its page speed rating system in _Lighthouse version 6.0&lt;/em&gt;, speed scores plunged from formerly given 100 points to mediocre 50 for many sites using images.&lt;/p&gt;

&lt;p&gt;This problem erodes Gatsby's core promise which is still advertised as of today: &lt;strong&gt;Create blazing fast websites!&lt;/strong&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%2Fcms.jamify.org%2Fcontent%2Fimages%2F2020%2F12%2Fimage.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%2Fcms.jamify.org%2Fcontent%2Fimages%2F2020%2F12%2Fimage.png" alt="Gatsby or Next?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nothing can hurt you more than not delivering to your &lt;strong&gt;core value proposition&lt;/strong&gt; , but the real disaster for Gatsby is its &lt;strong&gt;inability to restore out-of-the box fast sites&lt;/strong&gt; after more than six months.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sadly, the reason for this is not a lack of willingness, it points towards fundamental design issues of the framework that are hard to rectify. You can read through the issue yourself to get a feeling about the depth of the problem. It is a combination of insufficient bundle size optimizations, deficiencies of the gatsby-image plugin and a conceptional weakness of trying to do everything with SSG.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next 10 to the rescue
&lt;/h2&gt;

&lt;p&gt;With Gatsby struggling to deliver its core promises and seemingly busy to commercialize its product generate cash for its investors, I was starting to take a closer look at Next.js.&lt;/p&gt;

&lt;p&gt;To my surprise, Next was producing smaller bundle sizes out-of-the box in all of my SSG test cases. Unfortunately, images were not addressed at all early October, however, some rumors were spread that something great is coming out with Next 10. What could it be?&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%2Fcms.jamify.org%2Fcontent%2Fimages%2F2020%2F12%2Fimage-1.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%2Fcms.jamify.org%2Fcontent%2Fimages%2F2020%2F12%2Fimage-1.png" alt="Gatsby or Next?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I attended the &lt;a href="https://nextjs.org/conf/stage/n" rel="noopener noreferrer"&gt;Next Conference&lt;/a&gt; on October 27th 2020 and the timing for a brand new  &lt;a href="https://nextjs.org/blog/next-10#built-in-image-component-and-automatic-image-optimization" rel="noopener noreferrer"&gt;built in image component with automatic image optimization&lt;/a&gt; couldn't be better. This combination of a React component with a serverless function for image optimization showcases the conceptional advantages of the hybrid approach.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Rather than quenching everything into SSG, make solutions with the tool that best fits your use case!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  I am hard to be convinced
&lt;/h3&gt;

&lt;p&gt;While excited about the new possibilities with Next, I was still not fully convinced to start a new version of the Jamify Blog starter with Next.js.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What am I going to do with all the nice plugins that are delivered with the starter?&lt;/li&gt;
&lt;li&gt;What about the GraphQL tools that come for free with Gatsby, will this be hard with Next,js?&lt;/li&gt;
&lt;li&gt;What about component shadowing? Will a Next version be easily extendible?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am glad that the spark of the Next conference prevailed the nagging questions above. Sometimes, it's better to simply try things out and conclude after.&lt;/p&gt;

&lt;p&gt;In this spirit, I initiated &lt;a href="https://github.com/styxlab/next-cms-ghost" rel="noopener noreferrer"&gt;&lt;strong&gt;next-cms-ghost&lt;/strong&gt;&lt;/a&gt; with a clear goal: A Next.js variant of the Jamify Blog starter that includes all features of the Gatsby version. So users can choose what ever they like best.&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%2Frepository-images.githubusercontent.com%2F312013805%2Fd8a6bc80-3486-11eb-8d64-c87af1a593fc" 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%2Frepository-images.githubusercontent.com%2F312013805%2Fd8a6bc80-3486-11eb-8d64-c87af1a593fc" alt="Gatsby or Next?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This goal was successfully reached on &lt;em&gt;December 5th, 2020&lt;/em&gt;, in less than 4 weeks and with very pleasant results – not only with respect to Lighthouse v6 scores.&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%2Fwww.jamify.org%2Fstatic%2F0c5ac31c29bc351ee759bd33504acdd4%2Fjamify-lh-scores-light.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%2Fwww.jamify.org%2Fstatic%2F0c5ac31c29bc351ee759bd33504acdd4%2Fjamify-lh-scores-light.gif" alt="Lighthouse v6 scores"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Less is more
&lt;/h3&gt;

&lt;p&gt;First of all, the developer experience with Next.js is superb. It does a lot of the heavy lifting for you, but generally tries to stay out of your way as much as possible. At the same time it gives you great support for fundamental concepts such as TypeScript.&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%2Fcms.jamify.org%2Fcontent%2Fimages%2F2020%2F12%2Fimage-3.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%2Fcms.jamify.org%2Fcontent%2Fimages%2F2020%2F12%2Fimage-3.png" alt="Gatsby or Next?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To this end, it also doesn't trick you into something you actually don't need. A great example is the GraphQL layer that Gatsby has been really proud of. It is great if you need it, but you don't always do! The data layer of &lt;a href="https://github.com/styxlab/next-cms-ghost" rel="noopener noreferrer"&gt;&lt;strong&gt;next-cms-ghost&lt;/strong&gt;&lt;/a&gt; relies entirely on REST interfaces that are far less complex, easier to maintain and play much nicer with TypeScript.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use GraphQL only when over- and under-fetching is a real problem that you need to solve, but never presume your use case needs to be optimized in that way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While there is some discussion about a plugin API in Next, it is quite unclear whether this will ever materialize. Thus, I took a practical approach and integrated all functionality that are in separate plugins directly into the Next.js Jamify Starter and made sure that you can enable/disable each feature with configuration options.&lt;/p&gt;

&lt;p&gt;While I am generally more in favour of the plugin approach, there are some advantages of this integration: no need to install or uninstall packages. Everything can be switch on or off not only in the config but also with environment variables. No plugins also leads to lesser maintenance work as the need to sync dependencies between many packages quickly becomes a burden. Overall not a bad solution after all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;While I may sound overly critical about Gatsby, I want to stress that it is still one of the best static site generators out there and I am sure that some of the downsides described here, will be tackled in 2021.&lt;/p&gt;

&lt;p&gt;I hear from the core team that they are working on serverless and new image plugins. They now also support a file based routing system, obviously inspired by Next.js. Interestingly, they also do not actively advertise the GraphQL feature anymore.&lt;/p&gt;

&lt;p&gt;So, if you invested heavily in Gatsby, you may still want to stay with them. Nonetheless, my preference for Next.js is obvious.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;My forecast&lt;/em&gt; is that Gatsby will not be able to level up with Next.js in 2021, because they have fallen behind not only in features. Gatsby &lt;em&gt;has become too complex&lt;/em&gt; to make the fundamental changes it needs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All this reminds me of the transient nature of software frameworks in general. The following graph from the &lt;a href="https://2019.stateofjs.com/front-end-frameworks/" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt; survey on Backend framworks illustrates this beautifully.&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%2Fwww.jamify.org%2Fstatic%2F59ceac4ee083610630c7524a8f5ba2a2%2Ff2650%2Fimage-5.webp" 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%2Fwww.jamify.org%2Fstatic%2F59ceac4ee083610630c7524a8f5ba2a2%2Ff2650%2Fimage-5.webp" alt="Gatsby or Next?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It looks like every framework has it's time until it is superseded by something newer, better, fancier. Let's wait and see what the future brings and always remind yourself that...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;...frameworks come and go, but what seems to prevail is JavaScript!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With this closing remark, &lt;strong&gt;I wish you a happy New Year 2021!&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.blogody.com/landing" rel="noopener noreferrer"&gt;Do you want early access to Blogody, the brand new blogging platform that I am creating? Just sign-up on the new Blogody landing page and be among the first to get notified!&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;This post was originally published at &lt;a href="https://www.jamify.org/2020/12/15/gatsby-or-next/" rel="noopener noreferrer"&gt;jamify.org&lt;/a&gt; on December 15, 2020.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>gatsby</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Running a professional blog for free</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Wed, 15 Jul 2020 15:09:21 +0000</pubDate>
      <link>https://dev.to/styxlab/running-a-professional-blog-for-free-4goc</link>
      <guid>https://dev.to/styxlab/running-a-professional-blog-for-free-4goc</guid>
      <description>&lt;p&gt;Ever wanted to run a blog site with zero costs? This tutorial explains how to do this in minutes with Jamify! If you follow along with the instructions in this tutorial, you'll have your own zero-cost setup by the end of this article featuring professional class speed, availability and security.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z47Qsxs5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/4b7c9f9965fe24bca65b9daf7a09e270/photo-1443745029291-d5c27bc0b562.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z47Qsxs5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/4b7c9f9965fe24bca65b9daf7a09e270/photo-1443745029291-d5c27bc0b562.jpg" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you ever deployed a blog or website to the public internet, you know that running a live site usually incurs operational costs. For example, a managed blog site hosted on &lt;em&gt;Ghost.org&lt;/em&gt; starts at &lt;a href="https://ghost.org/pricing/"&gt;$29/month&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can considerably cut down such expenses by using a self-hosted solution, but a publicly reachable server is not free. A self-hosted solution typically costs around  &lt;a href="https://ghost.org/pricing/"&gt;$5/month&lt;/a&gt;. Even a relatively inexpensive solution that was described in the &lt;a href="https://www.jamify.org/2020/04/07/ghost-cms-on-hetzner-cloud"&gt;Ghost CMS on Hetzner Cloud&lt;/a&gt; tutorial here on &lt;a href="https://www.jamify.org"&gt;Jamify.org&lt;/a&gt; cost you at least &lt;a href="https://ghost.org/pricing/"&gt;$3/month&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As Jamify sites are static sites they can be deployed to a global CDN and do not require traditional servers. CDN deployments are extremely cost efficient, therefore you can benefit from the free tiers of &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt; or other providers and run your live site at &lt;strong&gt;no costs on a global CDN&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However, up until recently, you still needed at least a self-hosted Ghost CMS installation on a public server. Why? Because not all images were included in your Gatsby bundle, so they had to be served from your Ghost CMS! That's why you had to make sure your CMS is &lt;em&gt;publicly reachable and available 24/7,&lt;/em&gt; &lt;strong&gt;depleting all the cost benefits of the static site approach.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the new Jamify plugin &lt;a href="https://github.com/styxlab/gatsby-theme-try-ghost/tree/master/packages/gatsby-rehype-inline-images"&gt;&lt;code&gt;gatsby-rehype-inline-images&lt;/code&gt;&lt;/a&gt; you can now integrate &lt;strong&gt;all images&lt;/strong&gt; into your static site bundle, so you do not need the CMS for serving images anymore. &lt;strong&gt;This opens up the possibility to deploy your blog from localhost for free.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ghost CMS on localhost
&lt;/h2&gt;

&lt;p&gt;Besides costs, being able to run your headless Ghost CMS on &lt;em&gt;localhost&lt;/em&gt; has a couple of notable advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easier setup as all production concerns fall away.&lt;/li&gt;
&lt;li&gt;No need to worry about security (firewalls, proxies, ports, authentication, SSL certificates, etc.).&lt;/li&gt;
&lt;li&gt;You can build your Jamify website offline and achieve fast build times that are not limited by network bandwidth (unless your blog incorporates external images).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, a local CMS installation also has some limitations and cannot cover all use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authoring articles with teams is not possible (no public access).&lt;/li&gt;
&lt;li&gt;Member functions (e.g. newsletter subscription and distribution) cannot be used (no publicly available backend).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if you need a public Ghost CMS installation at some point in time, a &lt;em&gt;localhost&lt;/em&gt; installation is still the number one choice in a lot of testing scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local CMS install
&lt;/h2&gt;

&lt;p&gt;Let's start with installing a Ghost CMS on your local machine. The following instructions have been tested on a Linux system running on Fedora, but should work on other Linux flavours too, including MacOS.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are using Windows it is recommended to install the Windows Subsystem for Linux (WSL 2) and use Ubuntu 20.04 LTS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To install Ghost locally make sure you install  &lt;a href="https://nodejs.org/"&gt;Node.js&lt;/a&gt;, the package manager &lt;a href="https://yarnpkg.com/en/docs/install#alternatives-tab"&gt;yarn&lt;/a&gt; and the &lt;code&gt;ghost-cli&lt;/code&gt;. Even if Node.js is already installed, check that you have a recent version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node &lt;span class="nt"&gt;-v&lt;/span&gt;
v12.18.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node comes bundled with the package manager &lt;code&gt;npm&lt;/code&gt;. Make use of it right away and install &lt;code&gt;yarn&lt;/code&gt; and the &lt;code&gt;ghost-cli&lt;/code&gt; with it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;npm &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;yarn ghost-cli@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Ghost
&lt;/h3&gt;

&lt;p&gt;With the needed tools available, you can now create a new directory and install Ghost CMS in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;ghost-local
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;ghost-local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the previously installed &lt;code&gt;ghost-cli&lt;/code&gt; for performing the actual install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;ghost-local]&lt;span class="nv"&gt;$ &lt;/span&gt;ghost &lt;span class="nb"&gt;install local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It may take a minute to download and install all files. After a successful install, you can visit the CMS under &lt;a href="http://localhost:2368/ghost/"&gt;http://localhost:2368/ghost/&lt;/a&gt; and complete the setup process in three steps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h6F7EX-y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-cms-setup-step1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h6F7EX-y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-cms-setup-step1.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I25zTq67--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-cms-setup-step2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I25zTq67--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-cms-setup-step2.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BdHgo9xM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-cms-setup-step3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BdHgo9xM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-cms-setup-step3.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a local install, you can safely enter a bogus email address and skip the staff user invite as you won't be able to work in teams anyway. After completing the final step, you should be brought to the Ghost Admin dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create API keys
&lt;/h3&gt;

&lt;p&gt;The initial setup is now complete. You can make further customizations in the admin interface, but this is not required at this point in time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In other tutorials on Jamify.org you may read the recommendation to turn on headless mode. For a local installation this is not needed as the installation will never be available publicly, so you can skip this step.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to be able to connect to your Ghost instance with Jamify later, you need to generate a content API key. Go to &lt;em&gt;Integrations -&amp;gt; Add custom integration&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kzqPb1El--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kzqPb1El--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-8.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and click &lt;em&gt;Create&lt;/em&gt; in order to generate a new key:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DzCrnKyx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DzCrnKyx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-9.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting and Stopping
&lt;/h3&gt;

&lt;p&gt;The installation routine automatically starts the local Ghost server. You can stop it with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;ghost-local]&lt;span class="nv"&gt;$ &lt;/span&gt;ghost stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will also have to re-start your server after every reboot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;ghost-local]&lt;span class="nv"&gt;$ &lt;/span&gt;ghost start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to check whether or not Ghost is currently running you can use this handy command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ghost &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the current Ghost server running if you want to follow along with this tutorial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Importing Content
&lt;/h3&gt;

&lt;p&gt;If you are already running another Ghost instance, you may want to import your content to your local installation. The easiest way is to use the import/export functionality under the &lt;em&gt;Labs&lt;/em&gt; section.&lt;/p&gt;

&lt;p&gt;Unfortunately, images must be transferred manually. So, in addition to the above import/export for the textual content, copy all images in directory &lt;code&gt;content/images/&lt;/code&gt; from the source to the target Ghost instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local Jamify install
&lt;/h2&gt;

&lt;p&gt;With a local CMS install it also makes sense to generate your static site locally, in fact, you won't be able to build your site with a cloud provider because your &lt;em&gt;localhost&lt;/em&gt; CMS is unreachable for them. Let's download the &lt;a href="https://github.com/styxlab/gatsby-starter-try-ghost"&gt;Jamify starter&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/styxlab/gatsby-starter-try-ghost.git jamify-starter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and change into the work directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;jamify-starter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Keys
&lt;/h3&gt;

&lt;p&gt;The Jamify starter must be told to source in the CMS content from you Ghost CMS on &lt;em&gt;localhost.&lt;/em&gt; For that, create a new file called &lt;code&gt;.ghost.json&lt;/code&gt; in your work directory and copy the previously generated content API keys in it:&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;"development"&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;"apiUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:2368"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contentApiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2a087eea8fc3c9a3e7392625c0"&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;"production"&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;"apiUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:2368"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contentApiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2a087eea8fc3c9a3e7392625c0"&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;blockquote&gt;
&lt;p&gt;You must replace the &lt;code&gt;contentApiKey&lt;/code&gt; with your own!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Remove members plugin
&lt;/h3&gt;

&lt;p&gt;The Jamify starter includes some plugins for convenience, one of which is the &lt;a href="https://github.com/styxlab/gatsby-theme-try-ghost/tree/master/packages/gatsby-theme-ghost-members"&gt;&lt;code&gt;gatsby-theme-ghost-members&lt;/code&gt;&lt;/a&gt; plugin. As discussed earlier, the members plugin needs a public backend which currently must be a Ghost CMS, therefore the subscription flow won't work with a CMS on &lt;em&gt;localhost.&lt;/em&gt; That's why you should remove this plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;yarn remove gatsby-theme-ghost-members
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and also exclude it in your &lt;code&gt;gatsby-config.js&lt;/code&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="c1"&gt;// gatsby-config.js&lt;/span&gt;

&lt;span class="nx"&gt;plugins&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="c1"&gt;// resolve: `gatsby-theme-ghost-members`,&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;
  
  
  Add plugin for inline images
&lt;/h3&gt;

&lt;p&gt;While feature and all meta images are included in the static bundle by default, all inline images within posts or pages are only included if you add the new &lt;a href="https://github.com/styxlab/gatsby-theme-try-ghost/tree/master/packages/gatsby-rehype-inline-images"&gt;&lt;code&gt;gatsby-rehype-inline-images&lt;/code&gt;&lt;/a&gt; plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;yarn add gatsby-rehype-inline-images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a sub-plugin of the &lt;code&gt;gatsby-transformer-rehype&lt;/code&gt; plugin and must be placed into your &lt;code&gt;gatsby-config.js&lt;/code&gt; as follows:&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;// gatsby-config.js&lt;/span&gt;

&lt;span class="nx"&gt;plugins&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;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-transformer-rehype`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;node&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;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;`GhostPost`&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
                &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s2"&gt;`GhostPage`&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;plugins&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;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-rehype-ghost-links`&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;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-rehype-prismjs`&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;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`gatsby-rehype-inline-images`&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="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;Including this plugin may result in longer build times as all inline images must be downloaded. However, as you are downloading them from &lt;em&gt;localhost&lt;/em&gt; you are not limited by network bandwidth.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/styxlab/gatsby-theme-try-ghost/tree/master/packages/gatsby-rehype-inline-images"&gt;&lt;code&gt;gatsby-rehype-inline-images&lt;/code&gt;&lt;/a&gt; plugin also processes images, so they are lazy loaded and fade in with a nice blur-up effect known from &lt;a href="https://medium.com/"&gt;Medium&lt;/a&gt;. See the plugin &lt;a href="https://github.com/styxlab/gatsby-theme-try-ghost/tree/master/packages/gatsby-rehype-inline-images"&gt;readme&lt;/a&gt; to learn more about the options this plugin provides.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smoke test
&lt;/h2&gt;

&lt;p&gt;You can now start your first test build with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;yarn develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and see if the build succeeds. Check the results on &lt;a href="http://localhost:8000/"&gt;http://localhost:8000/&lt;/a&gt;. Now, add a new article in your Ghost CMS on &lt;em&gt;localhost&lt;/em&gt; and press the &lt;em&gt;Publish&lt;/em&gt; button. After that re-build your project again with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;yarn develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and verify that the new article comes through:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Cg7kTnrP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-new-article.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cg7kTnrP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-new-article.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build your static site
&lt;/h2&gt;

&lt;p&gt;While the development command is great for testing, you need to issue the build command to generate an optimized bundle that can be deployed to a CDN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;yarn build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check that your site looks as expected by starting the build server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;gatsby serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and visit your site at &lt;a href="http://localhost:9000/"&gt;http://localhost:9000/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy to Netlify
&lt;/h2&gt;

&lt;p&gt;Now its time to deploy your site to a global content delivery network (CDN). This step has been described in more detail in the &lt;a href="https://www.jamify.org/2020/05/19/getting-started-with-jamify/"&gt;getting started tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here, I just repeat the simple steps. Once you have the Netlify CLI tool installed you can login&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;npm &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;netlify-cli

&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;netlify login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and deploy the previously build bundle from the &lt;code&gt;public/&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;netlify deploy &lt;span class="nt"&gt;--prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Answer the upcomimg questions as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GKT8I66I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GKT8I66I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-12.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and you should see you site manually published on Netlify&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5PAIbXTg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5PAIbXTg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-13.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;under &lt;a href="https://eager-golick-336605.netlify.app"&gt;https://eager-golick-336605.netlify.app&lt;/a&gt; or another unique subdomain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5b2N2LQF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-netlify.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5b2N2LQF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-netlify.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although optional, many people want to deploy their blog on a &lt;a href="https://docs.netlify.com/domains-https/custom-domains/"&gt;custom domain&lt;/a&gt;. You can either purchase a new domain on Netlify or bring your own. This does not come for free and a custom domain name will cost you about $1,5/month.&lt;/p&gt;

&lt;p&gt;Congrats! 🎉 Believe it or not, &lt;strong&gt;your site is now running on a flaring fast CDN with zero operational cost&lt;/strong&gt;. Plus, your site is even SSL secured and enjoys all the Jamstack security benefits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Deployment
&lt;/h2&gt;

&lt;p&gt;In another tutorial article, I showed how you can setup a &lt;a href="https://www.jamify.org/2020/04/14/continuous-content-publishing/"&gt;continuous deployment pipeline&lt;/a&gt;, where a content change in your CMS triggers a site re-build which is then automatically propagated to your live site on the global CDN.&lt;/p&gt;

&lt;p&gt;This setup heavily relies on online cloud services: your CMS must have a public endpoint that triggers a webhook on Gatsby Cloud which deploys the build to Netlify. With a CMS on &lt;em&gt;localhost&lt;/em&gt;, &lt;strong&gt;this setup won't work anymore.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Webhooks on localhost
&lt;/h3&gt;

&lt;p&gt;With a neat &lt;a href="https://github.com/adnanh/webhook"&gt;webhook&lt;/a&gt; open-source project from Adnan Hajdarević you can create a similar pipeline on localhost too. There are different methods available for installing this Golang program, here I choose to download the the &lt;a href="https://github.com/adnanh/webhook/releases/download/2.7.0/webhook-linux-amd64.tar.gz"&gt;&lt;code&gt;webhook-linux-amd64.tar.gz&lt;/code&gt;&lt;/a&gt;  &lt;a href="https://github.com/adnanh/webhook/releases"&gt;binary package&lt;/a&gt;, unpack the file and copy the executable in &lt;code&gt;/usr/bin/&lt;/code&gt; folder of my machine to make it globally available.&lt;/p&gt;

&lt;p&gt;The webhook program consumes a &lt;code&gt;hooks.json&lt;/code&gt; definition file and spins-up a server on localhost. We need to define two actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build the jamify-starter with &lt;code&gt;yarn build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Deploy the build package with &lt;code&gt;netlify deploy --prod&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;which can be combined in one script file called &lt;code&gt;build-and-deploy.sh&lt;/code&gt; that you should place in your work &lt;code&gt;jamify-starter&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

yarn clean
yarn build
netlify deploy &lt;span class="nt"&gt;--prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make this file executable with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x build-and-deploy.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now create the &lt;code&gt;hooks.json&lt;/code&gt; in the same directory:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"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;"jamify-webhook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"execute-command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./build-and-deploy.sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command-working-directory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/home/styxlab/jamify-starter"&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;The working directory must be an absolute path, please change it to your own needs. You can now spin-up the webhook server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;jamify-starter]&lt;span class="nv"&gt;$ &lt;/span&gt;webhook &lt;span class="nt"&gt;-hooks&lt;/span&gt; hooks.json &lt;span class="nt"&gt;-verbose&lt;/span&gt; &lt;span class="nt"&gt;-port&lt;/span&gt; 7000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now test this new hook by triggering the webhook with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://0.0.0.0:7000/hooks/jamify-webhook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connect to CMS
&lt;/h3&gt;

&lt;p&gt;You can add this webhook easily to your CMS on localhost, so it get's triggered whenever you make changes to your content:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kDH1nxeE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kDH1nxeE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-14.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---Y7sF57N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---Y7sF57N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/image-15.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Test your pipeline
&lt;/h3&gt;

&lt;p&gt;Let's make a simple content change. For this test, I change the title of the first post and also exchange the feature image with another one from &lt;a href="https://unsplash.com/"&gt;Unsplash&lt;/a&gt;. Make sure to hit the &lt;em&gt;Update&lt;/em&gt; button after making these changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pzmxQEk_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-cms-content-edit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pzmxQEk_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/07/localhost-cms-content-edit.png" alt="Running a professional blog for free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the build has completed, your live site should then be automatically updated with the new content changes.&lt;/p&gt;

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

&lt;p&gt;If you do not need member functions and mostly write your articles yourself, the described setup may be exactly what you need for running an up-to-date, super-fast, SSL-secured, shell-proof public blog site with 99.99% uptime &lt;strong&gt;at zero costs&lt;/strong&gt; 🥳.&lt;/p&gt;

&lt;p&gt;While this article focuses on the operating costs of a live blog site, it is worth mentioning that this solution makes blogging not only more affordable, it also makes blogging &lt;strong&gt;more accessible&lt;/strong&gt; : The install process is much simpler, so that it is feasible for people who feel discouraged by  traditional self-hosting solutions.&lt;/p&gt;

&lt;p&gt;Furthermore, taking a public CMS server out of the equation will certainly reduce complexity, ongoing maintenance efforts and let your mind put at easy: &lt;strong&gt;without a server, you cannot be hacked.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.blogody.com/landing"&gt;Do you want early access to Blogody, the brand new blogging platform that I am creating? Just sign-up on the new Blogody landing page and be among the first to get notified!&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;This post was originally published at &lt;a href="https://www.jamify.org/2020/07/15/running-a-professional-blog-for-free/"&gt;jamify.org&lt;/a&gt; on July 15, 2020.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>gatsby</category>
      <category>ghost</category>
      <category>react</category>
    </item>
    <item>
      <title>Newsletter marketing with Jamify</title>
      <dc:creator>Joost Jansky</dc:creator>
      <pubDate>Sun, 05 Jul 2020 08:11:55 +0000</pubDate>
      <link>https://dev.to/styxlab/newsletter-marketing-with-jamify-352</link>
      <guid>https://dev.to/styxlab/newsletter-marketing-with-jamify-352</guid>
      <description>&lt;p&gt;Learn how to initiate, organize and maintain newsletter marketing campaigns with Jamify! It may surprise you that membership subscriptions on your static site are readily possible. Best of all, you can manage members in your Ghost CMS. Start creating professional newsletter campaigns today!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IDWdaybu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/40c4aaf3e167415ffbe872bc9b92a70b/photo-1514862474054-e3509f8af30f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IDWdaybu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.jamify.org/static/40c4aaf3e167415ffbe872bc9b92a70b/photo-1514862474054-e3509f8af30f.jpg" alt="Newsletter marketing with Jamify"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A newsletter is still a popular and effective way to connect to your audience and establish trusted relations with your readers. The Ghost team continues to invest heavily into membership functions that you can also use with Jamify in order to initiate, organize and maintain professional newsletter campaigns.&lt;/p&gt;

&lt;p&gt;It is still widely believed that statically built sites cannot provide dynamic functionality such as newsletter subscriptions. &lt;em&gt;Totally wrong!&lt;/em&gt; Jamify utilizes the static site builder Gatsby which creates static sites that can be built with &lt;strong&gt;&lt;em&gt;app like features&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/styxlab/gatsby-starter-try-ghost"&gt;Jamify starter&lt;/a&gt; therefore integrates a new &lt;a href="https://github.com/styxlab/gatsby-theme-try-ghost/tree/master/packages/gatsby-theme-ghost-members"&gt;membership plugin&lt;/a&gt; that allows for your users to freely subscribe to your site thereby acquiring &lt;em&gt;membership status&lt;/em&gt; in your Ghost CMS. The CMS handles sending out an email invite and adding members to your membership dashboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subscription Flow with Jamify
&lt;/h2&gt;

&lt;p&gt;Let's see how this works for a user visiting your Jamify site. There are two places where your users can subscribe to your site. The most prominent one is the &lt;em&gt;Subscribe&lt;/em&gt; button at the top right corner. This option is is present on all pages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2tt-pkPL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/06/newsletter-subscribe-button-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2tt-pkPL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cms.jamify.org/content/images/2020/06/newsletter-subscribe-button-2.png" alt="newsletter-subscribe-button-2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pressing &lt;em&gt;Subscribe&lt;/em&gt; opens a new modal overlay window:&lt;/p&gt;



&lt;p&gt;The only information asked for is an email address - it can't get any simpler. Let's choose to provide one and press &lt;em&gt;Subscribe&lt;/em&gt;:&lt;/p&gt;



&lt;p&gt;You should now see the green success message. The screen stays up until a user hits the cross button at the top right corner or the browser's back button.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; You can also press the &lt;code&gt;ESC&lt;/code&gt; key on your keyboard to exit the overlay window.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In addition to the modal subscription window, a subscribe section is also shown at the end of every post:&lt;/p&gt;



&lt;p&gt;This is the perfect place for asking your users to subscribe. After your visitors enjoyed reading your article, they get the opportunity to subscribe to your site in order to stay informed when you publish a new post.&lt;/p&gt;

&lt;p&gt;Pressing the &lt;em&gt;Submit&lt;/em&gt; button terminates the flow on your site and the user receives an email in order to confirm the subscription.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your Jamify site first registers the user's email address in your Ghost CMS which then takes care of handling the confirmation process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  User confirmation
&lt;/h3&gt;

&lt;p&gt;A typical email that your users receive in their inbox looks as follows:&lt;/p&gt;



&lt;p&gt;This opt-in method follows best practices and ensures that subscribing to your site is an active decision. Your user needs to click this button in order to freely sign-up to your site. There is also a direct link at the bottom of every mail which can be used instead of clicking the button.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you inspect the subscription link you'll see that it refers to your Ghost CMS backend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even though users subscribe to your backend, a success message is forwarded and opens your front-end page:&lt;/p&gt;



&lt;p&gt;That way users are kept on your main site while the hard work is performed in the background! This last step completes the user's subscription flow.&lt;/p&gt;

&lt;p&gt;Note that a user can always unsubscribe by pressing a link that is sent with every email. Now, it's your turn to feed your users with a newsletter or other email marketing material.&lt;/p&gt;

&lt;h2&gt;
  
  
  Members dashboard
&lt;/h2&gt;

&lt;p&gt;All users who successfully subscribed to your site show up in the membership dashboard of your CMS:&lt;/p&gt;



&lt;p&gt;This is the place where you can manage your members. You can manage each member individually, add labels and notes and also control if a user will receive newsletters:&lt;/p&gt;



&lt;h2&gt;
  
  
  Preview Newsletter
&lt;/h2&gt;

&lt;p&gt;With your Ghost CMS you can now automatically send full articles as an email version to your members. Before doing that, you should make sure you are satisfied with the end result and send a test email to yourself.&lt;/p&gt;

&lt;p&gt;From your post view, open your right settings pane and choose &lt;em&gt;Email newsletter.&lt;/em&gt; This opens a new dialog as shown below:&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that you must configure Mailgun in order to be able to use the email newsletter feature. For further instructions, look at the configuration section below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;em&gt;Preview in browser&lt;/em&gt; function is a really great feature as it gives you a visual presentation of the outcome on both the desktop and on mobile devices:&lt;/p&gt;



&lt;p&gt;Once you are fully satisfied with both the desktop and the mobile results, use the &lt;em&gt;Send test email&lt;/em&gt; button to get the result into your own inbox. This is how the desktop version looks in my inbox:&lt;/p&gt;



&lt;p&gt;It's reassuring to see that the emailed version looks exactly like the desktop preview version.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's really confusing that Ghost uses your SMTP configuration for sending you test emails, but requires a Mailgun setup in order to be able to use the newsletter functionality.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Personalize Newsletters
&lt;/h2&gt;

&lt;p&gt;It would be strange to receive an email containing a full blog article without a small greeting or introductory message. This is where &lt;strong&gt;email cards&lt;/strong&gt; enter the game:&lt;/p&gt;



&lt;p&gt;An &lt;em&gt;email card&lt;/em&gt; can be placed anywhere in your post and is only shown in the email output, but not in the actual post (yes, this also works with Jamify 😉).&lt;/p&gt;



&lt;p&gt;While email cards are great, they still feel a bit limited. For example, you cannot place any messages in front of the article, the earliest place is below the feature image.&lt;/p&gt;

&lt;p&gt;Furthermore, email cards only support basic text formatting. Wouldn't it be great to place an image of your signature in your note or be able to change the typography so it looks like a handwritten note? As members functions are still beta in Ghost, it' probably a bit early to ask for those features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Newsletter Campaigns
&lt;/h2&gt;

&lt;p&gt;You have written and reviewed your article, discussed it with your peers, added a personalized note with email cards and tested the newsletter result in the preview windows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you need to do in order to send out the newsletter to your subscribed members?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;First, you should check the newsletter subscription status of your members. By default, all members are signed up to your newsletters, but are there users you want to exclude? Have you excluded users that should receive the newsletter this time?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, the final step needed is right before hitting the &lt;em&gt;Publish&lt;/em&gt; button, by selecting the &lt;em&gt;Send by email&lt;/em&gt; switch:&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;Want to send a newsletter after the post has been published? No problem: Just set your post into draft status, turn the email switch on and re-publish. Best of all: Your Jamify front-end page is not interrupted by this action!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It would be great to have a function that allows sending only to those users that did not receive the newsletter earlier. It's important to be extra cautions here: if you happen to send out the same newsletter twice, &lt;strong&gt;it's a sure way to land in the spam folder or get unsubscribed forever!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Teaser Newsletters
&lt;/h2&gt;

&lt;p&gt;In my view, sending the full post as an email is a bit bloated. Many people I spoke to also prefer to send an excerpt with a link to the full post instead of a full article. You want to inform your readers with a newsletter, but you also want to channel your users back to your blog site.&lt;/p&gt;

&lt;p&gt;Ghost's newsletter flow does not support this use case, however, you can make a reduced teaser version of your post as a second post – literally a &lt;em&gt;ghost post&lt;/em&gt; 😂. There is just one complication. In order to send out the newsletter, you must publish it first. In an &lt;a href="https://dev.to/continuous-content-publishing/"&gt;automated workflow&lt;/a&gt;, publishing your article triggers a &lt;em&gt;webhook&lt;/em&gt; which then leads to the publication of your &lt;em&gt;secondary ghost post:&lt;/em&gt; &lt;strong&gt;Ouch!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Excluding Posts in Jamify
&lt;/h3&gt;

&lt;p&gt;You need a way to &lt;em&gt;publish&lt;/em&gt; a post in your back-end that can be excluded in your Jamify front-end. With the flexibility you have with Jamify, this is readily possible. First, you need to mark the post for exclusion. You can use an internal tag for that purpose. Internal tags in Ghost start with a hash. So, in your CMS admin interface, create a new internal tag with name &lt;code&gt;#hidden&lt;/code&gt; as follows:&lt;/p&gt;



&lt;p&gt;Note that you need to switch to the &lt;em&gt;Internal tags&lt;/em&gt; category in order to see the tag after creation. You will assign this tag to your newsletter post later.&lt;/p&gt;

&lt;p&gt;Now, you need to tell your Jamify starter that it should not generate pages for posts that contain the tag &lt;code&gt;#hidden&lt;/code&gt;. This can be easily achieved with setting a configuration option in &lt;code&gt;siteConfig.js&lt;/code&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="c1"&gt;// siteConfig.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;siteUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://www.jamify.org`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="c1"&gt;// Exclude post or pages (default: do not exclude)&lt;/span&gt;
  &lt;span class="na"&gt;excludePostsOrPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;tag&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="s2"&gt;`#hidden`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;excludePostOrPage&lt;/code&gt; option takes a Javascript function as input, so you gain full control over the exclusion process. Depending on the context, the &lt;code&gt;node&lt;/code&gt; variable will be populated with all fields present on posts or pages, which gives you a vast range of possibilities.&lt;/p&gt;

&lt;p&gt;In the above example, we exclude posts based on a simple tag, but you can use more advanced pattern matching algorithms and work with a combination of fields.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We use internal tags in this example, but the &lt;code&gt;excludePostOrPage&lt;/code&gt; function works with regular tags too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order for these changes to take effect, you need to re-build your site. With an automated set-up all you need to do is pushing the change to Github.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As the idea of the teaser is to channel your user's back to your site, make sure the new post is published and accessible to the world, before sending out the newsletter.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Teaser
&lt;/h3&gt;

&lt;p&gt;The teaser newsletter should be simple and give a glimpse into the topic of a newly published article. Start by making a dedicated draft post, which could start with a greeting, again utilizing email cards:&lt;/p&gt;



&lt;p&gt;and followed by the start of the article:&lt;/p&gt;



&lt;p&gt;Now, it's super important that you don't forget to assign the hidden tag to this newsletter teaser post before pressing the &lt;em&gt;Publish&lt;/em&gt; button:&lt;/p&gt;



&lt;p&gt;Again, you should make use of the &lt;em&gt;Preview in browser&lt;/em&gt; functions and send yourself the newsletter for review before hitting the big &lt;em&gt;Publish&lt;/em&gt; button.&lt;/p&gt;

&lt;h2&gt;
  
  
  CMS Configuration
&lt;/h2&gt;

&lt;p&gt;In order to be able to use the newsletter features in your Ghost CMS, you must go to the &lt;em&gt;Labs&lt;/em&gt; section and activate the &lt;em&gt;Enable members&lt;/em&gt; and the &lt;em&gt;Allow free member signup&lt;/em&gt; switches:&lt;/p&gt;



&lt;p&gt;It's quite new that you can also configure the reply email that is sent with the newsletter email:&lt;/p&gt;



&lt;p&gt;Finally, you must configure &lt;a href="https://www.mailgun.com/"&gt;Mailgun&lt;/a&gt;, otherwise the newsletter sending function is disabled:&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;Mailgun is currently the only option for distributing newsletters. Hopefully Ghost will provide more options after the beta phase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Redirects
&lt;/h3&gt;

&lt;p&gt;All links within your newsletter email point back to your Ghost CMS which is not visible to the public, so they will appear to be broken. It's therefore extremely important that those links get redirected to your live site.&lt;/p&gt;

&lt;p&gt;If you installed your Ghost CMS as described in our self-hosting tutorial &lt;a href="https://www.jamify.org/2020/04/07/ghost-cms-on-hetzner-cloud/"&gt;Ghost CMS on Hetzner Cloud&lt;/a&gt; you are done and you can skip this section. Otherwise, you need to upload the following &lt;code&gt;redirects.json&lt;/code&gt; file to your Ghost CMS:&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="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;from&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="s2"&gt;^&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/(?!content&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/images&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/|members&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/|unsubscribe&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;/|p&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;to&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="s2"&gt;https://www.your-blog.org/$1&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="s2"&gt;permanent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;Basically this file instructs the Ghost CMS server to permanently redirect all endpoints to your static site, except the ones starting with either &lt;code&gt;/content/images&lt;/code&gt;, &lt;code&gt;/members&lt;/code&gt; or &lt;code&gt;/unsubscribe&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;A flaring fast static Jamify site that you can push to the edges of a CDN is capable of providing your visitors with a &lt;em&gt;dynamic user experience&lt;/em&gt;. The new membership plugin that is integrated into the Jamify starter enables a membership subscription flow that is not different from a traditional Ghost setup.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This means: no loss in dynamic user experience, but a big gain in site performance, security and developer flexibility!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a site owner it is important that you can utilize the members function in your headless Ghost CMS, so no other tool is needed and everything can be done right where you write your articles. While the members dashboard is cool, the newsletter sending in Ghost feels too tightly coupled to the article publishing workflow which makes it difficult to launch independent newsletter campaigns.&lt;/p&gt;

&lt;p&gt;Nevertheless, you can create hidden posts that never show on your blog site solely for the purpose of generatingnewsletters. This is a great alternative until Ghost supports more flexible newsletter features and gives you a lot of freedom for starting independent newsletter campaigns!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.blogody.com/landing"&gt;Do you want early access to Blogody, the brand new blogging platform that I am creating? Just sign-up on the new Blogody landing page and be among the first to get notified!&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>gatsby</category>
      <category>ghost</category>
      <category>cms</category>
    </item>
  </channel>
</rss>
