<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Sue Smith</title>
    <description>The latest articles on Forem by Sue Smith (@suesmith).</description>
    <link>https://forem.com/suesmith</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%2F154099%2F9d185df0-7f11-45be-a0d9-a24997721513.jpg</url>
      <title>Forem: Sue Smith</title>
      <link>https://forem.com/suesmith</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/suesmith"/>
    <language>en</language>
    <item>
      <title>Transform web pages at the edge</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Mon, 03 Nov 2025 16:57:50 +0000</pubDate>
      <link>https://forem.com/fastly/transform-web-pages-at-the-edge-1lop</link>
      <guid>https://forem.com/fastly/transform-web-pages-at-the-edge-1lop</guid>
      <description>&lt;p&gt;Edge computing apps allow you to enhance the behavior of a website by manipulating the request and response at the network edge, near the user. You can now transform your web page content at the Fastly edge more easily with the &lt;a href="https://www.fastly.com/blog/rewriting-html-with-the-fastly-javascript-sdk" rel="noopener noreferrer"&gt;HTML Rewriter&lt;/a&gt; in your JavaScript Compute apps. Ideal for customizations like personalization and A/B testing, the rewriter uses familiar DOM manipulation patterns. &lt;/p&gt;

&lt;p&gt;Let's run through how to switch up your page HTML with a Fastly Compute app in just a few steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start a new project
&lt;/h2&gt;

&lt;p&gt;In your terminal, create a new 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="nb"&gt;mkdir &lt;/span&gt;htmlrewrite &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;htmlrewrite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize a new Compute app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @fastly/cli compute init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Accept the defaults, choosing &lt;strong&gt;JavaScript&lt;/strong&gt; and selecting the empty starter kit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fajp232915f821hx8tnwc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fajp232915f821hx8tnwc.png" alt="empty starter" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter project metadata
&lt;/h2&gt;

&lt;p&gt;In your new project, open the &lt;code&gt;package.json&lt;/code&gt; and change the Compute JS SDK dependency as follows:&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="s2"&gt;"@fastly/js-compute"&lt;/span&gt;: &lt;span class="s2"&gt;"^3.35.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;npm install&lt;/code&gt; to get your environment ready.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;fastly.toml&lt;/code&gt; file, add the details for the website you want to transform at the edge (changing the addresses to use your own or using the included demo site):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[local_server]&lt;/span&gt;

  &lt;span class="nn"&gt;[local_server.backends]&lt;/span&gt;

    &lt;span class="nn"&gt;[local_server.backends.website]&lt;/span&gt;
      &lt;span class="py"&gt;override_host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"www.goldengirls.codes"&lt;/span&gt;
      &lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://www.goldengirls.codes/"&lt;/span&gt;

&lt;span class="nn"&gt;[setup]&lt;/span&gt;

  &lt;span class="nn"&gt;[setup.backends]&lt;/span&gt;

    &lt;span class="nn"&gt;[setup.backends.website]&lt;/span&gt;
      &lt;span class="py"&gt;address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"www.goldengirls.codes"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write your logic
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;src/index.js&lt;/code&gt; we'll be writing our Compute logic to transform the HTML at the edge. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flaa3upagld76dcaoukvt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flaa3upagld76dcaoukvt.png" alt="our js code" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start by importing a couple of dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getGeolocationForIpAddress&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fastly:geolocation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HTMLRewritingStream&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;fastly:html-rewriter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're going to build geolocation into our processing.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;handleRequest&lt;/code&gt; function, add &lt;code&gt;try&lt;/code&gt; &lt;code&gt;catch&lt;/code&gt; blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;//rewriter processing here&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Internal Server Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;h3&gt;
  
  
  Grab geolocation info
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;code&gt;try&lt;/code&gt; block, let's first get some info from the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ip&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;geo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getGeolocationForIpAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're going to use the time of day at the user location to tailor the display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getHours&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utc_offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;emoji&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;12&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="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;18&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll insert this daft emoji into the page to personalize it to the user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specify rewrite behavior
&lt;/h3&gt;

&lt;p&gt;Still inside the &lt;code&gt;try&lt;/code&gt; block, use an &lt;code&gt;HTMLRewritingStream&lt;/code&gt; to specify what you want your Compute app to do to the HTML from your origin website. In this example we append the emoji to the &lt;code&gt;h1&lt;/code&gt; element and replace every second image with a different one – change yours to suit your website!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;transformer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HTMLRewritingStream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emoji&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div.code:nth-child(even) img&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src&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://shadypinesmiami.github.io/sophia.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use standard CSS selectors to indicate the elements you want to transform.&lt;/p&gt;

&lt;p&gt;Fetch the response from the website specified as a &lt;code&gt;backend&lt;/code&gt; in your &lt;code&gt;toml&lt;/code&gt; and carry out the transformation on it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;backendResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&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.goldengirls.codes/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;website&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeThrough&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transformer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, return the new response to the user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;backendResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content-type&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;text/html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your script should now look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// &amp;lt;reference types="@fastly/js-compute" /&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getGeolocationForIpAddress&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fastly:geolocation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HTMLRewritingStream&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fastly:html-rewriter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ip&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;geo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getGeolocationForIpAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getHours&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;geo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utc_offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;emoji&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;12&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="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;displayTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;18&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;transformer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HTMLRewritingStream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emoji&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div.code:nth-child(even) img&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src&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://shadypinesmiami.github.io/sophia.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;backendResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&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.goldengirls.codes/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;website&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipeThrough&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transformer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;backendResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content-type&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;text/html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&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="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Internal Server Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;h2&gt;
  
  
  Test your app
&lt;/h2&gt;

&lt;p&gt;Time to run your app! In the terminal, enter the start command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;With any luck you'll see a local address to try the app at.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdtkkwuyqi25zjy2o2gyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdtkkwuyqi25zjy2o2gyh.png" alt="test site" width="800" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might notice that the time of day emoji doesn't actually match the time of day at your location.. 🤔 That's because your app is just running locally on your computer – you'll need to deploy it to the edge to see that functionality working reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy your app
&lt;/h2&gt;

&lt;p&gt;Everything working the way you want it to? Great, time to deploy to Fastly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.fastly.com/signup" rel="noopener noreferrer"&gt;Sign up for a Fastly account&lt;/a&gt; if you haven't already.&lt;/p&gt;

&lt;p&gt;Grab an API token from your account:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Account&lt;/strong&gt; &amp;gt; &lt;strong&gt;API tokens&lt;/strong&gt; &amp;gt; &lt;a href="https://manage.fastly.com/account/personal/tokens" rel="noopener noreferrer"&gt;&lt;strong&gt;Personal tokens&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Token&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; anything you like&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; Automation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role:&lt;/strong&gt; Engineer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope:&lt;/strong&gt; Global (deselect the Read-only access box)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access:&lt;/strong&gt; All services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiration:&lt;/strong&gt; Never expire&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Copy the token value and save it on your computer&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In your terminal, create a Fastly profile, entering the API token you copied from your account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fastly profile create 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can go ahead and enter the deploy command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Accept the defaults and let the CLI create a new service for you, confirming the &lt;code&gt;backend&lt;/code&gt; details from your &lt;code&gt;toml&lt;/code&gt;. Once it's deployed, the output will include the address to try your new app at, which will end &lt;code&gt;edgecompute.app&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkd4oovo1csxicz71l1ug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkd4oovo1csxicz71l1ug.png" alt="deployed app details" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open your app in a browser to see the correct time of day indicator:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9lto4d587sftd6lpaag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9lto4d587sftd6lpaag.png" alt="app in browser" width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is indeed afternoon where I am!&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep going
&lt;/h2&gt;

&lt;p&gt;Add more processing to your Compute app! You can use the HTML Rewriter to make all sorts of changes through DOM manipulation, like adding attributes to your elements to change the site behavior.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fastly.com/blog/rewriting-html-with-the-fastly-javascript-sdk" rel="noopener noreferrer"&gt;Rewriting HTML with the Fastly JavaScript SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://js-compute-reference-docs.edgecompute.app/docs/fastly:html-rewriter/HTMLRewritingStream/" rel="noopener noreferrer"&gt;HTML Rewriter docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastly.com/documentation/guides/getting-started/domains/securing-domains/tls-quick-start/" rel="noopener noreferrer"&gt;Add a domain to your service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/fastly/an-easy-intro-to-edge-computing-3ced"&gt;An easy intro to edge computing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastly.com/documentation/guides/compute/developer-guides/javascript/" rel="noopener noreferrer"&gt;Learn more about building Compute apps in JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you get stuck please feel free to post on the &lt;a href="https://community.fastly.com/" rel="noopener noreferrer"&gt;Fastly Community Forum&lt;/a&gt;. 🛟&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>webdev</category>
      <category>cloud</category>
      <category>learning</category>
    </item>
    <item>
      <title>Enabling developers in GitHub Codespaces</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Tue, 07 Oct 2025 14:09:43 +0000</pubDate>
      <link>https://forem.com/fastly/enabling-developers-in-github-codespaces-1l3a</link>
      <guid>https://forem.com/fastly/enabling-developers-in-github-codespaces-1l3a</guid>
      <description>&lt;p&gt;Over the last few months I’ve been exploring GitHub codespaces for developer enablement. I needed to replace our Fastly onboarding projects that had been hosted on Glitch, and ideally wanted to avoid the need for learners to install local tooling or even sign up for an account before trying our Compute platform. In this post I’ll run through what I’ve discovered about using codespaces for dev product learning.&lt;/p&gt;

&lt;p&gt;Here’s an overview of what our codespace projects do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install dependencies and automatically run an app&lt;/li&gt;
&lt;li&gt;Open previews of the app UI in the codespace&lt;/li&gt;
&lt;li&gt;Deploy apps at the click of a button using bash scripts&lt;/li&gt;
&lt;li&gt;Hide UI elements to minimize distractions&lt;/li&gt;
&lt;li&gt;Use an extension to show custom buttons in the editor for actions like splitting views, sharing app previews, opening the terminal, formatting code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This daft video runs through how they work:&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/BJZ3niThD2s"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, what is a codespace?
&lt;/h2&gt;

&lt;p&gt;A codespace is a web editing environment you can open in the browser from a GitHub repository. Codespaces use a version of the VS Code editor, so you can specify editor settings much like you would in a local VS Code installation. Using codespaces lets you carry out development activities without downloading or installing anything onto your local machine – it all happens in the cloud.&lt;/p&gt;

&lt;p&gt;You can access codespaces from the homepage of a GitHub repo, using the &lt;strong&gt;Code&lt;/strong&gt; button to open an environment for editing the codebase on a specific repo branch. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1095rn65n0a5mlvt4jxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1095rn65n0a5mlvt4jxp.png" alt="code button on a repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Edits made in a codespace are automatically kept for a limited period of time you can set in your GitHub account – you’ll receive a warning if a codespace is about to be deleted and you can export your changes to a branch &lt;a href="https://docs.github.com/en/codespaces/setting-your-user-preferences/configuring-automatic-deletion-of-your-codespaces" rel="noopener noreferrer"&gt;if you aren’t ready to lose them&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Containers
&lt;/h2&gt;

&lt;p&gt;A codespace runs in a Docker container, and you can specify requirements in the repo &lt;code&gt;devcontainer.json&lt;/code&gt; file. I usually include system features like Node (mostly I’m targeting JavaScript projects in the Node ecosystem), but the codespace will guess some dependencies based on the repo content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s an example container spec I’m using for edge computing projects: &lt;a href="https://github.com/glitchdotcom/learn-edge-computing/blob/main/.devcontainer/devcontainer.json" rel="noopener noreferrer"&gt;~learn-edge-computing/devcontainer.json&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;You can attach commands to container lifecycle events – these run when the codespace opens, so you can use them to carry out setup tasks and get the codespace in the state you want for your learners when they open the project. I’ve been using the &lt;code&gt;updateContentCommand&lt;/code&gt; and &lt;code&gt;postAttachCommand&lt;/code&gt; events to install NPM packages and run &lt;code&gt;package.json&lt;/code&gt; scripts I want to execute straight away.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📚 The &lt;a href="https://containers.dev/implementors/json_reference/" rel="noopener noreferrer"&gt;devcontainer metadata reference&lt;/a&gt; lists the options.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is part of a container config I used for projects originally developed on Glitch that I’d exported to GitHub:&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="nl"&gt;"updateContentCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm install"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"postAttachCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run start || npx --yes serve"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Previews and ports
&lt;/h2&gt;

&lt;p&gt;You can run apps “locally” in the codespace and they’ll be exposed through specific ports. With the Simple Browser you can automatically open these apps right inside the editor at an &lt;code&gt;app.github.dev&lt;/code&gt; address. The &lt;strong&gt;PORTS&lt;/strong&gt; area in the &lt;strong&gt;Terminal&lt;/strong&gt; at the bottom of the editor provides access to port settings, so you can open previews, change visibility, and share URLs with collaborators.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctx1omb5piadh9gl4m3v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctx1omb5piadh9gl4m3v.png" alt="ports with a preview open"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the container config, I include a section specifying that specific ports should automatically open in the preview. For my edge compute learning experience, it sets both the origin website and edge apps to open from their default ports, with custom labels making them more obvious to the learner:&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="nl"&gt;"portsAttributes"&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;"3000"&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;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"🚧 Origin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"onAutoForward"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openPreview"&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;"7676"&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;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"🌎 Compute"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"onAutoForward"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openPreview"&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;I also use a custom 🔗 &lt;strong&gt;Share&lt;/strong&gt; button to set a port to public and provide the URL so that the user can copy it to share with collaborators – they can see the preview as long as they’re logged into GitHub.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If your project is a fully static site and doesn’t use a framework, you can still run a preview using &lt;a href="https://www.npmjs.com/package/serve" rel="noopener noreferrer"&gt;npx serve&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Extensions
&lt;/h2&gt;

&lt;p&gt;You can list required VS Code extensions in your codespace container config and they’ll automatically be installed when someone opens the project. I include &lt;a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt; because my projects typically use JavaScript, and the extension for custom buttons then runs the format command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom buttons
&lt;/h3&gt;

&lt;p&gt;I’ve found the &lt;a href="https://marketplace.visualstudio.com/items?itemName=jkearins.action-buttons-ext" rel="noopener noreferrer"&gt;VS Code Action Buttons&lt;/a&gt; extension extremely helpful when it comes to customizing the UI for my learning projects. The extension lets you specify buttons that appear along the bottom of the editor. Your buttons can call VS Code editor commands and CLI commands, so I use them to give users an easy way to toggle views, and run bash scripts or &lt;strong&gt;Terminal&lt;/strong&gt; processes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39njdw9q97h4c3udz6ut.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39njdw9q97h4c3udz6ut.png" alt="action buttons in the ui"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s an excerpt of one of my button lists:&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="nl"&gt;"actionButtons"&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;"commands"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"🌈 Prettify"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"singleInstance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"useVsCodeApi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"editor.action.formatDocument"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tooltip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tidy up your code"&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;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"🚀 Publish"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"singleInstance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bash helpers/publish.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;"tooltip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Publish your content to Fastly Compute"&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;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;You can include whatever &lt;strong&gt;Terminal&lt;/strong&gt; commands you need for your target frameworks – I tend to separate them into bash scripts so that the user can tweak them more readily if they like.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📋 Here are the commands you can run on button clicks: &lt;a href="https://code.visualstudio.com/api/references/commands" rel="noopener noreferrer"&gt;Built-in Commands&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bash scripts
&lt;/h2&gt;

&lt;p&gt;With the projects I’m working on being experimental, I wanted users to be able to see and tailor the CLI code that automates processing. For that reason I included the bash scripts in a &lt;code&gt;helpers&lt;/code&gt; folder, calling those scripts from the container config and button clicks. The Fastly CLI commands have a little bit of control flow complexity that really needs a lot of testing, so I need to be able to make changes easily.&lt;/p&gt;

&lt;p&gt;Here’s a more basic bash script I use for projects users have imported (and I therefore don’t know for sure which scripts they have in their &lt;code&gt;package.json&lt;/code&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="c"&gt;# We're making some guesses about the package scripts lolol&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; package.json &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;🤔 No package.json found – try the Open button instead!&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else 
  &lt;/span&gt;&lt;span class="nv"&gt;OOPS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;🤬 hmm maybe check what's in your package.json scripts and try "&lt;/span&gt;npm run script-name&lt;span class="s2"&gt;"?&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OOPS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  npm run start &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OOPS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also use scripts like this to write out instructional information to the user in the &lt;strong&gt;Terminal&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;The Fastly projects support deployment to the edge, so I typically use a 🚀 &lt;strong&gt;Publish&lt;/strong&gt; button that runs the Fastly CLI tooling and deploys the app. Here's  publish script for our Compute Static Publisher: &lt;a href="https://github.com/glitchdotcom/11ty-to-compute/blob/main/helpers/publish.sh" rel="noopener noreferrer"&gt;publish.sh&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpks3vezt2f0v582mzhbd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpks3vezt2f0v582mzhbd.jpg" alt="publish button and terminal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Codespaces make a great editing environment for simple static website projects, and you can publish from the editor, for example if you have a blog. You can deploy to GitHub Pages at the click of a button by including the &lt;a href="https://www.npmjs.com/package/gh-pages" rel="noopener noreferrer"&gt;gh-pages&lt;/a&gt; package in your project, and a script in your &lt;code&gt;package.json&lt;/code&gt;, like this Vite example:&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="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"serve"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vite preview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gh-pages -d dist"&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;To publish using a button, just call the &lt;code&gt;deploy&lt;/code&gt; command from the custom button extension covered above. I’m using this flow for my own blog and static site projects that I migrated from Glitch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment variables
&lt;/h2&gt;

&lt;p&gt;If your platform requires an API key, you can instruct users to acquire and add one inside the codespace. In the &lt;code&gt;README&lt;/code&gt; I include links and steps for grabbing a Fastly API key and adding it using the command palette. When a user adds an environment variable, the codespace will prompt them to reload, which they’ll need to do in order to use the variable in subsequent commands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frj3ug477ytochmj8gybw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frj3ug477ytochmj8gybw.png" alt="manage user secrets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  File and feature visibility
&lt;/h2&gt;

&lt;p&gt;You can specify settings for the VS Code editing experience in your container config just like you would in a local environment. I tend to hide some features to minimize distractions, like the minimap, and files / folders like &lt;code&gt;node_modules&lt;/code&gt;, so that the learner can focus on the core parts of the project I’m trying to familiarize them with.&lt;/p&gt;

&lt;p&gt;You can include these in the settings object in your container JSON:&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="nl"&gt;"settings"&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;"files.exclude"&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;"package-lock.json"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"node_modules/"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;"editor.minimap.enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;h2&gt;
  
  
  Source control
&lt;/h2&gt;

&lt;p&gt;Although a codespace automatically stores your edits until it’s deleted, it’s a good idea to encourage users to regularly commit their changes to the underlying repo in case they lose them. You can do this in the &lt;strong&gt;Source Control&lt;/strong&gt; area on the left.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zaenwy6a386y45czzx2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zaenwy6a386y45czzx2.png" alt="source control area"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Things can get a bit confusing depending on whether your users have started the codespace from your repo or from a fork of it – I encourage users to create their own fork so that it’s clearer where their changes should be saved.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤔 &lt;em&gt;Something that gets a bit messy with codespaces for dev product onboarding is that the flow seems to be primarily optimized for devs making contributions to a repo rather than forking it to make their own project. If you don’t plan to publish changes you want your users to be able to sync their forks with, you can use template repos instead. This is one place I’ve felt the tension of what I was able to support users to do on Glitch vs this workflow.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Optimizing your repos for codespaces
&lt;/h2&gt;

&lt;p&gt;When you first open a codespace with a custom container config, it can be pretty slow to start up. You can reduce this with &lt;a href="https://docs.github.com/en/codespaces/prebuilding-your-codespaces" rel="noopener noreferrer"&gt;prebuilds&lt;/a&gt; that target specific regions you expect your users to be in. Although the free tier is generous, you might want to keep an eye on the costs for storage and compute associated with your codespaces, and definitely set spending limits in your GitHub account.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 Some of the setup for codespaces can translate to users cloning your repos locally and opening them in VS Code on their computers – this is something I want to explore soon, as well as supporting other web based VS Code environments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I found this post from &lt;a href="https://dev.to/blackgirlbytes"&gt;Rizèl Scarlett&lt;/a&gt; super helpful when I was figuring out what I could do: &lt;a href="https://dev.to/github/how-to-run-a-frontend-workshop-in-codespaces-2ede"&gt;How to run a frontend workshop in Codespaces&lt;/a&gt;&lt;/strong&gt; 🙌&lt;/p&gt;

&lt;p&gt;Some official docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/codespaces/quickstart" rel="noopener noreferrer"&gt;Quickstart for GitHub Codespaces&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/docs/devcontainers/create-dev-container" rel="noopener noreferrer"&gt;Create a Dev Container&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of my codespace-optimized projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One I used for people migrating from Glitch: &lt;a href="https://github.com/SueSmith/glitchy-editing/blob/main/.devcontainer/devcontainer.json" rel="noopener noreferrer"&gt;~glitchy-editing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Publishing an 11ty blog to the edge: &lt;a href="https://github.com/glitchdotcom/11ty-to-compute/" rel="noopener noreferrer"&gt;~11ty-to-compute&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Edge computing intro: &lt;a href="https://github.com/glitchdotcom/learn-edge-computing/" rel="noopener noreferrer"&gt;~learn-edge-computing&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>github</category>
      <category>vscode</category>
      <category>learning</category>
    </item>
    <item>
      <title>Develop an edge computing app in the browser</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Fri, 19 Sep 2025 09:22:44 +0000</pubDate>
      <link>https://forem.com/fastly/develop-an-edge-computing-app-in-the-browser-1kh5</link>
      <guid>https://forem.com/fastly/develop-an-edge-computing-app-in-the-browser-1kh5</guid>
      <description>&lt;p&gt;When I try a new web technology, I really want to play around with it upfront before installing anything locally or setting up a developer environment. Over the last few months I’ve been exploring GitHub Codespaces for this purpose, working on a set of projects that guide you through building and deploying apps to the network edge straight from the browser. In this post I’ll introduce our new Fastly Compute learning experience that you can try out in seconds.&lt;/p&gt;

&lt;p&gt;With a Compute app, you can enhance the user experience for a website at the edge. The app can manipulate the request from the user and the response from the origin website. You can write your code in various languages and the Fastly SDKs will compile it into Web Assembly (WASM) that can run at the edge, between your users and your website host. In this guide we’re writing our edge application logic in JavaScript.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/A087xT_R6lY"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Read on for a more detailed walkthrough of the flow but here’s the gist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You fork a GitHub repo
&lt;/li&gt;
&lt;li&gt;Open your fork in a codespace
&lt;/li&gt;
&lt;li&gt;The app runs and automatically opens a preview
&lt;/li&gt;
&lt;li&gt;The project includes a sample origin website that runs too
&lt;/li&gt;
&lt;li&gt;You tweak the Compute app code and see the preview update as you work
&lt;/li&gt;
&lt;li&gt;When you’re ready, you grab a Fastly API key, copy it into your project, and publish&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fork the project
&lt;/h2&gt;

&lt;p&gt;Getting your own app running takes a couple of clicks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sign into GitHub and visit the &lt;a href="https://github.com/glitchdotcom/learn-edge-computing" rel="noopener noreferrer"&gt;~learn-edge-computing&lt;/a&gt; repo.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Fork the repo into your account (best to leave the name unchanged)
&lt;/li&gt;
&lt;li&gt;Open your fork in a codespace by clicking &lt;strong&gt;Code&lt;/strong&gt; and creating a codespace on your main branch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the codespace opens it’ll attempt to do a few things automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build, run, and open a preview for your example origin website
&lt;/li&gt;
&lt;li&gt;Build, run, and preview your initial Compute app
&lt;/li&gt;
&lt;li&gt;You’ll find some buttons along the bottom of the editor to make the process easier

&lt;ul&gt;
&lt;li&gt;Use the 🔎 &lt;strong&gt;Split&lt;/strong&gt; button to separate your preview from your code so that you can edit and see the results at the same time&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get to know your new app
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6njbi0j78xckl1anw5y8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6njbi0j78xckl1anw5y8.png" alt="project in codespace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🚧 Your project includes a demo origin website – the code for it is in the &lt;code&gt;origin&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;🌎 The logic for your Compute app is in the &lt;code&gt;src&lt;/code&gt; folder. Check out the content of the &lt;code&gt;index.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;In the Terminal area, select &lt;strong&gt;PORTS&lt;/strong&gt; to see the origin and edge versions of your site – use the buttons to toggle between them in the preview. Check out the differences in functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The style is different because the Compute app switches the stylesheet at the edge.
&lt;/li&gt;
&lt;li&gt;There’s a cookie written into the page that includes geolocation information passed in at the edge.
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ohno&lt;/code&gt; link returns a synthetic HTML page at the edge instead of a default server error.
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;data&lt;/code&gt; link also returns a synthetic page instead of raw JSON.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Develop in the browser
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81cbot35q3okzbasyfed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F81cbot35q3okzbasyfed.png" alt="app preview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make a change to your Compute app. In the README you’ll find a suggested edit you can copy and paste right into the &lt;code&gt;index.js&lt;/code&gt; file. With any luck your app will automatically rebuild and update in the preview. The edit adds information to the geolocation cookie indicating the time of day at the user location.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the geolocation info won’t be accurate until you deploy to the edge, because your app is initially running “locally” inside the codespace which is running in a container hosted by GitHub.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Make changes to your origin app too in the origin folder, like changing the HTML and CSS.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can share your draft app with collaborators using the 🔗 &lt;strong&gt;Share&lt;/strong&gt; button at the bottom of the editor – they’ll just need to be signed into GitHub to see it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Deploy to the edge
&lt;/h2&gt;

&lt;p&gt;Sign up for a &lt;a href="https://fastly.com/signup" rel="noopener noreferrer"&gt;free Fastly account&lt;/a&gt; and &lt;a href="https://www.fastly.com/documentation/guides/account-info/account-management/using-api-tokens/" rel="noopener noreferrer"&gt;grab an API key&lt;/a&gt;. Pop your key into your codespace with the name &lt;code&gt;FASTLY_API_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Click the 🚀 &lt;strong&gt;Publish&lt;/strong&gt; button at the bottom of the editor and follow the prompts. A few things will happen at this point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Fastly tooling will build your app and package it for deployment
&lt;/li&gt;
&lt;li&gt;It’ll create a new service in your Fastly account and upload the package
&lt;/li&gt;
&lt;li&gt;The scripts in the codespace will also deploy your origin website to a GitHub pages site for your repo
&lt;/li&gt;
&lt;li&gt;The GitHub pages site will be set as the origin for your Compute app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifuj7o9edwd9bmmr7972.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifuj7o9edwd9bmmr7972.png" alt="deploy output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When everything’s ready, you’ll see an &lt;code&gt;edgecompute.app&lt;/code&gt; address in the Terminal output. Go ahead and click it to check out your deployed app. How does it behave differently at the edge?&lt;/p&gt;

&lt;p&gt;You can carry on making edits to your app and hit that 🚀 &lt;strong&gt;Publish&lt;/strong&gt; button whenever you want to go live with them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Remember to commit your changes to your fork of the GitHub repo if you want to keep them – use the &lt;strong&gt;Source Control&lt;/strong&gt; area on the left of the codespace editor.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep going
&lt;/h2&gt;

&lt;p&gt;Curious how the app works? Check out the &lt;code&gt;helpers&lt;/code&gt; and &lt;code&gt;.devcontainer&lt;/code&gt; folders!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.fastly.com/documentation/solutions/tutorials/enhance-ux/" rel="noopener noreferrer"&gt;Learn more including local development&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/fastly/an-easy-intro-to-edge-computing-3ced"&gt;An easy intro to edge computing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.fastly.com/documentation/solutions/tutorials/introduction-to-compute/" rel="noopener noreferrer"&gt;Follow a more detailed intro to Compute&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.fastly.com/documentation/solutions/examples/javascript/" rel="noopener noreferrer"&gt;Check out code examples in JavaScript&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.fastly.com/documentation/guides/getting-started/domains/securing-domains/tls-quick-start" rel="noopener noreferrer"&gt;Point your own domain at your site&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>serverless</category>
      <category>javascript</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Publish your website without a host</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Fri, 29 Aug 2025 10:17:26 +0000</pubDate>
      <link>https://forem.com/fastly/publish-your-website-without-a-host-3c3n</link>
      <guid>https://forem.com/fastly/publish-your-website-without-a-host-3c3n</guid>
      <description>&lt;p&gt;When you use a CDN, cached copies of your website’s static assets are stored at the network edge for fast delivery to your visitors. Well, if your website &lt;em&gt;is&lt;/em&gt; just those assets, why not just dump the whole thing at the edge and serve it directly from there instead of storing it on a web hosting service in the first place? &lt;/p&gt;

&lt;p&gt;That's what the JavaScript Static Publisher for Fastly Compute does. It delivers your static site straight from the network edge using a serverless app to handle user requests, and an edge data store for your content. This kind of &lt;em&gt;originless&lt;/em&gt; setup is well suited to generated static sites made up of HTML, CSS, and client side JavaScript, like blogs and react apps.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/BJZ3niThD2s"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Jump to:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Try a simple static site&lt;/li&gt;
&lt;li&gt;Publish a project from your computer&lt;/li&gt;
&lt;li&gt;Write and publish a blog from a codespace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can deploy existing sites to Fastly Compute using a few simple commands in your IDE. You can also create a new site, edit, and publish it without installing a thing on your computer by following a guided experience in a GitHub codespace – fork a demo project, open it in the browser, pop in an API key, and publish at the click of a button. &lt;/p&gt;

&lt;h2&gt;
  
  
  Try a simple static site
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjt1ml2vdg8np7rhw8y5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjt1ml2vdg8np7rhw8y5f.png" alt="Website project in codespace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;a href="https://github.com/glitchdotcom/website-to-compute" rel="noopener noreferrer"&gt;~website-to-compute&lt;/a&gt;&lt;/strong&gt; project demonstrates how to publish a simple static site to the edge from a GitHub codespace. &lt;/p&gt;

&lt;p&gt;The steps are in the repo &lt;code&gt;README&lt;/code&gt;, here’s the TL;DR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fork the repo&lt;/li&gt;
&lt;li&gt;Open your forked version for editing in the browser by clicking &lt;strong&gt;Code &amp;gt; Codespaces&lt;/strong&gt; and creating a new codespace on your main branch

&lt;ul&gt;
&lt;li&gt;The codespace config will run a few setup tasks when it first opens, it might take a couple of minutes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Your website preview will open in a tab – click the &lt;strong&gt;🔎 Split&lt;/strong&gt; button at the bottom to see the site side by side with your code

&lt;ul&gt;
&lt;li&gt;Edit your site HTML and CSS! Your preview will update in the editor… 👀&lt;/li&gt;
&lt;li&gt;Share your draft site with collaborators by clicking &lt;strong&gt;🔗 Share&lt;/strong&gt; and copying the URL to your clipboard 📋&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;When you’re ready to publish to Fastly, &lt;a href="http://fastly.com/signup" rel="noopener noreferrer"&gt;sign up for an account&lt;/a&gt; and grab an API key, copying it into your codespace project

&lt;ul&gt;
&lt;li&gt;Click the &lt;strong&gt;🚀 Publish&lt;/strong&gt; button along the bottom of the editor and follow the prompts&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Your &lt;code&gt;edgecompute.app&lt;/code&gt; address will appear in the terminal output&lt;/li&gt;

&lt;li&gt;&lt;em&gt;Make sure you save your edits to GitHub using the &lt;strong&gt;Source Control&lt;/strong&gt; area on the left of the editor&lt;/em&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Publish a project from your computer
&lt;/h2&gt;

&lt;p&gt;If you already have a static site on your computer that you want to deploy, open it in an IDE.&lt;/p&gt;

&lt;p&gt;Import the &lt;a href="https://github.com/fastly/compute-js-static-publish" rel="noopener noreferrer"&gt;Static Publisher&lt;/a&gt; and pass it the root directory to scaffold a Compute app for your site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @fastly/compute-js-static-publish@latest &lt;span class="nt"&gt;--root-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./_site  &lt;span class="nt"&gt;--kv-store-name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;site-content
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set up dependencies:&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="nb"&gt;cd &lt;/span&gt;compute-js &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🧪 If you want to test your site locally before deploying, use &lt;code&gt;npm run dev:publish&lt;/code&gt; and &lt;code&gt;npm run dev:start&lt;/code&gt; then open it in the browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you're ready to publish, &lt;a href="https://www.fastly.com/documentation/guides/account-info/account-management/using-api-tokens/" rel="noopener noreferrer"&gt;grab a Fastly API key&lt;/a&gt; and set it as the value of the &lt;code&gt;FASTLY_API_TOKEN&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;Deploy your app:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fquvad946wcitbhlc9o8p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fquvad946wcitbhlc9o8p.jpg" alt="Site deploying"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;edgecompute.app&lt;/code&gt; address in the terminal output – it won't show the content yet so don't worry if you see an error message. 😅&lt;/p&gt;

&lt;p&gt;Publish your content to the KV Store:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpriqy851xaak4g8jk6m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpriqy851xaak4g8jk6m.jpg" alt="Publish flow in the cli"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reload your &lt;code&gt;edgecompute.app&lt;/code&gt; URL in the browser and with any luck your content will be there!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Each time you have new content to publish, just run the &lt;code&gt;fastly:publish&lt;/code&gt; command again.&lt;/p&gt;

&lt;p&gt;📚 For more detail &lt;a href="https://www.fastly.com/documentation/solutions/tutorials/publish-static-site/" rel="noopener noreferrer"&gt;check out the tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Write and publish a blog from a codespace
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47jxmcnruom7t0mq1gfh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47jxmcnruom7t0mq1gfh.png" alt="11ty in codespace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;a href="https://github.com/glitchdotcom/11ty-to-compute" rel="noopener noreferrer"&gt;~11ty-to-compute&lt;/a&gt;&lt;/strong&gt; project publishes an Eleventy blog to the edge. You can draft new blog posts in the codespace and publish whenever you’re ready to share them with the world.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/QZM7jJTgZP0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Check out the &lt;code&gt;README&lt;/code&gt; for steps but here's the gist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fork the repo and open it in a codespace&lt;/li&gt;
&lt;li&gt;Make changes and add blog posts&lt;/li&gt;
&lt;li&gt;Grab a Fastly API key and add it in the codespace&lt;/li&gt;
&lt;li&gt;Hit the &lt;strong&gt;🚀 Publish&lt;/strong&gt; button&lt;/li&gt;
&lt;li&gt;Tell the world!&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 You can share your WIP blog posts for feedback from collaborators using the button at the bottom of the editor.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fastly.com/documentation/guides/getting-started/domains/securing-domains/tls-quick-start/" rel="noopener noreferrer"&gt;Point your own domain at your new site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dev.to/fastly/an-easy-intro-to-edge-computing-3ced"&gt;Learn about edge computing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Find out more about the &lt;a href="https://github.com/fastly/compute-js-static-publish" rel="noopener noreferrer"&gt;JavaScript Static Publisher for Fastly Compute&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Learn more about the publication flow in the &lt;a href="https://www.fastly.com/documentation/solutions/tutorials/publish-static-site/" rel="noopener noreferrer"&gt;static site publisher tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🛟 Need help? Post on the &lt;a href="https://community.fastly.com" rel="noopener noreferrer"&gt;Fastly Community forum&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>serverless</category>
      <category>javascript</category>
      <category>devex</category>
    </item>
    <item>
      <title>Understanding that app you vibe coded</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Fri, 11 Jul 2025 19:44:57 +0000</pubDate>
      <link>https://forem.com/suesmith/understanding-that-app-you-vibe-coded-5hig</link>
      <guid>https://forem.com/suesmith/understanding-that-app-you-vibe-coded-5hig</guid>
      <description>&lt;p&gt;Dealing with a project you generated using an AI tool? If you don’t have programming skills and need to understand the code for an application it can be hard to know where to begin. Perhaps you're discovering that generating the code is just one of many steps in making a successful software application! &lt;/p&gt;

&lt;p&gt;In this guide we’ll outline some places to get started learning about a codebase you need to troubleshoot, fix, or extend. We'll start by opening and running the app in a developer environment. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We’ll assume you’re working with a web application, like a website or app users access in the browser – for other types of app the steps here will not work.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Export your code
&lt;/h2&gt;

&lt;p&gt;Well be working in GitHub so if your code isn't already on there you'll need to import it. Most tools provide the ability to download or export your code straight to &lt;a href="https://github.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. If you download your code, you’ll need to install developer tooling (IDEs like VS Code and dependencies) to actually run your app on your computer. You can alternatively work with your code in the browser, which is a lot easier, so that’s what we’ll focus on here. &lt;/p&gt;

&lt;p&gt;Get your code onto GitHub – if the service you’re using doesn’t offer a GitHub export function, you can &lt;a href="https://docs.github.com/en/get-started/start-your-journey/uploading-a-project-to-github" rel="noopener noreferrer"&gt;upload your files&lt;/a&gt; straight into a GitHub repository instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add some helper code
&lt;/h3&gt;

&lt;p&gt;We’re going to open the project in a GitHub codespace – this will let you work with it without installing anything on your computer. We'll do this using containers, which let you use a dev environment on the web instead of locally on your own machine. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ The helper code is based on some assumptions about your project, for example that it’s a web application with a user interface and that it uses a &lt;code&gt;package.json&lt;/code&gt; file. If this is not the case, for example if you’re working with a mobile app, you will encounter errors!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make the process more likely to work for you, add a file to your repo. Click &lt;strong&gt;Add file &amp;gt; Create new file&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcws1fi47jrnboy8cru53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcws1fi47jrnboy8cru53.png" alt="add file" width="800" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; as the file name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5381oc9bbong3vulz8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5381oc9bbong3vulz8a.png" alt="container file" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste the following in as the file contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// For format details, see https://aka.ms/devcontainer.json. For config options, see the  
// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu  
{  
  "name": "Ubuntu",  
  "image": "mcr.microsoft.com/devcontainers/base:noble",  
  "features": {  
    "ghcr.io/devcontainers/features/node:1": {}  
  },  
  "portsAttributes": {  
        "3000-9000": {  
            "label": "App",  
            "onAutoForward": "openPreview"  
        }  
  },  
  "updateContentCommand": "npm install",  
  "waitFor": "updateContentCommand"  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells the codespace to install the necessary dependencies for your project and automatically open it when it runs. &lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Commit changes… &amp;gt; Commit changes&lt;/strong&gt; to save your new file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4er5sw771vqqv9bdtrz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4er5sw771vqqv9bdtrz7.png" alt="commit changes" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Open your project
&lt;/h2&gt;

&lt;p&gt;From your GitHub repo homepage, open your app in a codespace by clicking &lt;strong&gt;Code &amp;gt; Codespaces&lt;/strong&gt;, and creating a new codespace on your main branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xmznyzq45ylealu9z5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xmznyzq45ylealu9z5b.png" alt="create codespace" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⏳ The codespace will attempt to provide what we asked it to in the container config file we added, and it might take a few minutes to open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take a look around
&lt;/h2&gt;

&lt;p&gt;If you’ve never used an IDE (Integrated Development Environment) before it might look a bit overwhelming, but you’ll get used to it. Codespaces on GitHub use VS Code, which is the most popular IDE around, so if you plan on digging into code more, this is a tool you’ll benefit from getting familiar with.&lt;/p&gt;

&lt;p&gt;The files in your project will appear on the left, and you can access other tools in there too. In the middle you’ll see your code editor, which will display the &lt;code&gt;README&lt;/code&gt; for your project by default if it has one. You can also open your other files by selecting them from the list on the left. At the bottom you’ll see the &lt;strong&gt;Terminal&lt;/strong&gt; and other tools that help you work on your project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjgjtah7vnqu0kqal77eh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjgjtah7vnqu0kqal77eh.png" alt="project in the codespace" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Does your app have a &lt;code&gt;README&lt;/code&gt; file? If so take a look in there in case it includes helpful information on running and developing your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare your environment
&lt;/h2&gt;

&lt;p&gt;Check your project for a file named &lt;code&gt;package.json&lt;/code&gt;. In most cases web apps use frameworks that rely on the &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; ecosystem, in which case your project will have this file and you can learn how to run and build it from there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr1st8o4hizqtrkb1o04u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr1st8o4hizqtrkb1o04u.png" alt="package json" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;package.json&lt;/code&gt; file indicates dependencies and scripts for your app. The dependencies are coding resources your app is pulling in from the web – these are utilities your app depends on to deliver its functionality. That’s code developed by other people and organizations, accessed through a registry like &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;NPM&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 Dependencies are not the only way your app uses code written by others, if you generated your project using an AI tool, it was most likely trained on data from open source projects, for example on GitHub. The developers who contributed that code didn’t consent to their data being used for this purpose, which is why a lot of them are not happy about it!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to run your app, you need to install the necessary dependencies. We set the container config to do that automatically when the codespace opens. With any luck the codespace will install everything you need. If you see any errors in the &lt;strong&gt;Terminal&lt;/strong&gt; area at the bottom, read the output for tips on moving forward. If that doesn’t work, try a web search for the error text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run your app
&lt;/h2&gt;

&lt;p&gt;Your &lt;code&gt;README&lt;/code&gt; or &lt;code&gt;package.json&lt;/code&gt; will indicate how to run your app locally. Check the &lt;code&gt;package.json&lt;/code&gt; for a &lt;code&gt;scripts&lt;/code&gt; section. Scripts can include &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;serve&lt;/code&gt;, &lt;code&gt;preview&lt;/code&gt;, and more depending on the frameworks your app uses.&lt;/p&gt;

&lt;p&gt;In your &lt;strong&gt;Terminal&lt;/strong&gt;, try running the scripts as follows. First try either &lt;code&gt;start&lt;/code&gt;, or &lt;code&gt;dev&lt;/code&gt;. If you don’t have either of those, try build.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9bcsglcdf2mgylee8bf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9bcsglcdf2mgylee8bf.png" alt="start script" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Watch the &lt;strong&gt;Terminal&lt;/strong&gt; output for updates, checking any errors for further information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgbwcbrhij0b3rjy0ymy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxgbwcbrhij0b3rjy0ymy.png" alt="website running" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚧 If your app is using a data source, like a database, you might need to carry out additional steps to run it outside the environment you built it in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hopefully your app will run and open a preview on a port. The container config we added will attempt to open it automatically. Most web frameworks use ports to run your app locally while you develop it. Forwarding it to a port means you can open the app at a local address (meaning not accessible over the web, just in your environment) in the web browser. &lt;/p&gt;

&lt;p&gt;You can also access your running app using &lt;strong&gt;Ports&lt;/strong&gt; in the &lt;strong&gt;Terminal&lt;/strong&gt; section at the bottom of the editor. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0sivato2lhvicw2fbgx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0sivato2lhvicw2fbgx.jpg" alt="ports" width="800" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your app is open, you can use the split button at the top right and drag the website preview tab over into it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybabtxiv9x7h0pi5sxob.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fybabtxiv9x7h0pi5sxob.jpg" alt="editor split" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This lets you see the code as well as the app itself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xzn36z3u3cckazt79mw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5xzn36z3u3cckazt79mw.png" alt="split view" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try changing your app code and see what happens! You can always undo your changes.&lt;/p&gt;

&lt;p&gt;If you continue working on the app, you’ll need to build and deploy it. Your package scripts will include whatever you need to run in the &lt;strong&gt;Terminal&lt;/strong&gt; to build your app. Once you have a build, you’ll need to deploy it somewhere to share it with your users at an address they can access, unless you’re taking your changes back into the platform you used to generate the code in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Save your changes
&lt;/h2&gt;

&lt;p&gt;When you’re ready to save any changes you’ve made, click the &lt;strong&gt;Source Control&lt;/strong&gt; button on the left.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxacdcktaw4olfw5bw0j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flxacdcktaw4olfw5bw0j.jpg" alt="source control" width="798" height="722"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter some text in the box and click &lt;strong&gt;Commit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feythp3g34fscv7d9n10m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feythp3g34fscv7d9n10m.png" alt="commit message" width="800" height="656"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Yes&lt;/strong&gt; in the pop up notification, then &lt;strong&gt;Sync changes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbsrri5lw9xgnf5uubqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzbsrri5lw9xgnf5uubqn.png" alt="sync changes" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your edits should sync with your GitHub repo. If you’re importing your code back into the platform you started from you can do that now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debug your app
&lt;/h2&gt;

&lt;p&gt;Is your app not doing what you want it to? You can debug it in the codespace too. Use the &lt;strong&gt;Problems&lt;/strong&gt; and &lt;strong&gt;Debug Console&lt;/strong&gt; tabs in the &lt;strong&gt;Terminal&lt;/strong&gt; area at the bottom.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1whr2ngbu2ii2fo34qu4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1whr2ngbu2ii2fo34qu4.png" alt="problems" width="800" height="597"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use the VS code debug tools, click into the top text box again and enter &lt;code&gt;&amp;gt;debug&lt;/code&gt; then select an option. Choose an option based on the error you’ve been seeing in the output when your app runs, like &lt;strong&gt;Debug npm script&lt;/strong&gt;, choosing the script you entered to run your app (&lt;code&gt;start&lt;/code&gt;, or &lt;code&gt;dev&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucaxttgcozeckb2734hx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucaxttgcozeckb2734hx.jpg" alt="debug output" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To open the debug controls in your codespace, choose &lt;strong&gt;View: Show Run and Debug&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4l9whizdj9nis98zclv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4l9whizdj9nis98zclv.png" alt="debug prompt" width="800" height="110"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Run and Debug&lt;/strong&gt;, choosing &lt;code&gt;Node.js&lt;/code&gt;. Watch the &lt;strong&gt;Debug console&lt;/strong&gt; for output. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febhwkcat22g7fhr152lj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febhwkcat22g7fhr152lj.png" alt="debug view" width="798" height="702"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To try the &lt;strong&gt;JavaScript Debug Terminal&lt;/strong&gt;, click the button then run your npm command to start the app again. For best results you'll want to dig into your code and add breakpoints to use in your debugging flow.&lt;/p&gt;

&lt;p&gt;Debugging is a whole skillset in itself! There are also lots of extensions you can install in your codespace to help you debug your app. Check out these VS Code tutorials for more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/docs/introvideos/debugging" rel="noopener noreferrer"&gt;Debugging in Visual Studio Code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/docs/debugtest/debugging" rel="noopener noreferrer"&gt;Debug code with Visual Studio Code&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get help 🛟
&lt;/h2&gt;

&lt;p&gt;Here’s the thing, learning to code is something you’ll do best with help. There are lots of resources and communities online. Here are a few pointers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the platform you used to generate your app have a community? Post in there!
&lt;/li&gt;
&lt;li&gt;Which frameworks is your app using? They most likely have dedicated community spaces online you can connect to.
&lt;/li&gt;
&lt;li&gt;There are also great developer and learning communities, like here on DEV, and over on &lt;a href="https://www.freecodecamp.org/" rel="noopener noreferrer"&gt;freeCodeCamp&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you get really stuck, need your app finished, and have the budget – hire a freelance developer to help you with it!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📻 Later in this series we'll get into learning about your app logic, which will most likely be written in JavaScript or TypeScript if the steps in this tutorial worked for you.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>llm</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>We should still teach coding</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Mon, 31 Mar 2025 13:28:22 +0000</pubDate>
      <link>https://forem.com/fastly/we-should-still-teach-coding-3cjh</link>
      <guid>https://forem.com/fastly/we-should-still-teach-coding-3cjh</guid>
      <description>&lt;p&gt;Software written using generative AI is all over the web. Performance and security issues abound. Open source projects are being &lt;a href="https://arstechnica.com/ai/2025/03/devs-say-ai-crawlers-dominate-traffic-forcing-blocks-on-entire-countries/" rel="noopener noreferrer"&gt;overwhelmed by bot traffic&lt;/a&gt;. There's a lot of harm being caused, but as an educator who cares about lowering barriers to software creation, I can't ignore the &lt;a href="https://dev.to/glitch/what-is-worth-learning-41e3"&gt;democratizing potential&lt;/a&gt; of these tools either.&lt;/p&gt;

&lt;p&gt;In this post I’d like to explore the opportunities for learning that this paradigm shift presents – from how to make your projects &lt;a href="https://www.fastly.com/products/ai" rel="noopener noreferrer"&gt;more efficient&lt;/a&gt; and &lt;a href="https://www.fastly.com/products/ddos-protection" rel="noopener noreferrer"&gt;secure&lt;/a&gt;, to learning about the &lt;a href="https://hbr.org/2023/04/generative-ai-has-an-intellectual-property-problem" rel="noopener noreferrer"&gt;intellectual property&lt;/a&gt; and &lt;a href="https://www.technologyreview.com/2022/04/20/1050392/ai-industry-appen-scale-data-labels/" rel="noopener noreferrer"&gt;labor exploitation&lt;/a&gt; that might have gone into training the models you used.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding incentives
&lt;/h2&gt;

&lt;p&gt;One thing I have learned working in education is the value of accepting people’s motivations – having a goal that a skill will help you achieve is the most effective motivator for learning. Clearly many people are finding ways to use AI to help them achieve goals.&lt;/p&gt;

&lt;p&gt;Motivations are determined by complex socioeconomic factors beyond our ability to reason away. Let’s instead keep the door to the good internet open by empowering people to make responsible choices, equipping them with knowledge of the technical systems they’re creating within. &lt;/p&gt;

&lt;p&gt;Gen AI might &lt;a href="https://techcrunch.com/2025/03/06/a-quarter-of-startups-in-ycs-current-cohort-have-codebases-that-are-almost-entirely-ai-generated/" rel="noopener noreferrer"&gt;help you spin up an MVP&lt;/a&gt;, but eventually you will have to dig into the code. You’ll either learn software engineering skills, or have to bring in the experts. Far from making engineers obsolete, I worry that less investment in these skills will make the barriers around the profession more extreme. &lt;strong&gt;&lt;em&gt;A select few having insight into how critical systems work is not a future I’m enthusiastic about.&lt;/em&gt;&lt;/strong&gt; Instead I’d like to find learning paths that these new ways of building software present.&lt;/p&gt;

&lt;h2&gt;
  
  
  The conditions for learning are in place
&lt;/h2&gt;

&lt;p&gt;Projects developed using gen AI can support a range of good practices in education, including some key activities that we often neglect in both formal learning and the workplace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Personalization&lt;/strong&gt;: We can work on something meaningful to the learner rather than dragging them through a one-size-fits-all experience.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast feedback loops&lt;/strong&gt;: Automation can fuel adaptive learning through short iterative cycles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflection&lt;/strong&gt;: Reflecting on an experience helps you internalize skills you’ve acquired and reapply them in different contexts. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code generated using LLMs enables and requires these perhaps more than “traditional” ways of making software. There are also some &lt;a href="https://teachcomputing.org/pedagogy" rel="noopener noreferrer"&gt;coding pedagogy techniques&lt;/a&gt; that gen AI projects can lend themselves to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reading before writing&lt;/strong&gt; – code comprehension is a crucial software engineering skill, consider an experienced engineer performing code reviews and mentoring junior teammates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starting from a functioning application&lt;/strong&gt; instead of a blank slate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Running&lt;/strong&gt; an app to see what it does, then &lt;strong&gt;investigating&lt;/strong&gt; how it did it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Taking gradual ownership&lt;/strong&gt; of a project by making a first edit, then turning it into something new.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Generative AI is not an appropriate substitute for the many interpersonal aspects of effective learning IMO. “Mentoring” powered by &lt;a href="https://hai.stanford.edu/news/covert-racism-ai-how-language-models-are-reinforcing-outdated-stereotypes" rel="noopener noreferrer"&gt;biased LLM content&lt;/a&gt; is incredibly dangerous.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Encouraging inquiry and independent thought
&lt;/h2&gt;

&lt;p&gt;I wonder about a gen AI coding exercise that gives you a broken project to fix, or prompts you to explore where the code came from – this kind of inquiry is being used in the humanities to support the development of &lt;a href="https://www.cambridge.org/elt/blog/2023/03/30/enhancing-learners-critical-thinking-skills-with-ai-assisted-technology/" rel="noopener noreferrer"&gt;critical thinking skills&lt;/a&gt;, &lt;em&gt;especially important since these tools might by default &lt;a href="https://www.microsoft.com/en-us/research/publication/the-impact-of-generative-ai-on-critical-thinking-self-reported-reductions-in-cognitive-effort-and-confidence-effects-from-a-survey-of-knowledge-workers/" rel="noopener noreferrer"&gt;erode those very skills&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Then we have the wealth of problems that arise when people deploy applications with little to no understanding of their implementation. What happens over the long term, what happens if your project becomes a &lt;em&gt;real thing&lt;/em&gt; people depend on, what happens when it breaks, what happens when it causes harm, how do we navigate the obfuscation of accountability? These are learning opportunities we’ll embrace if we want people to make more informed choices about how they use technology.&lt;/p&gt;

&lt;p&gt;Software engineering is a very privileged profession, largely because it requires access to education. &lt;a href="https://simonwillison.net/2025/Mar/19/vibe-coding/" rel="noopener noreferrer"&gt;Vibe coding&lt;/a&gt; creates new paths into building with tech. The starting point may be different, but we might even manage to invite more people into the spaces where we shape the future of the web.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Learn how &lt;a href="https://www.fastly.com/blog/ai-innovation-sustainability-key-takeaways-from-ai-action-summit" rel="noopener noreferrer"&gt;Fastly is making AI more sustainable&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Cover image is &lt;a href="https://publicdomainreview.org/collection/march-of-the-intellect/" rel="noopener noreferrer"&gt;The March of Intellect&lt;/a&gt; by Robert Seymour.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>webdev</category>
      <category>learning</category>
    </item>
    <item>
      <title>Enhance an 11ty site at the edge</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Fri, 21 Mar 2025 14:01:26 +0000</pubDate>
      <link>https://forem.com/fastly/enhance-an-11ty-site-at-the-edge-5cgc</link>
      <guid>https://forem.com/fastly/enhance-an-11ty-site-at-the-edge-5cgc</guid>
      <description>&lt;p&gt;In this post we're going to customize the UX in an &lt;a href="https://www.11ty.dev/" rel="noopener noreferrer"&gt;Eleventy&lt;/a&gt; site with a &lt;a href="https://www.fastly.com/documentation/solutions/tutorials/enhance-ux/" rel="noopener noreferrer"&gt;Compute app&lt;/a&gt; running on the Fastly network at locations near your users around the world. We'll use the &lt;a href="https://glitchdotcom.github.io/my-site/" rel="noopener noreferrer"&gt;Eleventy Base Blog deployed to GitHub Pages&lt;/a&gt;, with some tweaks to its RSS feed to let us do some fun stuff at the edge. We'll write a JavaScript app that we'll compile into Web Assembly (Wasm) that can run securely on the Fastly network.&lt;/p&gt;

&lt;h2&gt;
  
  
  The website and feed
&lt;/h2&gt;

&lt;p&gt;Eleventy (11ty) generates your website in the form of a bunch of HTML files and some CSS. This makes it a super fast, performant experience for the user – it also makes it perfect for playing with edge computing. You can do lots of cool things with 11ty plugins, like exposing an RSS feed of the posts in your site. We'll set our feed to return JSON so that we can mess with the data at the edge before sending it back to the user. &lt;/p&gt;

&lt;h2&gt;
  
  
  Set up your site
&lt;/h2&gt;

&lt;p&gt;Our fork of the Eleventy Base Blog &lt;a href="https://github.com/glitchdotcom/my-site/blob/d93a9d99d1fd5922a970adca585ada62385fb5e8/eleventy.config.js#L50" rel="noopener noreferrer"&gt;includes a change&lt;/a&gt; in &lt;code&gt;eleventy.config.js&lt;/code&gt; to make the feed return JSON instead of the Atom format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwya5ht1pfemcmtzmqror.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwya5ht1pfemcmtzmqror.png" alt="The GitHub diff in the eleventy config" width="800" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use the example site for your Compute app if you like, but later in this series we'll also try editing the site in conjunction with our edge functionality, so fork your own copy if you plan to follow along:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/glitchdotcom/my-site" rel="noopener noreferrer"&gt;Fork the repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow the steps in the &lt;code&gt;README&lt;/code&gt; to edit and deploy to GitHub Pages – tl;dr:

&lt;ul&gt;
&lt;li&gt;Edit the &lt;code&gt;eleventy.config.js&lt;/code&gt; &lt;code&gt;feedPlugin&lt;/code&gt; section to set &lt;code&gt;metadata&lt;/code&gt; &lt;code&gt;base&lt;/code&gt; to your own GitHub IO domain&lt;/li&gt;
&lt;li&gt;Change the references to &lt;code&gt;my-site&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt; to your repo name&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;.github/workflows/gh-pages.yml.sample&lt;/code&gt; to &lt;code&gt;.github/workflows/gh-pages.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;gh-pages&lt;/code&gt; branch&lt;/li&gt;
&lt;li&gt;In your repo &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Pages&lt;/strong&gt; section, choose &lt;strong&gt;Deploy from a branch&lt;/strong&gt; and select &lt;code&gt;gh-pages&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Watch the &lt;strong&gt;Actions&lt;/strong&gt; for your deploy status&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Grab the URL for your new site, as you'll need it in your Compute setup.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up your Fastly account
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.fastly.com/signup" rel="noopener noreferrer"&gt;Sign up for a free Fastly account&lt;/a&gt; if you haven't already.&lt;/p&gt;

&lt;p&gt;Grab an API token from your account:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Account&lt;/strong&gt; &amp;gt; &lt;strong&gt;API tokens&lt;/strong&gt; &amp;gt; &lt;a href="https://manage.fastly.com/account/personal/tokens" rel="noopener noreferrer"&gt;&lt;strong&gt;Personal tokens&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Token&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; anything you like&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type:&lt;/strong&gt; Automation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role:&lt;/strong&gt; Engineer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope:&lt;/strong&gt; Global (deselect the Read-only access box)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access:&lt;/strong&gt; All services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiration:&lt;/strong&gt; Never expire&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Copy the token value and save it on your computer&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Set up your developer environment
&lt;/h2&gt;

&lt;p&gt;We'll use the Fastly CLI to spin up a Compute service, so get it installed on your computer:&lt;/p&gt;

&lt;p&gt;Create a new 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="nb"&gt;mkdir &lt;/span&gt;11ty-edge &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;11ty-edge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the Fastly CLI – &lt;a href="https://www.fastly.com/documentation/reference/tools/cli/" rel="noopener noreferrer"&gt;see the docs if you aren't using NPM&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;  npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @fastly/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a Fastly profile, entering the API token you copied from your account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  fastly profile create 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start a Compute app
&lt;/h2&gt;

&lt;p&gt;We're going to use &lt;a href="https://expressly.edgecompute.app/docs/intro" rel="noopener noreferrer"&gt;Expressly&lt;/a&gt;, which lets us build our Compute app using a similar structure to Node.js server frameworks like Express. We'll listen for user requests, manipulating the request and response we send back to the user.&lt;/p&gt;

&lt;p&gt;Initialize your Compute app using the Expressly starter kit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  fastly compute init &lt;span class="nt"&gt;--from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://github.com/fastly/compute-starter-kit-javascript-expressly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can set the name, description, and author if you like, or accept the defaults.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Include &lt;code&gt;--accept-defaults&lt;/code&gt; with your Fastly commands if you don't want to respond to every prompt.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Run &lt;code&gt;npm install&lt;/code&gt; when prompted.&lt;/p&gt;

&lt;p&gt;Check your app is installed correctly by running it locally and opening it in your browser:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rl1y40aqf4v8qkkvifm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3rl1y40aqf4v8qkkvifm.jpg" alt="The app running locally" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The local site will just return &lt;code&gt;OK&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explore the app
&lt;/h2&gt;

&lt;p&gt;Take a minute to explore the files in the Compute app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85vcjbldxily2i3rarn1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85vcjbldxily2i3rarn1.png" alt="Compute logic in JS" width="800" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;src/index.js&lt;/code&gt; file contains our Compute logic including the Expressly routing structures&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;fastly.toml&lt;/code&gt; file contains our app setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll be making changes to both of these files, and the Fastly tooling will change the TOML when we deploy our app.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 The &lt;code&gt;bin&lt;/code&gt; and &lt;code&gt;pkg&lt;/code&gt; directories include the compiled assets the CLI will use to deploy your app to Fastly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Set up your origin
&lt;/h2&gt;

&lt;p&gt;At the moment the app doesn't do much, it just returns a default response to the user. Let's get it to return the response from our 11ty website.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;fastly.toml&lt;/code&gt; and add the following at the end of the file, changing the domain to your own GitHub IO subdomain if you're using your own version of the site deployed to GitHub Pages:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[setup]

  [setup.backends]

    [setup.backends.blog]
      address = "glitchdotcom.github.io"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;src/index.js&lt;/code&gt;, add a variable near the top of the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;backendResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the &lt;code&gt;router.use&lt;/code&gt; function to fetch the response from the origin site, making it &lt;code&gt;async&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="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-powered-by&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;expressly&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;backendResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We set the &lt;code&gt;blog&lt;/code&gt; backend in the TOML, so Fastly will make the request to our origin website.&lt;/p&gt;

&lt;p&gt;Delete the &lt;code&gt;router.get('/'...&lt;/code&gt; and &lt;code&gt;router.post("/submit"&lt;/code&gt; functions, replacing them with one to respond to all requests with the response from the origin site:&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="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&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="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;backendResponse&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;Your script should now look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// &amp;lt;reference types="@fastly/js-compute" /&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@fastly/expressly&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;backendResponse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-powered-by&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;expressly&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;backendResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&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="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;backendResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy your app
&lt;/h2&gt;

&lt;p&gt;In the terminal, exit from your local server with &lt;code&gt;CTRL+C&lt;/code&gt; if necessary. Run the deploy command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Let the CLI create a new service, accepting the default options or changing any you like. The tooling will build and compile your app, upload the package to Fastly, and activate the service it's attached to. When it's ready, you'll see an &lt;code&gt;edgecompute.app&lt;/code&gt; address in the terminal output – open it in your browser, adding the path for your GitHub repo name (&lt;code&gt;my-site&lt;/code&gt; if you're using the example), like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://informally-one-shrimp.edgecompute.app/my-site/" rel="noopener noreferrer"&gt;informally-one-shrimp.edgecompute.app/my-site/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwbhq2tqg0qvh06mfc1d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwbhq2tqg0qvh06mfc1d.png" alt="Deployed app in IDE" width="800" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Right now all the app will do is return the response from the origin website, but we're going to change the behavior for certain requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiikxbd5d2umk7lx1le7v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiikxbd5d2umk7lx1le7v.png" alt="Site deployed in browser" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a synthetic feed page
&lt;/h2&gt;

&lt;p&gt;Click the &lt;strong&gt;Feed&lt;/strong&gt; link in the site header for your deployed app (at the &lt;code&gt;edgecompute.app&lt;/code&gt; address – it just returns a JSON list of the posts in the site, which is &lt;a href="https://glitchdotcom.github.io/my-site/feed/feed.json" rel="noopener noreferrer"&gt;what we get from the origin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0kv5cadzk5odrimkasz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0kv5cadzk5odrimkasz.png" alt="JSON feed" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's turn this into a page. Back in your app, in the &lt;code&gt;src/index.js&lt;/code&gt; file, add a new variable near the top of the script, changing the value to the name of your forked 11ty repo if you're using your own version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/my-site/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//change to your repo name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a new endpoint &lt;strong&gt;before&lt;/strong&gt; the &lt;code&gt;router.all("(.*)"&lt;/code&gt; section:&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="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;feed/feed.json`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;originData&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;backendResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;``&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// change to your repo name&lt;/span&gt;
  &lt;span class="k"&gt;for &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;pst&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;originData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date_published&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDateString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;linkUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;p&amp;gt;&amp;lt;a href="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;linkUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&amp;lt;strong&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt; – &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;!DOCTYPE html&amp;gt;
  &amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
      &amp;lt;meta charset="UTF-8"&amp;gt;
      &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1" /&amp;gt;
      &amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;originData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; – Feed 🗞️&amp;lt;/title&amp;gt;
      &amp;lt;!-- 🚧 Change CSS location to suit your site 🚧 --&amp;gt;
      &amp;lt;link rel="stylesheet" href="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;css/index.css"/&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
      &amp;lt;header&amp;gt;&amp;lt;a class="home-link" href="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;My Website&amp;lt;/a&amp;gt;&amp;lt;/header&amp;gt;
      &amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;originData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; – Feed 🗞️&amp;lt;/h2&amp;gt;
      &amp;lt;div&amp;gt;&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="s2"&gt;&amp;lt;/div&amp;gt;
    &amp;lt;/body&amp;gt;
  &amp;lt;/html&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;backendResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code parses the JSON feed response and builds it into HTML.&lt;/p&gt;

&lt;p&gt;Deploy your app again:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;It may take a minute or so for your changes to update, but when your new service version is up, open the feed page again at the &lt;code&gt;edgecompute.app&lt;/code&gt; address, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://informally-one-shrimp.edgecompute.app/my-site/feed/feed.json" rel="noopener noreferrer"&gt;informally-one-shrimp.edgecompute.app/my-site/feed/feed.json&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjp4gs7kcntaksenib2yk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjp4gs7kcntaksenib2yk.png" alt="Site feed" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we have a web page instead of the JSON data... 🎉&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🧰 You can access a complete example of the app code in the &lt;a href="https://github.com/glitchdotcom/11ty-feed" rel="noopener noreferrer"&gt;11ty-feed&lt;/a&gt; starter kit and &lt;a href="https://fiddle.fastly.dev/fiddle/dae9ad2b" rel="noopener noreferrer"&gt;Fiddle&lt;/a&gt; if you want to try running the code in the browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;⏳ Stay tuned for the next part of the series we'll add some edge data to the functionality – we can access information about the user, like their location, so we'll build that into our app processing to customize the site behavior.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;In the meantime, check out how you can &lt;a href="https://www.fastly.com/documentation/solutions/tutorials/kv-hit-counter/" rel="noopener noreferrer"&gt;build edge data into your apps&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>serverless</category>
      <category>11ty</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Get edge certified with new Fastly credentials</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Tue, 17 Dec 2024 16:01:18 +0000</pubDate>
      <link>https://forem.com/fastly/get-edge-certified-with-new-fastly-credentials-409m</link>
      <guid>https://forem.com/fastly/get-edge-certified-with-new-fastly-credentials-409m</guid>
      <description>&lt;p&gt;Whatever path you took into tech, continuous learning and development will always help keep your career moving in the right direction. Also, learning is fun! Our new &lt;strong&gt;Edge Computing 101&lt;/strong&gt; badge recognizes learners who successfully set up a Fastly Compute service that carries out a little bit of processing on a website at the network edge. The best part is that it's completely free, and you can follow the steps to achieve it inside an interactive Glitch project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR &lt;a href="https://glitch.com/~learn-edge-computing" rel="noopener noreferrer"&gt;Jump over to Glitch and earn your Edge Computing 101 badge&lt;/a&gt;&lt;/strong&gt; 🎏🏅&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr79062gfmgfctltbrd8g.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr79062gfmgfctltbrd8g.jpg" alt="Learning in the Glitch editor" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We've spent part of 2024 building Fastly's first developer certification program. We initially trialed our new credentials as part of employee training, with coworkers from all over the company successfully completing the steps to get up to speed with the edge. We made the certification available for public use recently, with community members earning their badges and giving us valuable feedback on the experience. We're now ready for more of you to get stuck in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why learn about edge computing?
&lt;/h2&gt;

&lt;p&gt;Edge computing is used by many of the biggest sites on the web, so these skills are valued by employers and organizations working on large scale applications with emergent technologies. Fastly Compute is an edge computing platform that enables you to make instant experiences at global scale – we've barely scratched the surface of what this technology can do. Edge engineering knowhow is still pretty rare, so if you want to get ahead of where the web is going, this is it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📚 &lt;strong&gt;&lt;a href="https://dev.to/fastly/an-easy-intro-to-edge-computing-3ced"&gt;Learn what the edge is all about in our edge computing intro series!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Fastly Edge Computing 101 badge
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndbgzo6tdb5d8zrv77ek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndbgzo6tdb5d8zrv77ek.png" alt="Fastly certification – edge computing 101" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;a href="https://badgr.com/public/badges/lTLmpCg4QRuMXvk0iKmqfQ" rel="noopener noreferrer"&gt;Edge Computing 101 badge&lt;/a&gt;&lt;/strong&gt; is an intro level certification – it's easy to earn! You'll submit the link to a Glitch website you remixed, and a Fastly deployed app that changes the UX for the site at the edge. You don't need any prior knowledge to complete the steps – the app uses some JavaScript, but you'll be able to grab example code from the docs inside the project. Building at the edge is a lot easier than you might think!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1euc9de0zwevkborljsi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1euc9de0zwevkborljsi.png" alt="Three states of the app" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to get into edge computing for the web more deeply, we'll have you covered later in 2025 when we extend this program to support more intermediate and advanced learning, so stay tuned if that's you.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to earn your certification
&lt;/h2&gt;

&lt;p&gt;You'll need (free) accounts on both Fastly and Glitch – if you already have them, sign in, otherwise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fastly.com/signup" rel="noopener noreferrer"&gt;Sign up for a Fastly developer account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://glitch.com/signup" rel="noopener noreferrer"&gt;Sign up for a Glitch account&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get your hands on your &lt;strong&gt;Edge Computing 101&lt;/strong&gt; badge, just remix the project and jump in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://glitch.com/~learn-edge-computing" rel="noopener noreferrer"&gt;~learn-edge-computing&lt;/a&gt;&lt;/strong&gt; 🎒🏆&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;README&lt;/code&gt; will guide you through the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You'll set up your Fastly account and grab an API key&lt;/li&gt;
&lt;li&gt;With your API key in your Glitch project, you'll deploy an edge app to Fastly Compute&lt;/li&gt;
&lt;li&gt;The Glitch project contains both the website code and the edge app code, but unlike the website which you can preview immediately inside Glitch, you'll need to deploy each time you want to publish a change to your Compute code&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;README&lt;/code&gt; includes an example edit you'll make to extend the Compute code and deploy again to see the changes&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;You'll find more info in our &lt;a href="https://dev.to/fastly/build-your-own-edge-computing-app-3cp2"&gt;tutorial on building your own edge computing app&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your Compute app sits between the user and your website, so it can manipulate the request and response. The example app will enhance the behavior of the site at the network edge, personalizing the display using geolocation information. It'll pass data back to the browser with the response to the user, where the client side code will write the info into the page HTML.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9tonk4edv0b04xv6hls.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9tonk4edv0b04xv6hls.jpg" alt="A request and response through Compute" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll find the link to submit your badge application at the end of the &lt;code&gt;README&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We'll aim to process your submission within 2-3 weeks.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🎓 We're using the &lt;a href="https://badgr.com/public/issuers/q9tiJ_k1QtaBdwbMmdk3mg/badges" rel="noopener noreferrer"&gt;Badgr&lt;/a&gt; platform for these credentials. Badgr supports &lt;a href="https://openbadges.org/" rel="noopener noreferrer"&gt;Open Badges&lt;/a&gt;, an open source credentialing standard. This will let us build out our learning program to issue badges, and many platforms around the web integrate with Open Badges, so you can &lt;a href="https://community.canvaslms.com/t5/Canvas-Badges-Credentials/How-do-I-share-my-earned-badges-from-my-Canvas-Badges-Backpack/ta-p/528659" rel="noopener noreferrer"&gt;share yours on networks like LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to get support
&lt;/h2&gt;

&lt;p&gt;If you get stuck, want to give feedback, or just connect to others who are also learning about the edge – &lt;a href="https://community.fastly.com/c/compute/6" rel="noopener noreferrer"&gt;pop into the Fastly forum&lt;/a&gt; where team and community members are around to help. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;🎄 Responses will be a little slower than normal over the festive season.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready for more?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7dynx0umppivp0a4zn6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7dynx0umppivp0a4zn6.png" alt="Fastly Compute starter app on Glitch" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're ready to extend your Compute proficiency, check out the &lt;a href="https://glitch.com/~fastly-compute-starter" rel="noopener noreferrer"&gt;~fastly-compute-starter&lt;/a&gt; project, which does a little more processing at the edge. You can also follow along with our &lt;a href="https://www.fastly.com/documentation/solutions/tutorials/enhance-ux/" rel="noopener noreferrer"&gt;video and tutorial on enhancing your site UX in the Fastly docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show off your badges! 📣
&lt;/h2&gt;

&lt;p&gt;Don't keep quiet about your learning achievements, boast about your expertise – humility is a scam! Share your badges on your social networks, link to them in the comments, post them in the forums, tell the world!&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>webdev</category>
      <category>certification</category>
      <category>career</category>
    </item>
    <item>
      <title>Autopost to Bluesky and Mastodon by API</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Fri, 13 Dec 2024 16:14:14 +0000</pubDate>
      <link>https://forem.com/glitch/autopost-to-bluesky-and-mastodon-by-api-500d</link>
      <guid>https://forem.com/glitch/autopost-to-bluesky-and-mastodon-by-api-500d</guid>
      <description>&lt;p&gt;Last time we learned how to &lt;a href="https://dev.to/glitch/verify-your-bluesky-or-mastodon-account-on-your-own-domain-with-a-free-website-1jfn"&gt;verify our accounts using a domain&lt;/a&gt; with a free Glitch website – this time let's set up a simple app to crosspost some automated content to Bluesky and Mastodon using their APIs.&lt;/p&gt;

&lt;p&gt;We'll set up developer credentials for both platforms, pop them into Glitch, and post some daft text including random emoji. We'll also discover a more complex example that posts links and images, in case you want to continue building!&lt;/p&gt;

&lt;h2&gt;
  
  
  Remix the Glitch project
&lt;/h2&gt;

&lt;p&gt;We're using a Glitch project with a lot of the code setup already so go ahead and &lt;strong&gt;remix&lt;/strong&gt; it to get your own copy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://glitch.com/~social-poster" rel="noopener noreferrer"&gt;~social-poster&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Glitch project hosting shuts down on 8th July 2025 so you won't be able to remix this project anymore – you can find the &lt;a href="https://github.com/glitchdotcom/social-poster" rel="noopener noreferrer"&gt;source code on Github&lt;/a&gt; if you'd like to deploy it somewhere else!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The app uses &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; and &lt;a href="https://axios-http.com/docs/intro" rel="noopener noreferrer"&gt;Axios&lt;/a&gt; to make connections to the Bluesky and Mastodon APIs, but don't worry if you aren't familiar with these frameworks, you'll be able to pop in your details and get postin' easily!&lt;/p&gt;

&lt;p&gt;If you like you can take a minute to browse the project. There are instructions in the &lt;code&gt;README&lt;/code&gt; as well. We'll mainly be working in these files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; where we include our credentials&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/client.js&lt;/code&gt; where we connect to the APIs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;server.js&lt;/code&gt; where we call our client methods and manage scheduling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The content we post by default is in the &lt;code&gt;postTxt&lt;/code&gt; variable in &lt;code&gt;src/client.js&lt;/code&gt; so change it if you want to post something different – the code initially only supports plain text content, but you'll find detail on posting media below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgcuk6cokka2cyum9a4ty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgcuk6cokka2cyum9a4ty.png" alt="The default text content in a variable" width="800" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These example posts demonstrate the default content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mastodon.social/@suewtf/113644869914130623" rel="noopener noreferrer"&gt;https://mastodon.social/@suewtf/113644869914130623&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bsky.app/profile/www.sue.wtf/post/3ld6oulfqg72z" rel="noopener noreferrer"&gt;https://bsky.app/profile/www.sue.wtf/post/3ld6oulfqg72z&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get your developer credentials
&lt;/h2&gt;

&lt;p&gt;To post from somewhere outside the official Bluesky and Mastodon apps, we're going to use the APIs. APIs are interfaces platforms provide to allow you to access their features using code. In order to gain this access, we'll need to authenticate with both platforms – this keeps the user data on the apps and websites we use safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bluesky app setup
&lt;/h3&gt;

&lt;p&gt;For Bluesky, we need an app password for the account we want to post to. In your Bluesky account, navigate to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Privacy and Security&lt;/strong&gt; &amp;gt; &lt;strong&gt;App Passwords&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfhrz3rfyb45qacmzc5y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfhrz3rfyb45qacmzc5y.jpg" alt="Bluesky app password screen" width="800" height="1800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Add app password&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter a &lt;strong&gt;Name&lt;/strong&gt; for your app password, like "Glitch poster"&lt;/li&gt;
&lt;li&gt;Copy the password and click &lt;strong&gt;Done&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Paste the password into your Glitch remix in the &lt;code&gt;.env&lt;/code&gt; file as the &lt;code&gt;APP_PASSWORD&lt;/code&gt; variable&lt;/li&gt;
&lt;li&gt;While you're in the &lt;code&gt;.env&lt;/code&gt;, enter the handle for the Bluesky account you want to post to &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjhtdlj0c1e6rtvwdmdy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjhtdlj0c1e6rtvwdmdy.jpg" alt="Glitch env with app password and handle" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Mastodon app setup
&lt;/h3&gt;

&lt;p&gt;For Mastodon, you'll need a token to authenticate your requests. Log into your account (you'll need to be in a browser rather than a mobile app). Navigate to &lt;strong&gt;Preferences&lt;/strong&gt; &amp;gt; &lt;strong&gt;Development&lt;/strong&gt;, and click &lt;strong&gt;New application&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give your application a &lt;strong&gt;name&lt;/strong&gt;, like "Glitch poster"&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;Application website&lt;/strong&gt;, include the URL of your Glitch website, which will end &lt;code&gt;.glitch.me&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Leave the &lt;strong&gt;Redirect URI&lt;/strong&gt; with the default content&lt;/li&gt;
&lt;li&gt;For scopes, make sure you check &lt;code&gt;write:statuses&lt;/code&gt; and &lt;code&gt;write:media&lt;/code&gt; if you want to be able to post images&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit&lt;/strong&gt; your application&lt;/li&gt;
&lt;li&gt;Copy the value of &lt;strong&gt;Your access token&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Paste it into your Glitch project &lt;code&gt;.env&lt;/code&gt; as the &lt;code&gt;MASTODON_TOKEN&lt;/code&gt; variable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00nsznmptc8peseugbwb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00nsznmptc8peseugbwb.jpg" alt="Mastodon app" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk45xhno8cg5pwsewfxla.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk45xhno8cg5pwsewfxla.jpg" alt="Mastodon scopes" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 You can also add your Glitch website as a verified link in your Mastodon profile – include a link in &lt;code&gt;index.html&lt;/code&gt; back to the Mastodon account, with &lt;code&gt;rel="me"&lt;/code&gt; in the anchor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgq7s7srhvu0s3unvd7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgq7s7srhvu0s3unvd7y.png" alt="My verified link" width="800" height="398"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahbd7iho4kd296215bg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahbd7iho4kd296215bg4.png" alt="Verified in Mastodon" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In your Mastodon account, it's also a good idea to check &lt;strong&gt;This is a bot account&lt;/strong&gt; in &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Profile&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Post!
&lt;/h2&gt;

&lt;p&gt;That should be you all set to post! Your Glitch remix includes code to run the posting on a schedule, but you can also post manually. In the preview, click into the address bar and enter one of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;postBsky&lt;/code&gt; to post only to Bluesky&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;postMasto&lt;/code&gt; for Mastodon only&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;postAll&lt;/code&gt; for both&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the &lt;strong&gt;Logs&lt;/strong&gt; to find any details or errors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Free8adx5ca96xp54fh43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Free8adx5ca96xp54fh43.png" alt="Post output" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check your accounts to find the posts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsylyee5i2254ii23eanj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsylyee5i2254ii23eanj.png" alt="Bluesky post" width="800" height="274"&gt;&lt;/a&gt;&lt;em&gt;Examples posts on Bluesky&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpv74bswaqn2u2bhfrmo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpv74bswaqn2u2bhfrmo.png" alt="Masto post" width="800" height="429"&gt;&lt;/a&gt;&lt;em&gt;Example posts on Mastodon&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Check out the code
&lt;/h3&gt;

&lt;p&gt;The code for Bluesky and Mastodon is slightly different, so let's break it down so that you can tweak and use it elsewhere. We'll be exploring &lt;code&gt;src/client.js&lt;/code&gt; for the API connections.&lt;/p&gt;

&lt;p&gt;For Bluesky, we need to start a session and save the token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&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;bskyClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/com.atproto.server.createSession&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HANDLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APP_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;bskyToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessJwt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then use the token in subsequent requests. Next we post the post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;bskyClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/com.atproto.repo.createRecord&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HANDLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app.bsky.feed.post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app.bsky.feed.post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;postText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;bskyToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;It's a bit more complicated if you need more than plain text – to include links you need &lt;a href="https://docs.bsky.app/docs/advanced-guides/posts#mentions-and-links" rel="noopener noreferrer"&gt;facets&lt;/a&gt;, and to include media you need &lt;a href="https://docs.bsky.app/docs/advanced-guides/posts#images-embeds" rel="noopener noreferrer"&gt;embeds&lt;/a&gt;. You'll find examples of both in &lt;strong&gt;&lt;a href="https://glitch.com/~wtf-poster" rel="noopener noreferrer"&gt;~wtf-poster&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For Mastodon we need just one request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;postText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postResponse&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;mastoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/v1/statuses&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;mastoToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Mastodon handles links automatically, but you'll need more processing if you want to upload images – the &lt;a href="https://docs.joinmastodon.org/methods/media/#v2" rel="noopener noreferrer"&gt;media&lt;/a&gt; endpoints let you add and link to uploaded files. Check out &lt;strong&gt;&lt;a href="https://glitch.com/~wtf-poster" rel="noopener noreferrer"&gt;~wtf-poster&lt;/a&gt;&lt;/strong&gt; for an example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Schedule posts
&lt;/h2&gt;

&lt;p&gt;In your Glitch project &lt;code&gt;server.js&lt;/code&gt; file, you'll find scheduling code around line 25. Uncomment the code out if you want your account to post automatically on a schedule – you can tweak the timing!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ready for more automation? Remix or copy from &lt;strong&gt;&lt;a href="https://glitch.com/~wtf-poster" rel="noopener noreferrer"&gt;~wtf-poster&lt;/a&gt;&lt;/strong&gt; to post links, images, and content from a third party API... 🎢🎡🛸&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🪩🛼🌈 &lt;a href="https://support.glitch.com" rel="noopener noreferrer"&gt;Share your cool autoposters in the Glitch forum!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>socialmedia</category>
      <category>api</category>
      <category>node</category>
    </item>
    <item>
      <title>Verify your Bluesky or Mastodon account on your own domain, with a free website!</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Tue, 03 Dec 2024 17:46:38 +0000</pubDate>
      <link>https://forem.com/glitch/verify-your-bluesky-or-mastodon-account-on-your-own-domain-with-a-free-website-1jfn</link>
      <guid>https://forem.com/glitch/verify-your-bluesky-or-mastodon-account-on-your-own-domain-with-a-free-website-1jfn</guid>
      <description>&lt;p&gt;Setting up your own domain for a website and social media is easier than you might think! I love domains, I have a few pointing at Glitch sites and in my social profiles. In this post I'm going to run through setting up another website and domain, and add it to Bluesky as a handle for a new account, and Mastodon as a verified link.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grab a Glitch remix
&lt;/h2&gt;

&lt;p&gt;We're going to make a website in a few minutes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remix &lt;a href="https://glitch.com/~my-social-website" rel="noopener noreferrer"&gt;~my-social-website!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Glitch project hosting shuts down on 8th July 2025 so you won't be able to remix this website anymore – you can find the &lt;a href="https://github.com/glitchdotcom/my-social-website" rel="noopener noreferrer"&gt;source code on GitHub&lt;/a&gt; if you'd like to deploy it somewhere else!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The project will open in the Glitch editor. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Preview&lt;/strong&gt; at the bottom and &lt;strong&gt;Open preview pane&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;That's your new website! It's already on the web at &lt;code&gt;your-project-name.glitch.me&lt;/code&gt; – you'll find the link above the preview.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can make changes now or later, but personalizing the site literally takes minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky95v2rkfb4p9ryn09wh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky95v2rkfb4p9ryn09wh.jpg" alt="My Glitch project" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;index.html&lt;/code&gt; to change the content of the page.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit the heading in the &lt;code&gt;h1&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;Add text to display in the page like the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; content.&lt;/li&gt;
&lt;li&gt;Add other content like images and links – check out the tips in the HTML..!&lt;/li&gt;
&lt;li&gt;Change the site style in &lt;code&gt;style.css&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you like you can change your Glitch project name in &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Edit project details&lt;/strong&gt; which will change your site address on Glitch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can keep going in your Glitch project or come back to it later – it's a lot of fun!&lt;/p&gt;

&lt;h2&gt;
  
  
  Get a domain
&lt;/h2&gt;

&lt;p&gt;Here's the thing, you could just use your &lt;code&gt;.glitch.me&lt;/code&gt; website address as your handle and verified link on both Bluesky and Mastodon, &lt;a href="https://dev.to/fastly/you-should-have-your-own-domain-23mp"&gt;but it's much better to have your own domain&lt;/a&gt; and is easier than most people think. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc542g9vwhkyf7dyjebgb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc542g9vwhkyf7dyjebgb.jpg" alt="Domainr search with " width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;a href="https://domainr.com/" rel="noopener noreferrer"&gt;Domainr&lt;/a&gt; to find a domain by searching for keywords like your name or a project you're working on. &lt;/li&gt;
&lt;li&gt;When you find a domain that you like, click it to see the available registrars. Check a few to find out the prices they're offering – you can get domains for a few dollars a year.&lt;/li&gt;
&lt;li&gt;You can go ahead and buy the domain from here, or if you already have a preferred registrar, just search the domain on their site and buy it there (I find myself using &lt;a href="https://porkbun.com/" rel="noopener noreferrer"&gt;Porkbun&lt;/a&gt; a lot because I like the experience even though I am a vegetarian lolol).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have your domain, your registrar will provide access to the DNS records for managing it. You'll need these to point the domain at your Glitch website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Point your domain at your site
&lt;/h2&gt;

&lt;p&gt;Now you have a domain you can use to send people to your content on the web and to verify your identity on social platforms. To point it at your Glitch site you'll also need TLS to keep it secure. We're going to use Fastly to get this for free – &lt;a href="https://dev.to/fastly/point-a-domain-at-your-site-with-fastly-1khm"&gt;we go over these steps in a lot more detail in this other tutorial&lt;/a&gt;, below is the TL;DR version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up a Fastly service
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sign up for a &lt;a href="https://www.fastly.com/signup?tier=free" rel="noopener noreferrer"&gt;free Fastly developer account&lt;/a&gt; (that's right, you're a developer now whether you knew it or not 🚀).&lt;/li&gt;
&lt;li&gt;In your new account, click &lt;strong&gt;Create service&lt;/strong&gt; and choose &lt;strong&gt;CDN&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter any &lt;strong&gt;Name&lt;/strong&gt; you like.&lt;/li&gt;
&lt;li&gt;Enter your new domain, with &lt;code&gt;www.&lt;/code&gt; at the start, like &lt;code&gt;www.sue.wtf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For your &lt;strong&gt;Origin&lt;/strong&gt; &amp;gt; &lt;strong&gt;Host&lt;/strong&gt; enter your Glitch website address – grab it from the Glitch editor by clicking the three dots above your preview and copying it. It should look something like this (no &lt;code&gt;https&lt;/code&gt; or slashes): &lt;code&gt;suewtf.glitch.me&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Activate&lt;/strong&gt;!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frf9j7h7oqow27665qbvz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frf9j7h7oqow27665qbvz.png" alt="New service" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Get a free TLS certificate
&lt;/h3&gt;

&lt;p&gt;Now let's grab a TLS certificate for the domain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;Security&lt;/strong&gt; choose &lt;strong&gt;TLS Management&lt;/strong&gt; then click &lt;strong&gt;Manage certificates&lt;/strong&gt; and &lt;strong&gt;Get started&lt;/strong&gt; to secure your domain.&lt;/li&gt;
&lt;li&gt;Enter the &lt;code&gt;www&lt;/code&gt; version of your domain and click &lt;strong&gt;Add&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Leave &lt;strong&gt;Certainly&lt;/strong&gt; selected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit&lt;/strong&gt; your new certificate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fastly will provide the details to verify that you own the domain – click &lt;strong&gt;Verification options&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy the &lt;strong&gt;ACME DNS challenge&lt;/strong&gt; &lt;code&gt;CNAME&lt;/code&gt; – it will be &lt;code&gt;_acme-challenge&lt;/code&gt; followed by your domain name.&lt;/li&gt;
&lt;li&gt;In the account where you bought your domain, navigate to your DNS settings. Add a new record, with &lt;code&gt;CNAME&lt;/code&gt; as the type, and the value you copied from Fastly as the &lt;strong&gt;Host&lt;/strong&gt; (usually the first text entry).&lt;/li&gt;
&lt;li&gt;Back in Fastly, grab the verification address by clicking the little clipboard – it'll be some letters followed by &lt;code&gt;fastly-validations.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In your DNS, add the value you copied as the second text entry in your new record (usually called &lt;code&gt;address&lt;/code&gt;, &lt;code&gt;data&lt;/code&gt;, or &lt;code&gt;content&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Save your new record.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It'll look a little different depending on your registrar, but here's an example in Squarespace:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7uzgh0owqseerfd9x2an.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7uzgh0owqseerfd9x2an.jpg" alt="Example DNS record for sue.wtf" width="800" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back in Fastly, your domain should soon pass verification, then your certificate will be issued within a few minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0odev1e6oaynwl8wm3b9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0odev1e6oaynwl8wm3b9.jpg" alt="New certificate subscription" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Point your DNS at your service
&lt;/h3&gt;

&lt;p&gt;OK now it's time to point the domain at your site through Fastly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Fastly, browse to &lt;strong&gt;Security&lt;/strong&gt; &amp;gt; &lt;strong&gt;Domains&lt;/strong&gt; and find your certificate. Under &lt;strong&gt;TLS configuration and DNS details&lt;/strong&gt; click &lt;strong&gt;View / Edit&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;CNAME record&lt;/strong&gt; address which will end &lt;code&gt;.sni.global.fastly.net&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Back in your DNS account, add another new record, &lt;code&gt;CNAME&lt;/code&gt; again, this time with the &lt;code&gt;www&lt;/code&gt; version of your domain, and the &lt;code&gt;sni&lt;/code&gt; text you just copied as the value.&lt;/li&gt;
&lt;li&gt;Save your new record.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtdh3w3ixw291noo9d29.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvtdh3w3ixw291noo9d29.jpg" alt="New DNS record" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It may take a while to update but with any luck (usually within an hour) you'll be able to visit your domain and land on your new Glitch website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcntq5zbhxcf966d3r28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxcntq5zbhxcf966d3r28.png" alt="My Glitch site at my domain" width="800" height="790"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 I usually set my DNS to redirect the &lt;code&gt;apex&lt;/code&gt; version of my domain (the one without a subdomain) to the &lt;code&gt;www&lt;/code&gt; version – steps vary by registrar but it's usually pretty straightforward.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Use your domain for your social profiles
&lt;/h2&gt;

&lt;p&gt;I'm going to use my new domain as a handle on a Bluesky account and a verified link on my Mastodon account. Luckily the Glitch remix already has some of this set up for me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bluesky
&lt;/h3&gt;

&lt;p&gt;Let's do Bluesky first (you'll need to set up an account with a default handle before you can switch to using your own domain):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your Bluesky account, choose &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Account&lt;/strong&gt; &amp;gt; &lt;strong&gt;Handle&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;I have my own domain&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enter your domain, like &lt;code&gt;www.sue.wtf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can set it up by adding another DNS record with the values in the popup, or you can set it up inside your Glitch project as follows:

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;No DNS panel&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;did&lt;/code&gt; value.&lt;/li&gt;
&lt;li&gt;In your Glitch project, create a new file by clicking the &lt;code&gt;+&lt;/code&gt; icon on the left above the filetree and entering &lt;code&gt;.well-known/atproto-did&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Paste the value from Bluesky into this new file.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87vaonytxktw0tqrkikd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87vaonytxktw0tqrkikd.jpg" alt="The did info in Glitch" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bluesky will verify your domain and update it as your new handle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauguwb4bq3svtovg5gsy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauguwb4bq3svtovg5gsy.jpg" alt="My new Bluesky account" width="800" height="1955"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://bsky.social/about/blog/4-28-2023-domain-handle-tutorial" rel="noopener noreferrer"&gt;More detailed guide to using your own domain in the Bluesky docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;💡 Remember to update the link to your Bluesky profile in your Glitch project HTML!&lt;/p&gt;

&lt;h3&gt;
  
  
  Mastodon
&lt;/h3&gt;

&lt;p&gt;Now for Mastodon, we'll use the domain to add a verified link to our profile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your Glitch project, update the link to Mastodon near the end of &lt;code&gt;index.html&lt;/code&gt; to your own Mastodon profile.&lt;/li&gt;
&lt;li&gt;The link already has &lt;code&gt;rel="me"&lt;/code&gt; in it – you need this to verify it on Mastodon.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07syfmuinf3109q3wsum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07syfmuinf3109q3wsum.png" alt="My masto link" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your Mastodon account, edit your profile, adding a link to your new domain that you have pointed at your Glitch site. It should verify fairly quickly!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0o1hlvt7xdcernigstm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0o1hlvt7xdcernigstm.png" alt="My verified domain" width="800" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the example accounts I used for this tutorial here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bsky.app/profile/www.sue.wtf" rel="noopener noreferrer"&gt;Bluesky&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://glasgow.social/@sue" rel="noopener noreferrer"&gt;Mastodon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it! &lt;/p&gt;

&lt;p&gt;🚀 &lt;a href="https://dev.to/glitch/autopost-to-bluesky-and-mastodon-by-api-500d"&gt;Next try remixing an app that automates Bluesky and Mastodon posting..&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🛟 &lt;a href="https://support.glitch.com" rel="noopener noreferrer"&gt;&lt;strong&gt;If you hit any issues ask for help on the Glitch forum!&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>dns</category>
      <category>socialmedia</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Let's talk about algorithms and social media</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Thu, 14 Nov 2024 12:22:53 +0000</pubDate>
      <link>https://forem.com/suesmith/lets-talk-about-algorithms-and-social-media-aj3</link>
      <guid>https://forem.com/suesmith/lets-talk-about-algorithms-and-social-media-aj3</guid>
      <description>&lt;p&gt;We're having another, bigger wave of folk moving from Twitter to platforms like Bluesky and Mastodon right now. There's a lot of talk about algorithms and feeds. Let's break it down, find out what algorithms are, and what to know about the information you discover in your favourite social media apps. &lt;/p&gt;

&lt;h2&gt;
  
  
  Algorithms are everywhere, and that's (mostly) ok!
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📣 OK first of all, every social media feed uses an algorithm, even if it's just a list of posts from people you follow in chronological order – that is the algorithm!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The problematic part was that apps started presenting feeds assembled using different algorithms that we couldn't see or understand. Using a different algorithm isn't necessarily a problem in itself – sometimes it's good to see something beyond that timeline from people you already know about. &lt;em&gt;The problem was that the algorithm was mysterious and hidden, and sometimes you couldn't opt out of it.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an algorithm?
&lt;/h2&gt;

&lt;p&gt;An algorithm is a series of instructions we give a computer to create the functionality you use in a software program, like presenting a list of posts in a social media app. An algorithm is like a recipe for a meal, or a manual for assembling a piece of furniture. &lt;/p&gt;

&lt;p&gt;Algorithms can get really complex, and use structures that determine the &lt;em&gt;control flow&lt;/em&gt; of an app, like conditionals. A conditional tells the computer to do something &lt;em&gt;if&lt;/em&gt; some condition is in place. Like not showing a post to someone if they've blocked the person posting it. Algorithms use lots more structures that change the behaviour of the apps you use, and they can be hard to predict!&lt;/p&gt;

&lt;p&gt;Algorithms also use &lt;strong&gt;data&lt;/strong&gt;, like the user details indicating they'd blocked that other person. The data on a social media app is &lt;em&gt;dynamic&lt;/em&gt;, meaning it's constantly changing, because people are joining, posting, interacting, and all sorts of events are happening in the world. The combination of these control structures and large amounts of data makes the experience of social media often radically different between users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Algorithmic feeds
&lt;/h2&gt;

&lt;p&gt;Over time, many social media feeds shifted from that list of posts from folk you follow to an &lt;strong&gt;algorithmic feed&lt;/strong&gt; that was created by some mechanism you couldn't see or control. Sometimes they would push content that was popular with others even though you didn't follow the people posting. Sometimes they would just push content the owner of the platform wanted to promote. Why?&lt;/p&gt;

&lt;p&gt;Most social media apps are free to use, but they cost money to provide. Software services are funded a few different ways, but typically the funders want a return on their investment – in the case of VC funding, which was prevalent in the tech industry for many years, they want an &lt;em&gt;extreme&lt;/em&gt; return. This is why platforms use ads, promoted posts, and sometimes paid accounts giving you additional features. &lt;/p&gt;

&lt;h2&gt;
  
  
  Follow the money, always
&lt;/h2&gt;

&lt;p&gt;Social media providers have struggled to come up with business models that don't destroy the experience they give users. If you're generating revenue from ads or promoted posts, you might charge by &lt;em&gt;impressions&lt;/em&gt; – the number of times a post appears in someone's feed. Even if you aren't making money this way, it's common for software companies to report on metrics around &lt;strong&gt;engagement&lt;/strong&gt; as a predictor of future success. Engagement means users spending time in the app and interacting with it. &lt;/p&gt;

&lt;p&gt;Software platforms are therefore incentivised to increase engagement, in order to generate revenue, or to keep the funding coming in so that they can continue operating. The consequence is programming your algorithm to push content that gives those engagement numbers a bump. &lt;em&gt;Unfortunately the posts that have this effect aren't always good for community health, like hate content.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Building these levers into your algorithm gives you the mechanism to push whatever content you like at people. This is part of how social media platforms have contributed to the spread of misinformation that aligned with the political interests of their owners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Emerging platforms and user choice
&lt;/h2&gt;

&lt;p&gt;There is good news. A raft of new social media platforms are attempting to decentralise and democratise your experience, by giving you choices over the algorithms that assemble your feeds, and making those feeds more transparent. &lt;/p&gt;

&lt;p&gt;For example, in Bluesky you can choose feeds that only show you posts from mutuals, or posts that are popular with people you follow – you can also create your own &lt;a href="https://docs.bsky.app/docs/starter-templates/custom-feeds" rel="noopener noreferrer"&gt;custom feeds&lt;/a&gt;. Mastodon is open source, which means people can see and contribute to the code, and even &lt;a href="https://docs.joinmastodon.org/user/run-your-own/" rel="noopener noreferrer"&gt;host their own version&lt;/a&gt; of it. How these platforms are going to be funded in a sustainable way remains to be seen. And idk what to tell you about Threads lol I'll leave it at that.&lt;/p&gt;

&lt;p&gt;Catch me on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://glasgow.social/@sue" rel="noopener noreferrer"&gt;Mastodon sue@glasgow.social&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bsky.app/profile/suesmith.lol" rel="noopener noreferrer"&gt;Bluesky @suesmith.lol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>computerscience</category>
      <category>web</category>
      <category>socialmedia</category>
      <category>learning</category>
    </item>
    <item>
      <title>How I make learning experiences</title>
      <dc:creator>Sue Smith</dc:creator>
      <pubDate>Mon, 30 Sep 2024 11:44:39 +0000</pubDate>
      <link>https://forem.com/suesmith/how-i-make-learning-experiences-4ph2</link>
      <guid>https://forem.com/suesmith/how-i-make-learning-experiences-4ph2</guid>
      <description>&lt;p&gt;I make things to help people learn coding skills. Most of my work is is closer to building edtech software than authoring education content, but I hesitate to identify what I do as edtech because, well &lt;a href="https://hackeducation.com/2020/07/20/surveillance" rel="noopener noreferrer"&gt;a lot of that is basically surveillance tech&lt;/a&gt; which is not what I'm about lol. &lt;/p&gt;

&lt;p&gt;A conversation at work prompted me to describe how I approach teaching a topic. I've been doing this for quite a long time now, so thought I might have some tips that could be useful to others looking to help folk learn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn the thing myself first
&lt;/h2&gt;

&lt;p&gt;This might seem obvious, but typically I'm teaching things I don't already know how to do, so I have to learn them first. The best time to teach something is right after you learned it imo, it puts you closer to the learner perspective, and you make fewer assumptions about what they already know.&lt;/p&gt;

&lt;p&gt;It's worth noting any places you find particularly challenging or awkward, bearing in mind that these are highly subjective and won't necessarily be representative of what your learners find hard – they are still likely places you can make the experience easier for some.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consider the conceptual elements
&lt;/h2&gt;

&lt;p&gt;Often when you're trying to acquire a tech skill, there are both conceptual and practical elements you need to grasp. Abstraction, analogies, and mental models can be helpful here, but first you need to frame whatever you think those conceptual components are.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Example&lt;/strong&gt;: This year I've been teaching edge computing. The notion of client and server in web development is relatively well known, but adding a third thing called the edge poses a conceptual challenge. It affects your understanding of what happens when people visit a website, and what the development process looks like in that context.&lt;/p&gt;

&lt;p&gt;🧰 &lt;strong&gt;Toolkit&lt;/strong&gt;: When it comes to teaching the conceptual elements, varying the levels of abstraction in your learning experience can help – like using &lt;a href="https://blog.teachcomputing.org/quick-read-6-semantic-waves/" rel="noopener noreferrer"&gt;semantic waves&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Consider the practical barriers
&lt;/h2&gt;

&lt;p&gt;With software development, we often have &lt;a href="https://dev.to/glitch/what-is-worth-learning-41e3"&gt;frustrating, time-consuming setup processes&lt;/a&gt; to get our environments in a state where we can begin learning. This friction reduces the number of people who manage to successfully engage, so I always consider removing barriers, at least for a first learning experience on a subject. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Example&lt;/strong&gt;: This is why I use Glitch so much, you can build applications without downloading or installing anything. I can also abstract a lot away behind the plumbing of a Glitch project and focus the experience on the core learning gains I'm trying to help people access.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is a trade-off here between clearing the path of unnecessary obstacles and not glossing over understanding the learner will need to apply what they've learned in the real world – this can be a hard balance to strike and often takes multiple iterations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design the experience
&lt;/h2&gt;

&lt;p&gt;I always try to teach hands-on, in context, in a developer environment. Editors like Glitch are great for this because there are &lt;a href="https://glitch.com/~teach-in-glitch" rel="noopener noreferrer"&gt;multiple places you can include guiding information&lt;/a&gt; that the learner can follow at their own pace – they can also see the results of their edits live.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🧰 &lt;strong&gt;Toolkit&lt;/strong&gt;: My goal is for people to come away from an experience with skills they can reapply in different settings. This can be hard to measure depending on the relationship you have with the learners, but I find the &lt;a href="https://computingeducationresearch.org/projects/primm/" rel="noopener noreferrer"&gt;Raspberry Pi coding pedagogy research and practices like PRIMM&lt;/a&gt; super helpful for guiding design decisions – ideally, start with a working example and walk the learner through making a change to it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Make it meaningful
&lt;/h2&gt;

&lt;p&gt;Framing learning experiences in terms that are valuable and meaningful to the learner is a great motivator. Make it about what they gain by learning this skill, perhaps for a project or goal they care about, rather than just teaching it for its own sake. Putting the task or skill in its technological or cultural context helps.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Example&lt;/strong&gt;: I've recently been teaching people about using their own domains for their sites and applications, and explained &lt;a href="[why%20it's%20a%20good%20idea%20to%20have%20your%20own%20domain](https://dev.to/fastly/you-should-have-your-own-domain-23mp)"&gt;why it's a good idea to do this&lt;/a&gt; as a supporting resource.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Community situated learning often provides additional motivation too – if you can encourage people to share reflections on what they've learned that'll help them retain their new skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test it with humans
&lt;/h2&gt;

&lt;p&gt;Whenever I'm working on a self-serve learning resource, I like to use it as a supporting asset for live training. Testing an experience with people in real time helps to reveal any &lt;a href="https://developerrelations.com/developer-experience/making-the-implicit-explicit" rel="noopener noreferrer"&gt;implicit knowledge&lt;/a&gt;, anything I've inadvertently assumed people would already know but that they don't. I can then work to cover that knowledge in the experience, or at least indicate it as a prerequisite.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Example&lt;/strong&gt;: Earlier in 2024 I tested public facing learning materials for my company's products by &lt;a href="https://dev.to/fastly/learning-at-fastly-a-shared-experience-345f"&gt;running internal employee training&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When people attend a live training, giving them something they can take away, refer back to, and continue developing is ideal, so this one's a win-win.&lt;/p&gt;

&lt;p&gt;🛼 &lt;strong&gt;&lt;em&gt;That's about it! Check out my &lt;a href="https://developerrelations.com/developer-education/an-open-framework-for-developer-learning" rel="noopener noreferrer"&gt;developer learning talk from 2023&lt;/a&gt; for more tips.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
