<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Timon van Spronsen</title>
    <description>The latest articles on DEV Community by Timon van Spronsen (@timon).</description>
    <link>https://dev.to/timon</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%2F28109%2F8265f4ac-5d7e-4d3e-a405-fb820495b5f4.png</url>
      <title>DEV Community: Timon van Spronsen</title>
      <link>https://dev.to/timon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/timon"/>
    <language>en</language>
    <item>
      <title>Introduction to hardware programming with DeviceScript</title>
      <dc:creator>Timon van Spronsen</dc:creator>
      <pubDate>Thu, 25 Jan 2024 09:05:14 +0000</pubDate>
      <link>https://dev.to/timon/introduction-to-hardware-programming-with-devicescript-53ak</link>
      <guid>https://dev.to/timon/introduction-to-hardware-programming-with-devicescript-53ak</guid>
      <description>&lt;p&gt;Hardware programming used to require you to learn C/C++. If you’re already familiar with JavaScript or TypeScript, you will be delighted to learn about &lt;a href="https://microsoft.github.io/devicescript/"&gt;DeviceScript&lt;/a&gt;, a TypeScript programming environment for microcontrollers. In this blogpost you’ll learn the basics of electronics and DeviceScript. We will create the “hello world” of programming: making an LED blink!&lt;/p&gt;

&lt;h2&gt;
  
  
  Hackerspace Pixelbar
&lt;/h2&gt;

&lt;p&gt;This blogpost originates from a workshop organized at &lt;a href="https://www.pixelbar.nl"&gt;Hackerspace Pixelbar&lt;/a&gt; in Rotterdam, which was generously sponsored by No Fluff Jobs. A hackerspace is a physical space where people interested in science, technology or digital art (and many other areas) can meet and exchange ideas. Want to visit? We’re open on Wednesday evenings and Saturday afternoons. Feel free to connect with us on Discord or refer to our website for current opening hours. Additionally, we regularly organize workshops about JavaScript and web-related topics. &lt;a href="https://www.meetup.com/nodeschool-rotterdam/"&gt;Join our Meetup group&lt;/a&gt; to get notified of the next event!&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety instructions
&lt;/h2&gt;

&lt;p&gt;Keep these safety instructions in mind while working with electronics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don’t adjust wiring while a circuit is powered. In other words, plug out the USB cable connected to your computer.&lt;/li&gt;
&lt;li&gt;Wash your hands after handling hardware. Some components may be lightly contaminated with toxic metals, so it’s good practice to wash your hands afterwards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;We’re going to need a few components to get going:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Seeed Studio XIAO ESP32C3 with headers soldered on&lt;/li&gt;
&lt;li&gt;A cable to connect the microcontroller to your computer (USB-C in our case)&lt;/li&gt;
&lt;li&gt;A breadboard&lt;/li&gt;
&lt;li&gt;A 5mm 2V LED – any LED will do, I recommend using a diffused LED&lt;/li&gt;
&lt;li&gt;A 100Ω  resistor – a higher value, e.g., 270Ω is fine too, the LED will just shine a little more dimly&lt;/li&gt;
&lt;li&gt;A few jumper cables&lt;/li&gt;
&lt;li&gt;Optionally: a button&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Aside from hardware, here are the software requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en"&gt;Node.js 18 or higher&lt;/a&gt; (LTS recommended)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://marketplace.visualstudio.com/items?itemName=devicescript.devicescript-vscode"&gt;DeviceScript extension&lt;/a&gt; for Visual Studio Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before we start, it’s essential to learn a bit about the components we’re going to be using.&lt;/p&gt;

&lt;h3&gt;
  
  
  The breadboard
&lt;/h3&gt;

&lt;p&gt;A breadboard is a way to build electronic circuits. The image below shows the front and the back of a breadboard with the adhesive backing removed. The top side is where we plug in our components and jumper wires. The backside demonstrates how everything is connected. The rows are connected horizontally, we call them terminal strips, they are not connected across the divider gap in the middle. The columns on the side (with the + and - above them) are called power rails, and are connected vertically.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  The microcontroller
&lt;/h3&gt;

&lt;p&gt;A microcontroller is a tiny computer on a single integrated circuit, common examples include Arduino and the ESP32 series. Microcontrollers usually contain several general purpose input/output pins (GPIO). These input/output pins allow us to connect components like LEDs. The pinout diagram below shows the pins present on the Seeed Studio XIAO ESP32C3, you can reference this diagram when you wire up the components.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2eyrhois89mikodlgix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2eyrhois89mikodlgix.png" alt="Pinout schema of Seeed Studio XIAO ESP32-C3" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The LED and resistor
&lt;/h3&gt;

&lt;p&gt;An LED has two legs, we call them the anode (+) and the cathode (-). The anode leg is slightly longer. We use a resistor to limit the current that flows through the LED, if we were to omit a resistor, the LED could burn out. In my setup I’m using 2V 20mA LEDs, the specifications of your LED may differ slightly, not to worry, the specified resistor will likely be enough to keep your LED from burning out. The anode should be connected to the positive side of the circuit, while the cathode should be connected to the ground, the other way around won’t hurt the LED, but it won’t do anything either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wiring up the hardware
&lt;/h2&gt;

&lt;p&gt;Let’s connect the components to the breadboard, you can follow the schema below. The bended leg of the LED in the breadboard schema below is the anode (the longer leg).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m9u8dwviyv7dfo88795.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m9u8dwviyv7dfo88795.png" alt="Schematic of an electronic circuit. The ESP32C3 is connected at the top (row 1) on columns D and H. There is a jumper cable that connects I2 with I10. The cathode of the LED is plugged into G10, the anode is plugged into E10. The resistor is plugged into B6 and B10." width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s examine what we did. We connected the GND pin (ground) with a jumper wire to row 10, this connects the ground to the terminal strip on row 10 on the top side of the gap, meaning that the cathode of the LED is connected to the ground. The anode of the LED is connected with the resistor, which in turn is connected with pin D6.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programming the hardware
&lt;/h2&gt;

&lt;p&gt;Now onto the most fun part! First create a new folder to contain your project (e.g., &lt;code&gt;blinky&lt;/code&gt;), open this folder in VS Code (File → Open Folder…). If you have the DeviceScript extension installed you should see a DeviceScript icon in the activity bar, click on it, then press “Create New Project” and follow the wizard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6e0qqchrez59nigjmvqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6e0qqchrez59nigjmvqh.png" alt="Image description" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back to the file explorer, open &lt;code&gt;src/main.ts&lt;/code&gt; and replace the contents with the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;startLightBulb&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;@devicescript/servers&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;pins&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;@dsboard/seeed_xiao_esp32c3&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;led&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;startLightBulb&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SCL_D5&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A couple of things to note here. It’s important to import the correct pin definitions, as every board has different pins, or a different layout. I once made the mistake of importing the pin definitions for &lt;code&gt;esp32c3_bare&lt;/code&gt; instead, wondering for an hour why my code didn’t work 😅. &lt;code&gt;startLightBulb&lt;/code&gt; starts a client to interact with the LED that we connected, we have to give it the pin that’s driving the LED (D5). &lt;code&gt;await led.toggle()&lt;/code&gt; will toggle the LED on and off, this is encapsulated in a &lt;code&gt;setInterval&lt;/code&gt; which is triggered every 1000 ms (= 1 second).&lt;/p&gt;

&lt;h3&gt;
  
  
  Flashing the microcontroller
&lt;/h3&gt;

&lt;p&gt;Before we can load our code on the microcontroller, we have to flash the DeviceScript firmware onto the microcontroller.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect the microcontroller to your computer with a USB cable.&lt;/li&gt;
&lt;li&gt;Open the command palette in VS Code (Command+Shift+P on Mac, Ctrl+Shift+P on Windows and Linux), search for “flash”.&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;DeviceScript: Flash Firmware…&lt;/code&gt; and choose the appropriate device.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A terminal will open where you can track the progress, it might take a few seconds, once finished it should say “flash OK”. You can now connect the device.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loading code onto the microcontroller
&lt;/h3&gt;

&lt;p&gt;Once again, open the DeviceScript panel, but now click on “Connect Device”, then select serial, your device should now appear in the sidebar (1). Then click on the little chevron besides the debug button in the top-right corner (2) and select “DeviceScript: Run” from the context menu. The LED on your breadboard should now start blinking!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxiwdgussxtdsba39rddc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxiwdgussxtdsba39rddc.png" alt="Image description" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The result
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F903bys52f4lq2r3svsvl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F903bys52f4lq2r3svsvl.gif" alt="Completed circuit with blinking LED" width="600" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dimming an LED
&lt;/h2&gt;

&lt;p&gt;Let’s make things slightly more exciting, we’ll make the LED fade. To achieve this we must add &lt;code&gt;dimmable: true&lt;/code&gt; to &lt;code&gt;startLightBulb&lt;/code&gt;, this will allow us to change the intensity of the LED with &lt;code&gt;led.intensity.write(intensity)&lt;/code&gt;, where intensity is some number between 0 and 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sleep&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;@devicescript/core&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;startLightBulb&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;@devicescript/servers&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;pins&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;@dsboard/seeed_xiao_esp32c3&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;led&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;startLightBulb&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SCL_D5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dimmable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fadeInLevels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fadeOutLevels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fade&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Fade in&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;level&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;fadeInLevels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intensity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level&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;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Stay at peak brightness for a bit&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&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="c1"&gt;// Fade out&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;level&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;fadeOutLevels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intensity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level&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;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fade&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;sleep&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This concludes the tutorial. Next up you could try wiring up a button to a digital pin and use it to toggle the LED, I’ll leave you with the schema below. If you have any questions, don’t hesitate to drop by &lt;a href="https://www.pixelbar.nl/"&gt;Pixelbar hackerspace in Rotterdam&lt;/a&gt;. We also have a &lt;a href="https://www.pixelbar.nl/contact/"&gt;Discord community&lt;/a&gt; that you can join to ask questions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50a71agxvzz9mdkrrtv2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50a71agxvzz9mdkrrtv2.png" alt="Schematic of electronic circuit, it adds a button to the circuit discussed earlier. There is a jumper wire between J2 and J22, and another between J3 and J20. The button is connected between the gap at G20 and E20." width="800" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>esp32</category>
      <category>iot</category>
    </item>
    <item>
      <title>Developing a Website with React, Feature Flags, Netlify and GitHub Actions</title>
      <dc:creator>Timon van Spronsen</dc:creator>
      <pubDate>Fri, 19 Jul 2019 11:25:57 +0000</pubDate>
      <link>https://dev.to/timon/developing-a-website-with-react-feature-flags-netlify-and-github-actions-2eld</link>
      <guid>https://dev.to/timon/developing-a-website-with-react-feature-flags-netlify-and-github-actions-2eld</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Please note:&lt;/strong&gt; this post was written for GitHub Actions v1. GitHub Actions v2 has been released which &lt;a href="https://github.blog/changelog/2019-09-17-github-actions-will-stop-running-workflows-written-in-hcl/" rel="noopener noreferrer"&gt;deprecates the HCL syntax for workflows&lt;/a&gt; which renders some parts of this blog post unusable. To learn more about GitHub Actions v2, please refer to the &lt;a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; and the excellent &lt;a href="https://www.edwardthomson.com/blog/github_actions_advent_calendar.html" rel="noopener noreferrer"&gt;posts&lt;/a&gt; by Edward Thomson.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In recent weeks I've helped develop a website for a very exciting project at &lt;a href="https://awkward.co" rel="noopener noreferrer"&gt;Awkward&lt;/a&gt; called Coffee by Benjamin. Coffee by Benjamin is a coffee roasting kit that allows anyone to roast their coffee at home, this guarantees the freshness of the coffee. The project will launch on Kickstarter soon. If you'd like to keep notified about this project you can follow them on &lt;a href="https://www.instagram.com/coffeebybenjamin/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; or visit the &lt;a href="https://coffeebybenjamin.com/" rel="noopener noreferrer"&gt;website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This project is my last one at Awkward as I'll be taking up a new challenge at another company soon. Even though I won't be a part of the project going forward, I still want to share something about the way we've been developing and shipping the website by utilizing React, feature flags, Netlify, and GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem statement
&lt;/h2&gt;

&lt;p&gt;The website will launch in three separate phases outlined below. We're currently in phase 1 but we're nearing completion on phase 2. Meanwhile, we've already started development on phase 3.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Phase 1: a simple landing page where people can fill in their email address to get notified when the project launches.&lt;/li&gt;
&lt;li&gt;Phase 2: a full-fletched website which contains more information about the project, a FAQ and a support form. This will launch together with the launch of the Kickstarter campaign.&lt;/li&gt;
&lt;li&gt;Phase 3: integrate Shopify into the website to sell the product directly. This will launch after the project has been successfully funded and shipped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though phase 3 won't launch till much later, we wanted to start development on this phase as soon as possible because it's the most complicated part of the website to build. This allows us to start testing the shop functionality long before it's launched and catch costly bugs from creeping into the website.&lt;/p&gt;

&lt;p&gt;Now we could build phase 3 in a separate branch, but we'd have to constantly update and solve merge conflicts on this branch when we update the phase 2 website. This is especially hard because there are a lot of overlapping parts that we'll change in phase 3. Furthermore, this would result in having to merge a gigantic pull request when phase 3 launches which comes with the risk of bugs in existing functionality. Instead, we want to gradually merge functionality from phase 3 in the main branch without exposing it to the public. We also want the team to be able to check the progress on both phase 2 and phase 3. Finally, we'd like to completely exclude any code from phase 3 while phase 2 is live so that we don't ship any unnecessary code.&lt;/p&gt;

&lt;p&gt;In the rest of the post I'll explain how we used a combination of feature flags, Netlify and GitHub Actions to achieve these goals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fevod8hvfe3zz2lzbe66r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fevod8hvfe3zz2lzbe66r.jpg" alt="The tray"&gt;&lt;/a&gt;&lt;/p&gt;
The tray you'll get as part of the home roasting kit



&lt;h2&gt;
  
  
  Feature flags
&lt;/h2&gt;

&lt;p&gt;The problem statement just screams for feature flags, which is exactly what we'll be using. Feature flags allow us to ship parts of phase 3 but don't actually show them to the public. Let's take a look at a definition of feature flags:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Release Toggles allow incomplete and un-tested codepaths to be shipped to production as latent code which may never be turned on.&lt;/p&gt;

&lt;p&gt;— &lt;a href="https://martinfowler.com/articles/feature-toggles.html" rel="noopener noreferrer"&gt;Feature Toggles, Pete Hodgson&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The nice thing about feature flags is that it allows you to switch between new and old functionality with the flip of a switch. Usually you do this by wrapping new functionality in a condition like so:&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;function&lt;/span&gt; &lt;span class="nf"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;USE_NEW_FEATURE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NewHeader&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// feature flag is not enabled&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OldHeader&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In code that's affected by a feature flag, you'll add new code without replacing the old code. This allows pull requests with new but overlapping functionality to be merged as they won't replace any existing functionality. Later when the feature flag is being phased out you can remove the conditions and remove any old code.&lt;/p&gt;

&lt;p&gt;Let's see how we can implement this into our stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Flags in Create React App
&lt;/h2&gt;

&lt;p&gt;We can implement feature flags by using environment variables &lt;a href="https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables" rel="noopener noreferrer"&gt;which Create React App supports out of the box&lt;/a&gt;. The benefits of using environment variables are that they're easy to use and they're compile-time constants, which means that code that is guarded by a condition that checks for the flag being enabled will be completely excluded from a build where the flag was disabled.&lt;/p&gt;

&lt;p&gt;Environment variables in Create React App can be supplied in a &lt;code&gt;.env&lt;/code&gt; file. The &lt;code&gt;.env&lt;/code&gt; file will contain the default value to use and is checked into Git and will only be changed when phase 3 goes live.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
REACT_APP_SHOPIFY_INTEGRATION_ENABLED=false

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

&lt;/div&gt;



&lt;p&gt;Now we can use the feature flag in &lt;code&gt;App.js&lt;/code&gt; to conditionally render the shop routes. By conditionally rendering the shop routes using a compile-time constant, the code won't end up in the production bundle unless the flag is enabled and users won't be able to route to these pages. The code for the pages will still end up in the production bundle, more on that later.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/App.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Suspense&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ... more imports hidden&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Home&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;pages/Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Shop&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;pages/shop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Cart&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;pages/cart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ProductDetail&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;pages/product-detail&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;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/faq"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Faq&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/support"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Support&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;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;REACT_APP_SHOPIFY_INTEGRATION_ENABLED&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/shop"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Shop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/cart"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Cart&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/product/:productId"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ProductDetail&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;Now that we've got the feature flag set up developers can add a &lt;code&gt;.env.local&lt;/code&gt; (or any of the &lt;a href="https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#what-other-env-files-can-be-used" rel="noopener noreferrer"&gt;other supported &lt;code&gt;.env&lt;/code&gt; files&lt;/a&gt;) which won't be checked into git.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.env.local&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REACT_APP_SHOPIFY_INTEGRATION_ENABLED=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring Netlify
&lt;/h2&gt;

&lt;p&gt;Now only developers can see the Shopify integration by checking out locally and changing the environment variable in &lt;code&gt;.env.local&lt;/code&gt;, what about other people that might want to review the site with a simple link? This is where Netlify comes in. Netlify allows developers to configure the build settings per branch and all branches will be deployed with a unique URL (separately from deploy previews), I'll let the Netlify documentation speak for itself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Branch deploys are published to a URL which includes the branch name as a prefix. For example, if a branch is called staging, it will deploy to staging--yoursitename.netlify.com.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; You may have to manually set the branch deploys setting to deploy all branches, this is explained in the &lt;a href="https://www.netlify.com/docs/continuous-deployment/#branch-deploy-controls" rel="noopener noreferrer"&gt;Netlify documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can add a branch in Git called &lt;code&gt;shop-staging&lt;/code&gt; and configure &lt;code&gt;netlify.toml&lt;/code&gt; to build this branch with the &lt;code&gt;REACT_APP_SHOPIFY_INTEGRATION_ENABLED&lt;/code&gt; feature flag enabled.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;netlify.toml&lt;/code&gt;:&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;[build]&lt;/span&gt;
  &lt;span class="py"&gt;publish&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"build"&lt;/span&gt;
  &lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"npm run build"&lt;/span&gt;

&lt;span class="nn"&gt;[context."shop-staging"]&lt;/span&gt;
  &lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="py"&gt;"REACT_APP_SHOPIFY_INTEGRATION_ENABLED&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="err"&gt;npm&lt;/span&gt; &lt;span class="err"&gt;run&lt;/span&gt; &lt;span class="err"&gt;build&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefixing the build command with &lt;code&gt;REACT_APP_SHOPIFY_INTEGRATION_ENABLED=true&lt;/code&gt; will override the settings in &lt;code&gt;.env&lt;/code&gt;. The site with the feature flag enabled will now be automatically deployed to shop-staging--yoursitename.netlify.com. We can now give this URL to testers and they'll be able to check out the progress on phase 3 and they can still check out the progress on phase 2 by visiting develop--yoursitename.netlify.com. You can also use this approach to enable the feature flag for deploy previews for certain pull requests.&lt;/p&gt;

&lt;p&gt;There's still one problem though, the &lt;code&gt;shop-staging&lt;/code&gt; branch will have to be to kept in sync with the main branch (in our case &lt;code&gt;develop&lt;/code&gt;). Luckily, GitHub provides an extensive API which provides a way to do a &lt;a href="https://developer.github.com/v3/git/refs/#update-a-reference" rel="noopener noreferrer"&gt;fast-forward update&lt;/a&gt; for a branch, this allows us to keep the &lt;code&gt;shop-staging&lt;/code&gt; branch in sync with the &lt;code&gt;develop&lt;/code&gt; branch. All we have to do is provide it the ref we want to update (&lt;code&gt;heads/shop-staging&lt;/code&gt;) and a commit SHA of the latest commit on the develop branch and then &lt;code&gt;shop-staging&lt;/code&gt; will be in sync with the &lt;code&gt;develop&lt;/code&gt; branch. Furthermore, we can automate this process by using GitHub Actions!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a GitHub Action to keep branches in sync
&lt;/h2&gt;

&lt;p&gt;GitHub actions, just like shell commands, are extremely composable. There's a lot you can accomplish by composing a few predefined actions. In this case we technically only need the &lt;a href="https://github.com/actions/bin/tree/master/filter" rel="noopener noreferrer"&gt;Filter action&lt;/a&gt; and the &lt;a href="https://github.com/actions/bin/tree/master/curl" rel="noopener noreferrer"&gt;&lt;code&gt;cURL&lt;/code&gt; action&lt;/a&gt;. But I couldn't get the &lt;code&gt;cURL&lt;/code&gt; action to accept a JSON body with an interpolated value, so we'll be creating our own.&lt;/p&gt;

&lt;p&gt;There are two ways to create GitHub Actions, you can create a separate repository that contains the Action, this way other projects will be able to reuse the Action. But for something small that you won't reuse you can create an Action right inside of the repository where the rest of the code for your project lives.&lt;/p&gt;

&lt;p&gt;We first create a folder &lt;code&gt;.github&lt;/code&gt;, inside of it we create a folder called &lt;code&gt;branch-sync-action&lt;/code&gt;. We must then create a &lt;code&gt;Dockerfile&lt;/code&gt;, the contents are copied from the &lt;code&gt;cURL&lt;/code&gt; action, we just change some of the labels. This &lt;code&gt;Dockerfile&lt;/code&gt; ensures that we can use &lt;code&gt;cURL&lt;/code&gt; which we'll use to do the HTTP call.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.github/branch-sync-action/Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; debian:stable-slim&lt;/span&gt;

&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; "com.github.actions.name"="Branch Sync"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; "com.github.actions.description"=""&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; "com.github.actions.icon"="refresh-cw"&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; "com.github.actions.color"="white"&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; entrypoint.sh /entrypoint.sh&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install &lt;/span&gt;curl &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get clean &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/entrypoint.sh"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create an &lt;code&gt;entrypoint.sh&lt;/code&gt; which is the script that will be executed when running the action.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.github/branch-sync-action/entrypoint.sh&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;#!/bin/sh&lt;/span&gt;

&lt;span class="nv"&gt;TARGET_BRANCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;

curl &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-X&lt;/span&gt; PATCH &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: token &lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;sha&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_SHA&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://api.github.com/repos/&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_REPOSITORY&lt;/span&gt;&lt;span class="s2"&gt;/git/refs/heads/&lt;/span&gt;&lt;span class="nv"&gt;$TARGET_BRANCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$1&lt;/code&gt; stands for the first argument provided to the script. For clarity we give it the name &lt;code&gt;TARGET_BRANCH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Don't forget to provide execution permissions by doing &lt;code&gt;chmod +x entrypoint.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's it for the action itself. Now we have to hook it up in a workflow:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.github/main.workflow&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;workflow&lt;/span&gt; &lt;span class="s2"&gt;"Sync shop-staging branch with develop"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"push"&lt;/span&gt;
  &lt;span class="nx"&gt;resolves&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Sync Branch"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="s2"&gt;"Filter develop branch"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;uses&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions/bin/filter@master"&lt;/span&gt;
  &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"branch develop"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="s2"&gt;"Sync Branch"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;needs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Filter develop branch"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;uses&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./.github/sync-branch-action"&lt;/span&gt;
  &lt;span class="nx"&gt;secrets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GITHUB_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"shop-staging"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;.github/main.workflow&lt;/code&gt; we define workflows for our project. Workflows decide which actions to run and when. In the &lt;code&gt;workflow&lt;/code&gt; block we tell it when to run by defining the &lt;code&gt;on&lt;/code&gt; attribute, in our case the workflow should run for every &lt;code&gt;push&lt;/code&gt; event, we also define the actions it should execute (in parallel) by defining the &lt;code&gt;resolves&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Next, we define the filter action. GitHub will send a &lt;code&gt;push&lt;/code&gt; event for every push to any branch, we want to add a filter so that we only sync the &lt;code&gt;shop-staging&lt;/code&gt; branch when someone pushes to the &lt;code&gt;develop&lt;/code&gt; branch, we're not interested in pushes to any other branch. In the &lt;code&gt;uses&lt;/code&gt; parameter we point to the slug of the &lt;a href="https://github.com/actions/bin" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; that provides this action and in this case the folder within this repository (filter). The &lt;code&gt;@master&lt;/code&gt; part tells it to use the code that was published on the master branch.&lt;/p&gt;

&lt;p&gt;Finally we add the action that syncs the &lt;code&gt;shop-staging&lt;/code&gt; branch with the &lt;code&gt;develop&lt;/code&gt; branch. It has the &lt;code&gt;needs&lt;/code&gt; parameter defined which tells GitHub Actions that it should first run the filter action and only continue with &lt;code&gt;Sync Branch&lt;/code&gt; if the filter action succeeds. Furthermore we define the &lt;code&gt;uses&lt;/code&gt; parameter which will point to the folder containing the &lt;code&gt;Dockerfile&lt;/code&gt; and &lt;code&gt;entrypoint.sh&lt;/code&gt; which is used by GitHub Actions to run it. We also pass it the &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; as a secret which we need to make an authenticated HTTP call, &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; is a uniquely generated token for every project on GitHub. Lastly, we provide the arguments for &lt;code&gt;entrypoint.sh&lt;/code&gt; which is the target branch it should sync to.&lt;/p&gt;

&lt;p&gt;We'll end up with a flow looking like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvr4etpfh33kmpjm3fekr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvr4etpfh33kmpjm3fekr.png" alt="Workflow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's important to note that the sync is one-way only. Everything that's pushed to &lt;code&gt;develop&lt;/code&gt; will be fast-forwarded to &lt;code&gt;shop-staging&lt;/code&gt;, if you're pushing to &lt;code&gt;shop-staging&lt;/code&gt; nothing will happen, it will cause problems with future synchronization because updates can't be fast-forwarded anymore. You can solve this by enabling the &lt;a href="https://developer.github.com/v3/git/refs/#update-a-reference" rel="noopener noreferrer"&gt;&lt;code&gt;force&lt;/code&gt; parameter&lt;/a&gt; in the &lt;code&gt;cURL&lt;/code&gt; request or by resetting the &lt;code&gt;shop-staging&lt;/code&gt; branch using &lt;code&gt;git reset&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy loading shop routes
&lt;/h2&gt;

&lt;p&gt;A last problem we still have to tackle is excluding phase 3 related code from the bundle while phase 2 is live. We can tackle this by utilizing some new features released in React just last year: &lt;a href="https://reactjs.org/docs/code-splitting.html#reactlazy" rel="noopener noreferrer"&gt;&lt;code&gt;React.lazy&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;Suspense&lt;/code&gt;. The changes we have to make to our code are quite minimal, we have to change the way we're importing the shop pages by utilizing &lt;code&gt;React.lazy&lt;/code&gt; and dynamic imports:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/App.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Suspense&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ... more imports hidden&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Home&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;pages/Home&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;Shop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pages/shop&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;Cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pages/cart&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;ProductDetail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pages/product-detail&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;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/faq"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Faq&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/support"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Support&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;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;REACT_APP_SHOPIFY_INTEGRATION_ENABLED&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/shop"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Shop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/cart"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Cart&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/product/:productId"&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ProductDetail&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;Now the shop pages will not end up in the main bundle, they will instead be lazily loaded when a user hits one of the shop routes. Which is impossible when the flag is not enabled. All of the routes are wrapped in a &lt;code&gt;Suspense&lt;/code&gt; component which is responsible for showing a fallback state when visiting one of the lazily loaded routes as it still takes some time to download the bundle. If you'd like to know more about code-splitting (in React) I can recommend the excellent &lt;a href="https://reactjs.org/docs/code-splitting.html" rel="noopener noreferrer"&gt;React documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;I created a simplified example of the code in this post which you can check out here: &lt;a href="https://github.com/TimonVS/sync-branch-demo" rel="noopener noreferrer"&gt;https://github.com/TimonVS/sync-branch-demo&lt;/a&gt;. You can clone it and push a commit to the master branch to see that the shop-staging branch will automatically be kept in sync.&lt;/p&gt;

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

&lt;p&gt;We're quite happy with this approach. GitHub Actions deem to be very flexible. It'd have been even simpler if Netlify would support this use case out of the box, but since that's not the case syncing two branches isn't too bad either.&lt;/p&gt;

&lt;p&gt;The approach described in this post can also be used when using split-testing which is built into Netlify and allows you to test two (or more) variants of a website. It's not something we're using ourselves but with split-testing come the same problems as described in the problem statement.&lt;/p&gt;

&lt;p&gt;Finally, I have to note that we're currently only using one feature flag. This approach might not scale well if you want to use lots of feature flags because you might want to deploy separate staging sites for all combination of flags.&lt;/p&gt;

&lt;p&gt;Happy roasting!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>github</category>
    </item>
  </channel>
</rss>
