<?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: Alex Eagleson</title>
    <description>The latest articles on DEV Community by Alex Eagleson (@alexeagleson).</description>
    <link>https://dev.to/alexeagleson</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%2F657194%2Fbb84cc4e-2299-4b57-b785-92c087327839.png</url>
      <title>DEV Community: Alex Eagleson</title>
      <link>https://dev.to/alexeagleson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexeagleson"/>
    <language>en</language>
    <item>
      <title>How to Set Up a Fullstack Rust Project with Axum, React, Vite, and Shared Types</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Tue, 18 Oct 2022 13:28:33 +0000</pubDate>
      <link>https://dev.to/alexeagleson/how-to-set-up-a-fullstack-rust-project-with-axum-react-vite-and-shared-types-429e</link>
      <guid>https://dev.to/alexeagleson/how-to-set-up-a-fullstack-rust-project-with-axum-react-vite-and-shared-types-429e</guid>
      <description>&lt;h1&gt;
  
  
  Table of Contents
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Motivation&lt;/li&gt;
&lt;li&gt;Project Setup&lt;/li&gt;
&lt;li&gt;Rust Server&lt;/li&gt;
&lt;li&gt;React Client&lt;/li&gt;
&lt;li&gt;Sharing Types&lt;/li&gt;
&lt;li&gt;Add Styles&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Motivation
&lt;/h1&gt;

&lt;p&gt;In this tutorial, I'll be demonstrating how to create a template for a fullstack web app using &lt;a href="https://github.com/tokio-rs/axum" rel="noopener noreferrer"&gt;Axum&lt;/a&gt; as the backend in Rust, and React with &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; for the frontend.&lt;/p&gt;

&lt;p&gt;We'll also be taking advantage of the &lt;a href="https://dev.to/alexeagleson/how-to-build-a-rust-cli-tool-to-generate-typescript-types-from-rust-20cm"&gt;Typescript type generating tool we built in a previous tutorial&lt;/a&gt; to generate TS types from Rust code and share types between our frontend and backend.  This is a common benefit of working with a Node.js driven backend, but more difficult to achieve when building in another language (like Rust!)&lt;/p&gt;

&lt;h1&gt;
  
  
  Project Setup
&lt;/h1&gt;

&lt;p&gt;If you're following along after completing the previous tutorial, then I suggest you create your app in a folder right next to your type generation CLI so that you can easily invoke it without dealing with painful file paths.  &lt;/p&gt;

&lt;p&gt;Alternatively if you published it, you can install the utility with &lt;code&gt;cargo install&lt;/code&gt;, or simply install the demo one I created for the tutorial with &lt;code&gt;cargo install typester&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(You can even follow this tutorial simply for the template setup and not use the type sharing utility at all if you choose)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Open your terminal where you'd like to create the project and run this command:&lt;/p&gt;

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

cargo new fullstack-app
cd fullstack-app


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

&lt;/div&gt;

&lt;p&gt;Open up &lt;code&gt;/fullstack-app&lt;/code&gt; in your IDE and add the following dependencies to your &lt;code&gt;Cargo.toml&lt;/code&gt; file:&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;[package]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"fullstack-app"&lt;/span&gt;
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.0"&lt;/span&gt;
&lt;span class="py"&gt;edition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2021"&lt;/span&gt;

&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;axum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.5.16"&lt;/span&gt;
&lt;span class="py"&gt;serde&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"derive"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;serde_json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.68"&lt;/span&gt;
&lt;span class="py"&gt;tokio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"full"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;tower-http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.3.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"cors"&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 addition to &lt;code&gt;axum&lt;/code&gt; for the web server, which is built on &lt;code&gt;tokio&lt;/code&gt;, we also use &lt;code&gt;tower-http&lt;/code&gt; to simplify CORS.&lt;/p&gt;

&lt;p&gt;We will be using &lt;code&gt;serde&lt;/code&gt; and &lt;code&gt;serde_json&lt;/code&gt; for serialization of our Rust data to send to the frontend.  &lt;/p&gt;

&lt;h1&gt;
  
  
  Rust Server
&lt;/h1&gt;

&lt;p&gt;Begin by opening up &lt;code&gt;main.rs&lt;/code&gt; and replacing it with this simple template for a web server with returns &lt;em&gt;"Hello, world!"&lt;/em&gt; at the root route: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;fullstack-app/src/main.rs&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;net&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SocketAddr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tower_http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CorsLayer&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CorsLayer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.allow_origin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&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="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SocketAddr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"listening on {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nn"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="nf"&gt;.into_make_service&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;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;If you are familiar with web servers in other languages this should all look pretty familiar.  The &lt;code&gt;root()&lt;/code&gt; function is the route handler for &lt;code&gt;/&lt;/code&gt; which is set here:&lt;/p&gt;

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

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&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="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;.layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cors&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 be using a very permissive set of rules for CORS to avoid any issues testing locally, though you'll likely want to adjust this before you publish the app live.&lt;/p&gt;

&lt;p&gt;Let's test it out!  Start your server with:&lt;/p&gt;

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

cargo run


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

&lt;/div&gt;

&lt;p&gt;You should be able to visit &lt;a href=""&gt;http://localhost:3000&lt;/a&gt; and see the &lt;em&gt;&lt;strong&gt;"Hello, World!"&lt;/strong&gt;&lt;/em&gt; response from your root route.&lt;/p&gt;

&lt;p&gt;Once you have that working we'll add a route that returns some serialized Rust data. &lt;/p&gt;

&lt;p&gt;First we'll create a second file in &lt;code&gt;src&lt;/code&gt; called &lt;code&gt;types.rs&lt;/code&gt; similar to how we did in the Typester project.&lt;/p&gt;

&lt;p&gt;Populate it with the following type:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fullstack-app/src/types.rs&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;serde&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Serialize)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;favourite_food&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;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 keep it fairly simple for this demonstration, just a basic struct. You can add more complex types later if you like.&lt;/p&gt;

&lt;p&gt;Now let's update our server code to include a GET route that returns a serialized vector of Person structs. &lt;/p&gt;

&lt;p&gt;When this is deserialized in Typescript the front end should expect to receive an array of Person objects.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fullstack-app/src/main.rs&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IntoResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;net&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SocketAddr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tower_http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CorsLayer&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// NEW&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;types&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CorsLayer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.allow_origin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&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="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="c1"&gt;// NEW&lt;/span&gt;
        &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/people"&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="n"&gt;get_people&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SocketAddr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"listening on {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nn"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="nf"&gt;.into_make_service&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;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// NEW&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_people&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;IntoResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Person A"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;favourite_food&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pizza"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Person B"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;favourite_food&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Broccoli"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Person C"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;favourite_food&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;OK&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="n"&gt;people&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;There are three blocks in the above I've annotated as &lt;code&gt;// NEW&lt;/code&gt; to indicate the changes we have made to the origin example of &lt;code&gt;main.rs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We've imported the types from the &lt;code&gt;types.rs&lt;/code&gt; file, created a new route function called &lt;code&gt;get_people&lt;/code&gt; which returns a vector of example people as JSON (the &lt;code&gt;Json&lt;/code&gt; struct takes care of the serialization for us using &lt;code&gt;serde&lt;/code&gt; in the background).&lt;/p&gt;

&lt;h1&gt;
  
  
  React Client
&lt;/h1&gt;

&lt;p&gt;Now let's create the front end client that will access the server we just created.&lt;/p&gt;

&lt;p&gt;From your &lt;code&gt;/fullstack-app&lt;/code&gt; directory run the following command (make sure you have &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;NodeJs&lt;/a&gt; installed first):&lt;/p&gt;

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

npm create vite@latest


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

&lt;/div&gt;

&lt;p&gt;For project name choose &lt;code&gt;client&lt;/code&gt; and for the template choose &lt;code&gt;React&lt;/code&gt; with &lt;code&gt;Typescript&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;App.tsx&lt;/code&gt; and replace the sample code with the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fullstack-app/client/src/App.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&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;react&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;Person&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;./types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;people&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPeople&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Person&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="nf"&gt;useEffect&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="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;http://localhost:3000/people&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;people&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setPeople&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;people&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;people&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;person&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="nt"&gt;p&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;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; is &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; years old
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&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="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;
&lt;h1&gt;
  
  
  Sharing Types
&lt;/h1&gt;

&lt;p&gt;You'll find that you have an error in the above code.  Where is the &lt;code&gt;Person&lt;/code&gt; type coming from?  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;types&lt;/code&gt; file it's trying to import is not defined.&lt;/p&gt;

&lt;p&gt;We'll use our typegen utility to create it!&lt;/p&gt;

&lt;p&gt;Now the way that you use it is really going to depend on a few factors, such as whether you did the previous tutorial, and whether you published it.  If you didn't do it at all, the third option will be to simply use the version I published with the post:&lt;/p&gt;
&lt;h3&gt;
  
  
  Option 1: Run your local copy
&lt;/h3&gt;

&lt;p&gt;Let's say you have your typegen utility in a folder adjacent to this app like so:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

/YOUR_TYPEGEN_PROGRAM
/fullstack-app


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

&lt;/div&gt;

&lt;p&gt;Then you will invoke it with the following command from the &lt;code&gt;/YOUR_TYPEGEN_PROGRAM&lt;/code&gt; directory (or whatever you named yours):&lt;/p&gt;

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

cargo run -- --input=../fullstack-app/src/types.rs --output=../fullstack-app/client/src/types.d.ts


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Option 2: Run your published copy
&lt;/h3&gt;

&lt;p&gt;If you published your copy to &lt;code&gt;crates.io&lt;/code&gt; then you can install it on your machine with:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

cargo install YOUR_TYPEGEN_PROGRAM


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

&lt;/div&gt;

&lt;p&gt;And then from within the &lt;code&gt;/fullstack-app&lt;/code&gt; directory:&lt;/p&gt;

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

YOUR_TYPEGEN_PROGRAM --input=./src/types.rs --output=./client/src/types.d.ts


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Option 3: Run my Published Copy
&lt;/h3&gt;

&lt;p&gt;If you didn't follow the previous tutorial you can &lt;a href="https://crates.io/crates/typester" rel="noopener noreferrer"&gt;simply use mine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just repeat &lt;code&gt;Option 2&lt;/code&gt; with &lt;code&gt;typester&lt;/code&gt; in place of &lt;code&gt;YOUR_TYPEGEN_PROGRAM&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Option 4: Run something more feature complete and production ready
&lt;/h3&gt;

&lt;p&gt;If you're looking to take this little boilerplate demo further into something really usable (and not specifically interested in building your own type sharing library) then our little demo from the &lt;a href="https://dev.to/alexeagleson/how-to-build-a-rust-cli-tool-to-generate-typescript-types-from-rust-20cm"&gt;previous tutorial&lt;/a&gt; probably won't get you very far.&lt;/p&gt;

&lt;p&gt;Here's a couple of much more feature rich options available out there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/1Password/typeshare" rel="noopener noreferrer"&gt;Typeshare&lt;/a&gt; by &lt;a href="https://1password.com/" rel="noopener noreferrer"&gt;1Password&lt;/a&gt;, the original inspiration for this blog post.  It's available on &lt;a href="https://crates.io/crates/typeshare" rel="noopener noreferrer"&gt;crates.io&lt;/a&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Wulf/create-rust-app" rel="noopener noreferrer"&gt;tsync&lt;/a&gt; by Wulf created as part of the awesome &lt;a href="https://github.com/Wulf/create-rust-app" rel="noopener noreferrer"&gt;Create Rust App&lt;/a&gt; utility for setting up fullstack Rust apps.  It's available on &lt;a href="https://crates.io/crates/tsync" rel="noopener noreferrer"&gt;crates.io&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you choose to use one of these make sure you read their documentation as the API will be different from our utility we built.&lt;/p&gt;



&lt;p&gt;If all goes well you'll have a generated file with the following filename and content:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;client/src/types.d.ts&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;type&lt;/span&gt; &lt;span class="nx"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&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;type&lt;/span&gt; &lt;span class="nx"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;type&lt;/span&gt; &lt;span class="nx"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;favourite_food&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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;With this type file in place you should no longer see any error in your &lt;code&gt;App.tsx&lt;/code&gt; file and &lt;code&gt;person&lt;/code&gt; should be correctly typed and identifiable as a &lt;code&gt;Person&lt;/code&gt; by your IDE for type checking and intellisense.  &lt;/p&gt;

&lt;p&gt;Here's a look at how VS Code will interpret it:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1666050136%2Faxum_server%2Fts_example_chvbjf.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1666050136%2Faxum_server%2Fts_example_chvbjf.png" alt="Type Hint Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Add Styles
&lt;/h1&gt;

&lt;p&gt;Just before we test out the finished version live, let's just it a quick pass with some CSS and turn these people into some basic employee cards.&lt;/p&gt;

&lt;p&gt;We'll be straight up pulling it directly from &lt;a href="https://www.w3schools.com/howto/howto_css_cards.asp" rel="noopener noreferrer"&gt;this simple example here&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;App.css&lt;/code&gt; directly beside &lt;code&gt;App.tsx&lt;/code&gt; (or override the one that is included with the project by default) and add this CSS:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;client/src/App.css&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="nc"&gt;.app&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;column-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300px&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;Next, update your &lt;code&gt;App.tsx&lt;/code&gt; to include the following.  You can feel free to change the avatar URLs if you choose.  Make sure you don't miss the &lt;code&gt;import "App.css";&lt;/code&gt; in there!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;client/src/App.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&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;react&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;Person&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;./types&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.css&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;AVATAR_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://res.cloudinary.com/dqse2txyi/image/upload/v1666049372/axum_server/img_avatar_lf92vl.png&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;AVATAR_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://res.cloudinary.com/dqse2txyi/image/upload/v1666049372/axum_server/img_avatar2_erqray.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;people&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPeople&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Person&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="nf"&gt;useEffect&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="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;http://localhost:3000/people&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;people&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setPeople&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;people&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"app"&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;people&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;AVATAR_1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AVATAR_2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Avatar"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;b&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;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;b&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Age: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Favourite Food: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favourite_food&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unknown&lt;/span&gt;&lt;span class="dl"&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Now, start up your Rust web server:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Make sure you are in the &lt;code&gt;/fullstack-app&lt;/code&gt; directory!)&lt;/em&gt;&lt;/p&gt;

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

cargo run


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

&lt;/div&gt;

&lt;p&gt;You should see this output:&lt;/p&gt;

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

listening on 127.0.0.1:3000


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

&lt;/div&gt;

&lt;p&gt;Next start your front end Vite dev server.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Make sure you are in the &lt;code&gt;/fullstack-app/client&lt;/code&gt; directory!)&lt;/em&gt;&lt;/p&gt;

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

npm run dev


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

&lt;/div&gt;

&lt;p&gt;If you see any errors on these commands, double check again that you are running them from the directories listed above.&lt;/p&gt;

&lt;p&gt;With both running visit the default Vite server URL/port at:&lt;/p&gt;

&lt;p&gt;&lt;a href=""&gt;http://localhost:5173/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enjoy your beautiful new app!&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1666050412%2Faxum_server%2Fpeople_cards_kjur37.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1666050412%2Faxum_server%2Fpeople_cards_kjur37.png" alt="People Cards"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I hope you've learned something new about building a web app using the best of both worlds (Rust and Typescript).  I would encourage you to keep developing on this idea and see what additional features you can build!&lt;/p&gt;

&lt;p&gt;That said if you are looking for something more production ready, I would highly encourage you to check out Wulf's &lt;a href="https://github.com/Wulf/create-rust-app" rel="noopener noreferrer"&gt;Create Rust App&lt;/a&gt;, a fantastic template built in the same vein of this project, but much more feature complete.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>typescript</category>
      <category>react</category>
      <category>vite</category>
    </item>
    <item>
      <title>How to Build a Rust CLI Tool to Generate Typescript Types from Rust</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Tue, 18 Oct 2022 13:27:13 +0000</pubDate>
      <link>https://dev.to/alexeagleson/how-to-build-a-rust-cli-tool-to-generate-typescript-types-from-rust-20cm</link>
      <guid>https://dev.to/alexeagleson/how-to-build-a-rust-cli-tool-to-generate-typescript-types-from-rust-20cm</guid>
      <description>&lt;h1&gt;
  
  
  Table of Contents
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Motivation&lt;/li&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Project Setup&lt;/li&gt;
&lt;li&gt;Building the CLI&lt;/li&gt;
&lt;li&gt;Working with Files&lt;/li&gt;
&lt;li&gt;Basic Types&lt;/li&gt;
&lt;li&gt;Enums&lt;/li&gt;
&lt;li&gt;Structs&lt;/li&gt;
&lt;li&gt;Tuples&lt;/li&gt;
&lt;li&gt;Standard Library Types&lt;/li&gt;
&lt;li&gt;Tests&lt;/li&gt;
&lt;li&gt;Building and Publishing&lt;/li&gt;
&lt;li&gt;Future Improvements&lt;/li&gt;
&lt;li&gt;Similar Open Source Tools&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Motivation
&lt;/h1&gt;

&lt;p&gt;Why would you want to write a tool that converts Rust types to Typescript types? Aren't they entirely separate languages?&lt;/p&gt;

&lt;p&gt;There are many reasons you might want to do so. The most common (though far from the only) case that we'll be focusing on is someone who is writing an API (like a web server) in Rust and consuming it with a Typescript frontend.&lt;/p&gt;

&lt;p&gt;Being able to automate the sharing types defined on the backend with the frontend has a lot of benefits and and can significantly reduce development time spent re-writing the same definitions in multiple languages.&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Our very first goal will be to turn this into valid Typescript code by writing the type definitions in Rust and using our program to convert them into Typescript types:&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;NumberAlias&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;./types&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;printNum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NumberAlias&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;printNum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try and paste this code into a &lt;code&gt;.ts&lt;/code&gt; file and run it you will get an error saying &lt;code&gt;NumberAlias&lt;/code&gt; is undefined and the &lt;code&gt;types&lt;/code&gt; file you are trying to import it from does not exist. We will use the output of our program to create that file.&lt;/p&gt;

&lt;p&gt;Type aliases work almost identically in Rust as they do in TS so this first challenge will be very simple in terms of output. Our goal is to generate the file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.d.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this Rust input file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Project Setup
&lt;/h1&gt;

&lt;p&gt;There are two crates we will be relying on to develop out type conversion utility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://crates.io/crates/clap"&gt;clap&lt;/a&gt; short for &lt;em&gt;Command Line Argument Parser&lt;/em&gt; is the most popular Rust crate for dealing with command line arguments. We'll be using it to allow our uses to tell us the input/out filenames of the Rust and Typescript files they are using,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://crates.io/crates/syn"&gt;syn&lt;/a&gt; derived from the word &lt;em&gt;syntax&lt;/em&gt; is a crate designed to convert Rust source code into a type-safe syntax tree where each token can be examined and parsed individually.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open up your favourite terminal. Make sure you have &lt;a href="https://www.rust-lang.org/tools/install"&gt;installed Rust on your system&lt;/a&gt;. Fresh installations will also include Rust's package manager called &lt;a href="https://doc.rust-lang.org/cargo/"&gt;Cargo&lt;/a&gt; which we'll need for this tutorial.&lt;/p&gt;

&lt;p&gt;When you're ready run the following command to create the utility. I've decided to call mine &lt;code&gt;typester&lt;/code&gt;, but you can call yours whatever you like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo new typester
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;Cargo.toml&lt;/code&gt; file (equivalent to &lt;code&gt;package.json&lt;/code&gt; in the JS/TS world) and an &lt;code&gt;src&lt;/code&gt; directory with a &lt;code&gt;main.rs&lt;/code&gt; file with a demo program. Test it out with &lt;code&gt;cargo run&lt;/code&gt; and you should see "Hello, world!" printed to your terminal.&lt;/p&gt;

&lt;p&gt;Next we will add the two packages (crates) that we need to write our program. Run the following command to automatically add the latest versions to your &lt;code&gt;Cargo.toml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo add clap
cargo add syn --features=full,extra-traits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;syn&lt;/code&gt; crate does not include all features by default, so make sure you include the ones I've listed above. Full gives us access to the &lt;code&gt;parse_file&lt;/code&gt; function and extra-traits derives &lt;code&gt;Debug&lt;/code&gt; for syn's types to make it easier for us to log values and debug our code.&lt;/p&gt;

&lt;p&gt;After adding your &lt;code&gt;Cargo.toml&lt;/code&gt; file should include the following:&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;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;clap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"4.0.9"&lt;/span&gt;
&lt;span class="nn"&gt;syn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.101"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"full"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"extra-traits"&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 version numbers may not match exactly, though if you are seeing different major versions I would recommend you align with the versions shown above for the sake of this tutorial in case either library has introduced breaking API changes since it was written.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building the CLI
&lt;/h1&gt;

&lt;p&gt;Before diving into the parsing itself, let's take a moment to set up the command line argument parsing with the &lt;code&gt;clap&lt;/code&gt; crate. Fortunately for us, clap makes that extremely easy.&lt;/p&gt;

&lt;p&gt;Here's some sample code. You can review clap's &lt;a href="https://docs.rs/clap/4.0.9/clap/index.html"&gt;documentation&lt;/a&gt; for the version we are using, or read ahead for a brief overview.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Typester"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.1.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.author&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alex E"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Convert Rust types to Typescript types"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nn"&gt;Arg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'i'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.long&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.help&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The Rust file to process (including extension)"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.arg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nn"&gt;Arg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.short&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'o'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.long&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;.help&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The name of the Typescript file to output (including extension)"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.get_matches&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="py"&gt;.get_one&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input required"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;output_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;
        &lt;span class="py"&gt;.get_one&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output required"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_filename&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_filename&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 above code will provide you with a great baseline to get started. It forces the user to define both a input filename (Rust) and an output filename (Typescript).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;clap&lt;/code&gt; takes care of some really handy grunt work like providing a nicely formatted &lt;code&gt;--help&lt;/code&gt; output and enforcing required arguments.&lt;/p&gt;

&lt;p&gt;Before testing the program out, it's good to understand a Rust CLI's (command line interface) argument structure. When compiling a release binary you can simply add the arguments as any other CLI after the name of the program, but for &lt;code&gt;cargo run&lt;/code&gt; you need to separate the &lt;code&gt;run&lt;/code&gt; and arguments with two hyphens like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo run &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src/types.rs &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;types.d.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of this command with our program will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[src/main.rs:29] input_filename = "src/types.rs"
[src/main.rs:30] output_filename = "types.d.ts"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Furthermore, as a user who may not be aware of the required arguments can take advantage of the &lt;code&gt;--help&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Convert Rust types to Typescript types

Usage: typester --input &amp;lt;input&amp;gt; --output &amp;lt;output&amp;gt;

Options:
  -i, --input &amp;lt;input&amp;gt;    The Rust file to process (including extension)
  -o, --output &amp;lt;output&amp;gt;  The name of the Typescript file to output (including extension)
  -h, --help             Print help information
  -V, --version          Print version information
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That nicely formatted help output is thanks to the great &lt;code&gt;clap&lt;/code&gt; crate.&lt;/p&gt;

&lt;h1&gt;
  
  
  Working With Files
&lt;/h1&gt;

&lt;p&gt;We'll use the standard library's &lt;code&gt;File&lt;/code&gt;, &lt;code&gt;Read&lt;/code&gt; and &lt;code&gt;Path&lt;/code&gt; to read the contents of our Rust file, and then parse it into a &lt;code&gt;syn::File&lt;/code&gt; where we can iterate over the contents of the file in a typesafe manner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;
    &lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nn"&gt;path&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

     &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// Code from previous section&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_filename&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unable to open file {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_path&lt;/span&gt;&lt;span class="nf"&gt;.display&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;input_file&lt;/span&gt;
        &lt;span class="nf"&gt;.read_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unable to read file"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// This is our tokenized version of Rust file ready to process&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input_file_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unable to parse file"&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;Since this is a simple utility meant for learning and does not need to be bulletproof and handle every potential bad file input, we'll simply use &lt;code&gt;.expect()&lt;/code&gt; in each scenario that doesn't conform to our requirements.&lt;/p&gt;

&lt;p&gt;For those unfamiliar, &lt;code&gt;.expect()&lt;/code&gt; is the same as &lt;code&gt;.unwrap()&lt;/code&gt; which will &lt;code&gt;panic&lt;/code&gt; on a &lt;code&gt;Result&lt;/code&gt; of &lt;code&gt;Err&lt;/code&gt; or an &lt;code&gt;Option&lt;/code&gt; of &lt;code&gt;None&lt;/code&gt;, but it allows us to provide some information to the user as to where/why that failure occurred.&lt;/p&gt;

&lt;p&gt;Now that we have created a &lt;code&gt;syn:File&lt;/code&gt; which the contents of our Rust file ready to parse, we can iterate over each token one at a time and start converting them into strings of text that conform to Typescript's syntax rules.&lt;/p&gt;

&lt;p&gt;To do this we take our syn file and iterate over it with &lt;code&gt;.items.iter()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;
    &lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nn"&gt;path&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// Code from previous sections&lt;/span&gt;

    &lt;span class="c1"&gt;// This string will store the output of the Typescript file that we will&lt;/span&gt;
    &lt;span class="c1"&gt;// continuously append to as we process the Rust file&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="py"&gt;.items&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// This `Item::Type` enum variant matches our type alias&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;type_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_item_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;type_text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Encountered an unimplemented type"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;write!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write to output file"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_item_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ItemType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"todo"&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;At this point we are ready to test it out Create the following &lt;code&gt;types.rs&lt;/code&gt; file directly next to your &lt;code&gt;main.rs&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo run -- --input=src/types.rs --output=types.d.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note the &lt;code&gt;"--"&lt;/code&gt; before the input flag, this is a placeholder for the program name while we are building in development, make sure you include it or your program will not work properly.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In your root of your project you should see a &lt;code&gt;types.d.ts&lt;/code&gt; file appear containing the text &lt;code&gt;todo&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.d.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Basic Types
&lt;/h1&gt;

&lt;p&gt;Now we are ready to parse the actual tokens. We'll start with the simplest one, the basic type alias &lt;code&gt;type NumberAlias = i32;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The will match on &lt;code&gt;syn::Item::Type&lt;/code&gt; as we have written above and call our &lt;code&gt;parse_item_type&lt;/code&gt; function which we need to expand and define. Each of our parsing functions for the different types our crate handles will return a string so we can simply concatenate them all together to build the output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// Code from previous sections with `parse_item_type` stub removed&lt;/span&gt;

&lt;span class="cd"&gt;/// Converts a Rust item type to a Typescript type&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// ## Examples&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Input:** type NumberAlias = i32;&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Output:** export type NumberAlias = number;&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_item_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ItemType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"export type "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// `ident` is the name of the type alias, `NumberAlias` from the example&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="py"&gt;.ident&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" = "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;type_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="py"&gt;.ty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;type_string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;output_text&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;NumberAlias&lt;/code&gt; in our type will be captured with the &lt;code&gt;ident&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;i32&lt;/code&gt; portion however could be any number of type values, and not necessarily a primitive. It would be &lt;code&gt;(i32, i32)&lt;/code&gt; for example.&lt;/p&gt;

&lt;p&gt;For this we'll create another handler function called &lt;code&gt;parse_type&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Converts a Rust type into a Typescript type&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// ## Examples&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Input:** (i32, i32) / Option&amp;lt;String&amp;gt;&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Output:** \[number, number\] / Option&amp;lt;string&amp;gt;;&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;syn_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;syn_type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Primitive types like i32 will match Path&lt;/span&gt;
        &lt;span class="c1"&gt;// We currently do not do anything with full paths&lt;/span&gt;
        &lt;span class="c1"&gt;// so we take only the last() segment (the type name)&lt;/span&gt;
        &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;segment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;type_path&lt;/span&gt;&lt;span class="py"&gt;.path.segments&lt;/span&gt;&lt;span class="nf"&gt;.last&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;field_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;segment&lt;/span&gt;&lt;span class="py"&gt;.ident&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ts_field_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_type_ident&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;field_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.to_owned&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ts_field_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;segment&lt;/span&gt;&lt;span class="py"&gt;.arguments&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// A simple type like i32 matches here as it&lt;/span&gt;
                &lt;span class="c1"&gt;// does not include any arguments&lt;/span&gt;
                &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;PathArguments&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
                &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Encountered an unimplemented token"&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="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Encountered an unimplemented token"&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="n"&gt;output_text&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you an see above, we are only focusing on our simple type for the time being and ignoring all other matches.&lt;/p&gt;

&lt;p&gt;If any type that our utility does not know how to process is encountered, the &lt;code&gt;dbg!&lt;/code&gt; macro will print a message along with a convenient line number so user's can easily identify which condition was hit and expand on the utility if they choose.&lt;/p&gt;

&lt;p&gt;You may also notice that for this &lt;code&gt;Path&lt;/code&gt; type we have matched we are only taking the &lt;code&gt;last()&lt;/code&gt; token. That is because currently we are not doing anything with the other parts of the path (for example &lt;code&gt;std:fs:File&lt;/code&gt;), just extracting the name of the type.&lt;/p&gt;

&lt;p&gt;The final function necessary to finish our prototype we will call &lt;code&gt;parse_type_ident&lt;/code&gt; which deals with the most primitive types, or simply return the name of the type if it is a custom type.&lt;/p&gt;

&lt;p&gt;All of Rust's many different types of numbers will simply be treated as a &lt;code&gt;number&lt;/code&gt; when deserialized as Typescript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Convert a primitive Rust ident to an equivalent Typescript type name&lt;/span&gt;
&lt;span class="cd"&gt;/// Translate primitive types to Typescript equivalent otherwise&lt;/span&gt;
&lt;span class="cd"&gt;/// returns the ident untouched&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// ## Examples&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Input:** i32 / Option / bool;&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Output:** number / Option / boolean;&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_type_ident&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;ident&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"i8"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"i16"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"i32"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"i64"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"i128"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"u8"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"u16"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"u32"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"u64"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"f32"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"f64"&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"isize"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"usize"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"str"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"String"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"char"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"bool"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"boolean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're finally ready to try it out. Run the command again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo run -- --input=src/types.rs --output=types.d.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the input:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get the output:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.d.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's a valid Typescript type!&lt;/p&gt;

&lt;p&gt;Congratulations, we have our first minimum prototype for a Rust -&amp;gt; TS conversion utility.&lt;/p&gt;

&lt;p&gt;Of course as you can imagine, getting complete support for serialization of all Rust's types is a monumental effort, likely requiring months or years of continued development.&lt;/p&gt;

&lt;p&gt;But fortunately like many things, 10-20% coverage of the most common types will take care of probably 80-90% of the most common use cases.&lt;/p&gt;

&lt;p&gt;So let's focus on getting a few more of the most common cases covered, most specifically: &lt;code&gt;enums&lt;/code&gt; and &lt;code&gt;structs&lt;/code&gt;:&lt;/p&gt;

&lt;h1&gt;
  
  
  Enums
&lt;/h1&gt;

&lt;p&gt;This is the example &lt;code&gt;enum&lt;/code&gt; we'll be using to test our support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[serde(tag&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;content&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Colour&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the expected output we'll be trying to create:&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;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Colour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may be wondering what the &lt;code&gt;#[serde(tag = "t", content = "c")]&lt;/code&gt; attribute is for?&lt;/p&gt;

&lt;p&gt;Well it turns out there are quite a few different ways that an enum can be serialized. If you'd like to learn more about them &lt;a href="https://serde.rs/enum-representations.html"&gt;this page in the serde documentation covers all the standard ones.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The method we'll be using is called &lt;a href="https://serde.rs/enum-representations.html#adjacently-tagged"&gt;adjacently tagged&lt;/a&gt;, the reason for this is that it makes it very clean and easy to handle on the Typescript side by using &lt;a href="https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html"&gt;union types&lt;/a&gt; to discriminate on the &lt;code&gt;t&lt;/code&gt; value and infer the correct type of the content &lt;code&gt;c&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;Technically these &lt;code&gt;t&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt; values can be any name that you choose, and we could write our utility to parse the attribute and read what the user has set, but since we are focusing on simplicity for now we're going to operate on the assumption that the user is using &lt;code&gt;t&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With that preliminary assumption in place, we can now expand our initial match in the main function to include enums, and create a new &lt;code&gt;parse_item_enum&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// Main function from previous sections&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="py"&gt;.items&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// This `Item::Type` enum variant matches our type alias&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;type_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_item_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;type_text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_enum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;enum_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_item_enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_enum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;enum_text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Encountered an unimplemented type"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;write!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write to output file"&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;Now we create the &lt;code&gt;parse_item_enum&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;
&lt;span class="cd"&gt;/// Converts a Rust enum to a Typescript type&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// ## Examples&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Input:**&lt;/span&gt;
&lt;span class="cd"&gt;/// enum Colour {&lt;/span&gt;
&lt;span class="cd"&gt;///     Red(i32, i32),&lt;/span&gt;
&lt;span class="cd"&gt;///     Green(i32),&lt;/span&gt;
&lt;span class="cd"&gt;///     Blue(i32),&lt;/span&gt;
&lt;span class="cd"&gt;/// }&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Output:**&lt;/span&gt;
&lt;span class="cd"&gt;/// export type Colour =&lt;/span&gt;
&lt;span class="cd"&gt;///   | { t: "Red"; c: number }&lt;/span&gt;
&lt;span class="cd"&gt;///   | { t: "Green"; c: number }&lt;/span&gt;
&lt;span class="cd"&gt;///   | { t: "Blue"; c: number };&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_item_enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_enum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ItemEnum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"export type"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;enum_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item_enum&lt;/span&gt;&lt;span class="py"&gt;.ident&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;enum_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"="&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item_enum&lt;/span&gt;&lt;span class="py"&gt;.variants&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Use the pipe character for union types&lt;/span&gt;
        &lt;span class="c1"&gt;// Typescript also allows it before the first type as valid syntax&lt;/span&gt;
        &lt;span class="c1"&gt;// https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types&lt;/span&gt;
        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" | {"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// For simplicity this implementation we are using assumes that enums will be&lt;/span&gt;
        &lt;span class="c1"&gt;// using serde's "Adjacently Tagged" attribute&lt;/span&gt;
        &lt;span class="c1"&gt;// #[serde(tag = "t", content = "c")]&lt;/span&gt;
        &lt;span class="c1"&gt;// https://serde.rs/enum-representations.html#adjacently-tagged&lt;/span&gt;
        &lt;span class="c1"&gt;// As an improvement on this implementation you could parse the attribute&lt;/span&gt;
        &lt;span class="c1"&gt;// and handle the enum differently depending on which attribute the user chose&lt;/span&gt;
        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"t: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;variant_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="py"&gt;.ident&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;variant_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt; , c: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="py"&gt;.fields&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Named&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;named_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;named_fields&lt;/span&gt;&lt;span class="py"&gt;.named&lt;/span&gt;&lt;span class="nf"&gt;.iter&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="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="py"&gt;.ident&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
                        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;field_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="py"&gt;.ty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;field_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&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="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Unnamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unnamed_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Currently only support a single unnamed field: e.g the i32 in Blue(i32)&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;unnamed_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unnamed_fields&lt;/span&gt;&lt;span class="py"&gt;.unnamed&lt;/span&gt;&lt;span class="nf"&gt;.first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;field_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;unnamed_field&lt;/span&gt;&lt;span class="py"&gt;.ty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;field_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Unit&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"undefined"&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="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;output_text&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've included comments above to annotate some of the sections that may be a bit more difficult to follow. &lt;/p&gt;

&lt;p&gt;The great thing is that we are already seeing the benefits of reuse with the previous functions we created like &lt;code&gt;parse_type&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;As you continue to developer and improve this utility you'll find that creaking eac individual token parser into its own function allows for a lot of opportunities for reuse when you start handling more complex types.&lt;/p&gt;

&lt;p&gt;With this in place we are now ready to test:&lt;/p&gt;

&lt;p&gt;Expand our &lt;code&gt;types.rs&lt;/code&gt; file to include both types we now support:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[serde(tag&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;content&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Colour&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&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;Run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo run -- --input=src/types.rs --output=types.d.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our output will be:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.d.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Colour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note that I am using a Typescript formatter, specifically &lt;a href="https://prettier.io/"&gt;prettier&lt;/a&gt;, on the output to make it more human friendly.  The actual output, while totally valid TS, will appear on a single line)&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Structs
&lt;/h1&gt;

&lt;p&gt;Now let's add support for structs.  Our example test input will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enjoys_coffee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our expected output will be:&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;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;enjoys_coffee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;Update the match in the &lt;code&gt;main&lt;/code&gt; function to match on &lt;code&gt;syn::Item::Struct&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;    &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// Main function from previous sections&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="py"&gt;.items&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;type_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_item_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;type_text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_enum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;enum_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_item_enum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_enum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;enum_text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Struct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_struct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;struct_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_item_struct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_struct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;struct_text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Encountered an unimplemented type"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nd"&gt;write!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write to output file"&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;Create the &lt;code&gt;parse_item_struct&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Converts a Rust struct to a Typescript interface&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// ## Examples&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Input:**&lt;/span&gt;
&lt;span class="cd"&gt;/// struct Person {&lt;/span&gt;
&lt;span class="cd"&gt;///     name: String,&lt;/span&gt;
&lt;span class="cd"&gt;///     age: u32,&lt;/span&gt;
&lt;span class="cd"&gt;///     enjoys_coffee: bool,&lt;/span&gt;
&lt;span class="cd"&gt;/// }&lt;/span&gt;
&lt;span class="cd"&gt;///&lt;/span&gt;
&lt;span class="cd"&gt;/// **Output:**&lt;/span&gt;
&lt;span class="cd"&gt;/// export interface Person {&lt;/span&gt;
&lt;span class="cd"&gt;///     name: string;&lt;/span&gt;
&lt;span class="cd"&gt;///     age: number;&lt;/span&gt;
&lt;span class="cd"&gt;///     enjoys_coffee: boolean;&lt;/span&gt;
&lt;span class="cd"&gt;/// }&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_item_struct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_struct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ItemStruct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;struct_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item_struct&lt;/span&gt;&lt;span class="py"&gt;.ident&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"export interface"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;struct_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;item_struct&lt;/span&gt;&lt;span class="py"&gt;.fields&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Named&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;named_fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;named_field&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;named_fields&lt;/span&gt;&lt;span class="py"&gt;.named&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;named_field&lt;/span&gt;&lt;span class="py"&gt;.ident&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;field_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ident&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;field_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;field_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;named_field&lt;/span&gt;&lt;span class="py"&gt;.ty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;field_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// For tuple structs we will serialize them as interfaces with&lt;/span&gt;
        &lt;span class="c1"&gt;// fields named for the numerical index to align with serde's&lt;/span&gt;
        &lt;span class="c1"&gt;// default handling of this type&lt;/span&gt;
        &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Unnamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Example: struct Something (i32, Anything);&lt;/span&gt;
            &lt;span class="c1"&gt;// Output: export interface Something { 0: i32, 1: Anything }&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="py"&gt;.unnamed&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.enumerate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nf"&gt;parse_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="py"&gt;.ty&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
                &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&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="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Unit&lt;/span&gt; &lt;span class="k"&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="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;output_text&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's test it out:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[serde(tag&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;content&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Colour&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enjoys_coffee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo run -- --input=src/types.rs --output=types.d.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our output:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.d.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Colour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;enjoys_coffee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;h1&gt;
  
  
  Tuples
&lt;/h1&gt;

&lt;p&gt;Tuples are a common data type in Rust that roughly correspond to array types in Typescript where each element has a specific type (so a tuple like &lt;code&gt;(i32, i32)&lt;/code&gt; for example would be translated to &lt;code&gt;[number, number]&lt;/code&gt; rather than the less specific &lt;code&gt;number[]&lt;/code&gt; that vectors would translate into.)&lt;/p&gt;

&lt;p&gt;We can add simple support by expanding the &lt;code&gt;match &amp;amp;segment.arguments&lt;/code&gt; in our &lt;code&gt;parse_type&lt;/code&gt; function to add this addition match arm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// in the `parse_type` function&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="c1"&gt;// Tuple types like (i32, i32) will match here&lt;/span&gt;
    &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type_tuple&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"["&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;elem&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;type_tuple&lt;/span&gt;&lt;span class="py"&gt;.elems&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nf"&gt;parse_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"]"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Standard Library Types
&lt;/h1&gt;

&lt;p&gt;As a final update, let's add support for some of Rust's most common types in the standard library like &lt;code&gt;Option&lt;/code&gt;, and &lt;code&gt;HashMap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The reason for these in particular is that they are common data types to be serialized, for example when parsed on the Javascript/Typescript side &lt;code&gt;Option&amp;lt;T&amp;gt;&lt;/code&gt; can be thought of as &lt;code&gt;T | undefined&lt;/code&gt; and &lt;code&gt;HashMap&amp;lt;T, U&amp;gt;&lt;/code&gt; can be deserialized as an object in the TS form of &lt;code&gt;Record&amp;lt;T, U&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No doubt you can come up with more, but here are some straightforward TS mappings of some of the most common data types. We don't need to do these dynamically, we can simply prepend these pre-written types to the file output before we begin to parse:&lt;/p&gt;

&lt;p&gt;Add the following line immediately after the variable &lt;code&gt;output_text&lt;/code&gt; is declared in the main function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nf"&gt;create_initial_types&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create that &lt;code&gt;create_initial_types&lt;/code&gt; function as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// Initialize some Typescript equivalents of&lt;/span&gt;
&lt;span class="cd"&gt;/// core Rust types like Result, Option, etc&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;create_initial_types&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;output_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;output_text&lt;/span&gt;
        &lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"type HashSet&amp;lt;T extends number | string&amp;gt; = Record&amp;lt;T, undefined&amp;gt;;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"type HashMap&amp;lt;T extends number | string, U&amp;gt; = Record&amp;lt;T, U&amp;gt;;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"type Vec&amp;lt;T&amp;gt; = Array&amp;lt;T&amp;gt;;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"type Option&amp;lt;T&amp;gt; = T | undefined;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"type Result&amp;lt;T, U&amp;gt; = T | U;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;output_text&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final version (of our incomplete program 😁) takes the following input:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[serde(tag&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;content&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Colour&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enjoys_coffee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ComplexType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;colour_map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Colour&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;list_of_names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;optional_person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&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;And produces the following valid Typescript output:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;types.d.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;type&lt;/span&gt; &lt;span class="nx"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&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;type&lt;/span&gt; &lt;span class="nx"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;type&lt;/span&gt; &lt;span class="nx"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;U&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Colour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Green&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;enjoys_coffee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ComplexType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;colour_map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Colour&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;list_of_names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;optional_person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Person&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;So now that we have the ability to share types between Rust and Typescript!&lt;/p&gt;

&lt;h1&gt;
  
  
  Tests
&lt;/h1&gt;

&lt;p&gt;It's always a good idea to add tests to your program/crate!  Let's add some basic ones to test that we get the output for our sample types that we have been working with.&lt;/p&gt;

&lt;p&gt;I'll start by creating a &lt;code&gt;tests&lt;/code&gt; in &lt;code&gt;src&lt;/code&gt;.  I'm going to create three files total:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/tests/type.rs
src/tests/enum.rs
src/tests/struct.rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These files will just have the three basic sample types we have been working with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/tests/type.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;NumberAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;src/tests/enum.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[serde(tag&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"t"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;content&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Colour&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;src/tests/struct.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enjoys_coffee&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&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;Next I'll write some simple test that read in these files and assert that the output matches the Typescript output that we expect, so that we can safely expand our type generating utility in the future and be able to know immediately by running our tests that we haven't broken any existing functionality:&lt;/p&gt;

&lt;p&gt;For now I'm simply going to add this testing module down at the bottom of &lt;code&gt;main.rs&lt;/code&gt; below the program itself and I'll use &lt;code&gt;use super::*&lt;/code&gt; so I have access to all the same modules that the main program does:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;
&lt;span class="nd"&gt;#[cfg(test)]&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;#[test]&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handles_type_alias&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./src/tests/type.rs"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;input_file&lt;/span&gt;&lt;span class="nf"&gt;.read_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input_file_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unable to parse file"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;typescript_types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_syn_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r#"export type NumberAlias = number;"#&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;typescript_types&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;#[test]&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handles_struct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./src/tests/struct.rs"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;input_file&lt;/span&gt;&lt;span class="nf"&gt;.read_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input_file_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unable to parse file"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;typescript_types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_syn_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;r#"export interface Person {name:string;age:number;enjoys_coffee:boolean;};"#&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;typescript_types&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;#[test]&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handles_enum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./src/tests/enum.rs"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;input_file&lt;/span&gt;&lt;span class="nf"&gt;.read_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input_file_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nn"&gt;syn&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input_file_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unable to parse file"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;typescript_types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_syn_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_syntax&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;r#"export type Colour =  | { t: "Red" , c: number} | { t: "Green" , c: number} | { t: "Blue" , c: number};"#&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;typescript_types&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we run the following command on the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would see the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;running 3 tests
test tests::handles_type_alias ... ok
test tests::handles_enum ... ok
test tests::handles_struct ... ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to keep your tests updated as you expand your utility!&lt;/p&gt;

&lt;h1&gt;
  
  
  Building and Publishing
&lt;/h1&gt;

&lt;p&gt;There are a few different ways we can use and share our program that we'll go over quickly.&lt;/p&gt;

&lt;p&gt;The first is with the command we have been using to do build and run a development version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo run -- --input=src/types.rs --output=types.d.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also build a release version with all the optimizations using:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then you'll find the &lt;code&gt;typester&lt;/code&gt; binary in the &lt;code&gt;target/release&lt;/code&gt; folder.  You can now place it anywhere on your machine and run it from the command line by navigating to the directory and invoking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./typester --input=src/types.rs --output=types.d.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last method if you want to share your utility with others, or use it on other machines is to publish it to &lt;a href="https://crates.io/"&gt;crates.io&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;You'll first need to upload your project to Github and make a crates.io account if you don't have one already.  &lt;a href="https://doc.rust-lang.org/cargo/reference/publishing.html"&gt;This tutorial will take you through all the steps you need to publish your crate.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can install your CLI locally with &lt;code&gt;cargo install YOUR_CRATE_NAME&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;You can see here I've &lt;a href="https://crates.io/crates/typester"&gt;published this utility to crates.io&lt;/a&gt; and now I can install it on any machine that has cargo installed with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo install typester
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which installs by default in your &lt;code&gt;$HOME/.cargo&lt;/code&gt; directory.  Now you can use the utility on any directory on your machine!&lt;/p&gt;

&lt;h1&gt;
  
  
  Future Improvements
&lt;/h1&gt;

&lt;p&gt;There's plenty of options for improving this crate you can pursue beyond just improving support for additional types within Rust's ecosystem.  &lt;/p&gt;

&lt;p&gt;Here's a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Target an entire project directory rather than just a single file with the &lt;a href="https://crates.io/crates/walkdir"&gt;walkdir&lt;/a&gt; crate&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Capture &lt;a href="https://doc.rust-lang.org/rust-by-example/meta/doc.html"&gt;doc comments&lt;/a&gt; for your types and convert them to &lt;a href="https://jsdoc.app/about-getting-started.html"&gt;jsdoc comments&lt;/a&gt; so your frontend dev team knows exactly how to use your types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom attributes.  We've already talked about parsing serde's attributes, what what about custom ones specifically for your crate like the ability to &lt;code&gt;#[ignore]&lt;/code&gt; types that aren't intended for frontend consumption?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Camel case.  Have your CLI watch for serde's &lt;a href="https://serde.rs/container-attrs.html"&gt;rename attribute&lt;/a&gt; and transform your struct fields into Typescript's standard of &lt;code&gt;camelCase&lt;/code&gt; from Rust's &lt;code&gt;snake_case&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generics!  Can you include support for them.  I don't even know where to start with that one, but it would probably be a great challenge.  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm sure you can come up with other great ideas too, feel free to comment on this post with your own!&lt;/p&gt;

&lt;h1&gt;
  
  
  Similar Open Source Tools
&lt;/h1&gt;

&lt;p&gt;If you are actually looking for a more robust version of this kind of tool and not interest in writing it yourself, there are a number of very similar and more feature rich versions of this utility out there already in the wild:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/1Password/typeshare"&gt;Typeshare&lt;/a&gt; by &lt;a href="https://1password.com/"&gt;1Password&lt;/a&gt;, the original inspiration for this blog post.  It's available on &lt;a href="https://crates.io/crates/typeshare"&gt;crates.io&lt;/a&gt;.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Wulf/create-rust-app"&gt;tsync&lt;/a&gt; by Wulf created as part of the awesome &lt;a href="https://github.com/Wulf/create-rust-app"&gt;Create Rust App&lt;/a&gt; utility for setting up fullstack Rust apps.  It's available on &lt;a href="https://crates.io/crates/tsync"&gt;crates.io&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I hope you learned something new about how Rust itself can be parsed with crates like &lt;code&gt;syn&lt;/code&gt; and different kinds of helpful utilities can be built out of it.&lt;/p&gt;

&lt;p&gt;There's no reason you can't add support for other languages you use too!  I simply chose Typescript as it's the one I'm most familiar with.&lt;/p&gt;

&lt;p&gt;In a &lt;a href="https://dev.to/alexeagleson/how-to-set-up-a-fullstack-rust-project-with-axum-react-vite-and-shared-types-429e"&gt;follow up blog post&lt;/a&gt;, we'll take a look at how to actually use this utility in a real fullstack application with an&lt;br&gt;
&lt;a href="https://github.com/tokio-rs/axum"&gt;Axum&lt;/a&gt; backend in Rust, and React with &lt;a href="https://vitejs.dev/"&gt;Vite&lt;/a&gt; for the frontend.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>typescript</category>
      <category>tutorial</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Complete Beginner's Guide to Web Development</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Wed, 21 Sep 2022 13:30:37 +0000</pubDate>
      <link>https://dev.to/alexeagleson/the-complete-beginners-guide-to-a-career-in-web-development-3fbl</link>
      <guid>https://dev.to/alexeagleson/the-complete-beginners-guide-to-a-career-in-web-development-3fbl</guid>
      <description>&lt;h1&gt;
  
  
  Topics
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Introduction&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a Front-End Developer?&lt;/li&gt;
&lt;li&gt;What is a Back-End Developer?&lt;/li&gt;
&lt;li&gt;What is a Full-Stack Developer?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Basic Tools and Concepts&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What Communication Tools are used?&lt;/li&gt;
&lt;li&gt;How do Meetings work?&lt;/li&gt;
&lt;li&gt;What is Project Management?&lt;/li&gt;
&lt;li&gt;What are Designs Systems?&lt;/li&gt;
&lt;li&gt;What are Designs Tools?&lt;/li&gt;
&lt;li&gt;How do Code Reviews work?&lt;/li&gt;
&lt;li&gt;What is Reading Code?&lt;/li&gt;
&lt;li&gt;Asking for Help&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Getting Started&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Computer Hardware&lt;/li&gt;
&lt;li&gt;A Working Environment&lt;/li&gt;
&lt;li&gt;A Way to Test Your Work&lt;/li&gt;
&lt;li&gt;A Goal to Work Toward&lt;/li&gt;
&lt;li&gt;A Resource to Learn From&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Web Development Basics&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How does a website get created?&lt;/li&gt;
&lt;li&gt;How can I build a website or web app?&lt;/li&gt;
&lt;li&gt;How can I build websites on my own computer?&lt;/li&gt;
&lt;li&gt;How do I set up a development environment on my computer?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;What is HTML?&lt;/li&gt;
&lt;li&gt;How do I use HTML?&lt;/li&gt;
&lt;li&gt;What else do I need to know about HTML?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning HTML?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Web Servers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a web server?&lt;/li&gt;
&lt;li&gt;What is a web request?&lt;/li&gt;
&lt;li&gt;How do I run a web server?&lt;/li&gt;
&lt;li&gt;What else do I need to know about web servers?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning web servers?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;What is CSS?&lt;/li&gt;
&lt;li&gt;How do I use CSS?&lt;/li&gt;
&lt;li&gt;What else do I need to know about CSS?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning CSS?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to0#what-is-javascript"&gt;What is Javascript?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How do I use Javascript?&lt;/li&gt;
&lt;li&gt;What is the DOM?&lt;/li&gt;
&lt;li&gt;How do I view the DOM?&lt;/li&gt;
&lt;li&gt;How do I add Javascript to a website?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning Javascript?&lt;/li&gt;
&lt;li&gt;What is Node.js&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning Node.js?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Command Line Terminal&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do I use the command line terminal?&lt;/li&gt;
&lt;li&gt;What else do I need to know about the command line terminal?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning the command line terminal?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;What is Git?&lt;/li&gt;
&lt;li&gt;What is a Version Control System (VCS)?&lt;/li&gt;
&lt;li&gt;How do I use Git?&lt;/li&gt;
&lt;li&gt;What is the difference between Git and Github?&lt;/li&gt;
&lt;li&gt;What else do I need to know about Git?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning Git?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;What is an API?&lt;/li&gt;
&lt;li&gt;How to I create an API?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning APIs?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Libraries and Package Management&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a library?&lt;/li&gt;
&lt;li&gt;What is a package?&lt;/li&gt;
&lt;li&gt;What is a package manager?&lt;/li&gt;
&lt;li&gt;What are NPM and Yarn?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;What is a database?&lt;/li&gt;
&lt;li&gt;How do I use a database?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning databases?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Front End Frameworks&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a front end framework?&lt;/li&gt;
&lt;li&gt;What are React, Angular, Vue and jQuery?&lt;/li&gt;
&lt;li&gt;What is a CSS framework?&lt;/li&gt;
&lt;li&gt;What are Bootstrap and TailwindCSS?&lt;/li&gt;
&lt;li&gt;How do I use a front end framework?&lt;/li&gt;
&lt;li&gt;How do I use React?&lt;/li&gt;
&lt;li&gt;What else do I need to know about React?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning React?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;What is Typescript?&lt;/li&gt;
&lt;li&gt;What is the difference between Typescript and Javascript?&lt;/li&gt;
&lt;li&gt;How do I use Typescript?&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning Typescript?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Web Hosting&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where do I host a website?&lt;/li&gt;
&lt;li&gt;How do I put my website on the internet?&lt;/li&gt;
&lt;li&gt;How do I host a web app?&lt;/li&gt;
&lt;li&gt;How do I host a React app?&lt;/li&gt;
&lt;li&gt;How do I host a Node.js server?&lt;/li&gt;
&lt;li&gt;How do I host a Node.js app?&lt;/li&gt;
&lt;li&gt;What is a CDN?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Web Domains&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is a URL?&lt;/li&gt;
&lt;li&gt;What is a domain name?&lt;/li&gt;
&lt;li&gt;What is DNS?&lt;/li&gt;
&lt;li&gt;How do I get a custom domain name?&lt;/li&gt;
&lt;li&gt;What is SSL?&lt;/li&gt;
&lt;li&gt;What is HTTPS?&lt;/li&gt;
&lt;li&gt;How do I get an SSL certificate?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;What is SSH?&lt;/li&gt;
&lt;li&gt;How do I use SSH?&lt;/li&gt;
&lt;li&gt;What are SSH keys?&lt;/li&gt;
&lt;li&gt;How do I generate SSH keys?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

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

&lt;ul&gt;
&lt;li&gt;What is CI/CD?&lt;/li&gt;
&lt;li&gt;What is Docker?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Interviewing and Job Hunting&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How long until I will be ready to apply for jobs?&lt;/li&gt;
&lt;li&gt;How do I know when I am ready to apply to jobs?&lt;/li&gt;
&lt;li&gt;Where do I find jobs?&lt;/li&gt;
&lt;li&gt;What programming language should I learn?&lt;/li&gt;
&lt;li&gt;Why are there so many different programming languages?&lt;/li&gt;
&lt;li&gt;What if I fail?&lt;/li&gt;
&lt;li&gt;What if I get overwhelmed?&lt;/li&gt;
&lt;li&gt;What are the most important factors in getting hired?&lt;/li&gt;
&lt;li&gt;How do I get a job when all companies want existing work experience?&lt;/li&gt;
&lt;li&gt;What can I expect from an interview?&lt;/li&gt;
&lt;li&gt;Do I need to get a degree?&lt;/li&gt;
&lt;li&gt;Do I need to go to college?&lt;/li&gt;
&lt;li&gt;Which factors most influence potential income?&lt;/li&gt;
&lt;li&gt;What other factors should I consider when applying to a company?&lt;/li&gt;
&lt;li&gt;How do I know if my expectations are too high?&lt;/li&gt;
&lt;li&gt;What if I find a job, but it's not what I was expecting?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;More Learning Resources&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to2#what-resources-should-I-use-to-learn-web-development"&gt;What resources should I use to learn web development?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning computer science?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Conclusion&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Welcome learners!
&lt;/h2&gt;

&lt;p&gt;This post is targeted at &lt;em&gt;anyone&lt;/em&gt; and &lt;strong&gt;&lt;em&gt;everyone&lt;/em&gt;&lt;/strong&gt; out there who has decided, for any reason at all -- that they would like to become a web developer.&lt;/p&gt;

&lt;p&gt;No matter your age, or experience level.  No matter whether you are a student, recent graduate, or someone who has had a lengthy career in a completely unrelated field.  This guide is for you.&lt;/p&gt;

&lt;p&gt;Although there is plenty of information that even experienced developers may find helpful, the primary audience I am aiming to target with this post are &lt;em&gt;complete beginners&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I know it can seem extremely overwhelming at first, and it's important to know that this is &lt;em&gt;totally normal&lt;/em&gt;.  The purpose is to give readers an introduction to a massive &lt;strong&gt;&lt;em&gt;range&lt;/em&gt;&lt;/strong&gt; of topics.  It is &lt;strong&gt;not&lt;/strong&gt; meant to be a fully comprehensive deep dive into any one of those topics &lt;em&gt;in particular&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Instead, at the end of each section where I discuss a concept, I will include a curated list of links and resources which you can visit to continue your learning on that topic.&lt;/p&gt;

&lt;p&gt;With a couple exceptions, all of these resources are entirely free.&lt;/p&gt;

&lt;p&gt;At any point a topic is spoken of or introduced, I will make an attempt to answer these three questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;What is it?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Why is it important?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;How do you use it?&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions are critical to beginners in particular as I know it can often be extremely difficult to bridge the gap between discussion of a concept and seeing how it's actually used in practical application. For example: I know websites use a programming language called &lt;em&gt;Javascript&lt;/em&gt; but where do I actually write that code and how do I make it run?&lt;/p&gt;

&lt;p&gt;If you encounter &lt;em&gt;anything&lt;/em&gt; in this tutorial that you feel is skipped over too quickly, please let me know in a comment and I will make a best effort to update it to be more clear.&lt;/p&gt;

&lt;p&gt;My goal here is to provide you with not only the technical details you need to know, but also answers to a lot of more generalized common questions that come up like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"How long do I need to practice before I can apply for jobs?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Do I need to go to college? (or back to college again?)"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"How do I know which things I even need to learn?"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In fact, maybe you're still so early in your journey that you don't even know what being a "web developer" means! And that's perfectly okay.&lt;/p&gt;

&lt;p&gt;Perhaps you're still in college and worried about what it's going to be like to apply for jobs when you graduate. Or maybe you hate your current job and you heard on the internet that being a web developer is a real sweet gig.&lt;/p&gt;

&lt;p&gt;Well, you're right it is. And it's a bit unique compared to some other professional fields like medicine, law or civil engineering where you really can learn and acquire all the skills necessary to succeed from the comfort of your own home entirely for free.&lt;/p&gt;

&lt;p&gt;That may not necessarily be the most efficient route, or the one that is right for you, but it does afford potential avenues of opportunity to a lot of people who might otherwise not have the same options.&lt;/p&gt;

&lt;p&gt;With that said it's important to state unequivocally that being accessible does not make it easy. Learning web development is difficult. &lt;em&gt;Really difficult.&lt;/em&gt; It's a massive field.&lt;/p&gt;

&lt;p&gt;That's the bad news.&lt;/p&gt;

&lt;p&gt;The good news, is that it's a &lt;em&gt;good kind of difficult&lt;/em&gt;. And you don't need to know everything. Not even close. I certainly don't.&lt;/p&gt;

&lt;p&gt;If your goal is to get employed, you just need to learn &lt;em&gt;enough&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Enough to get started and make small contributions to the big projects at the companies where you work. Enough to keep asking questions and learning as you go.&lt;/p&gt;

&lt;p&gt;This guide is designed to introduce you to the basics of the many concepts you'll encounter in the web development world, but keep you focused on that goal.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(I'll add one last reminder that if at any time you feel overwhelmed or that anything in this guide is too technical for you, even as a complete beginner, to please comment and leave feedback.  I will always be happy to try and improve things to help.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Aspiring to becoming a web developer (which itself is just a specific area of focus for the more generalized role of software developer) means signing up for a lifetime of learning.&lt;/p&gt;

&lt;p&gt;If that alone isn't enough to scare you aware right now, then that's a good sign you're on the right track.&lt;/p&gt;

&lt;p&gt;The very first lesson, and the first thing you need to learn, is to become comfortable with &lt;em&gt;&lt;strong&gt;not knowing how to do something&lt;/strong&gt;&lt;/em&gt;. It's going to happen to you &lt;strong&gt;constantly&lt;/strong&gt;. Even when you've got years of experience. There's a good chance that you'll encounter something you don't know how to do at first glance as frequently as every day.&lt;/p&gt;

&lt;p&gt;If you see yourself as someone who can be in that situation, and see it as a &lt;em&gt;challenge to overcome&lt;/em&gt; rather than an &lt;em&gt;impasse&lt;/em&gt;, then you are fortunate enough to possess what is probably the most important prerequisite for becoming a developer.&lt;/p&gt;

&lt;p&gt;The entire software industry exists because of people with that attitude, and it is entirely dependent on them to continue to function.&lt;/p&gt;

&lt;p&gt;If you're still reading I'm going to assume you've agreed that you are that kind of person. Great! Let's take this opportunity to test that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a roadmap or summary of everything I should learn?
&lt;/h3&gt;

&lt;p&gt;I'm going to hit you with a link that you might come across while you're beginning your journey. Maybe you've already come across it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before you click, acknowledge that part of being a developer is recognizing that it's perfectly okay not to know something. It's perfectly okay not to know lots of stuff!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Take a moment to skim through the link below. If you feel completely overwhelmed, remember that's totally normal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://roadmap.sh/frontend" rel="noopener noreferrer"&gt;The step-by-step roadmap to becoming a front-end developer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What do you think? That's a heck of a lot you're going to have to learn isn't it? Maybe this wasn't such a good idea?&lt;/p&gt;

&lt;p&gt;The reality is you're going to come across a lot of similar links like this while you are learning. They are often going to make you feel like maybe it's too much, that the journey will not be possible.&lt;/p&gt;

&lt;p&gt;I've been a developer for many years (including enough to be teaching and training others) and there's topics and tools on that list that not only have I never used -- but there's some I've never even heard of!&lt;/p&gt;

&lt;p&gt;I'm here to tell you definitively that if your goal is simply to "become employed as a web developer" then you can safely devote 100% of your attention to just the first five things on that list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Internet&lt;/strong&gt; (the browser and simple web servers)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML&lt;/strong&gt; (the structure of websites and web apps)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS&lt;/strong&gt; (the style/appearance of websites and web apps)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Javascript&lt;/strong&gt; (the interactivity and data for websites and web apps)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version control systems&lt;/strong&gt; (the ability to work with other team members and back up your project)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. Almost everything else on that list is simply a tool someone has created that boils down to one of the above (or makes it easier/faster to work with them).&lt;/p&gt;

&lt;p&gt;If you have a solid understanding of the fundamentals of those five things, then you will have the necessary knowledge to learn everything else.&lt;/p&gt;

&lt;p&gt;I'll pick a few random ones off the list to demonstrate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Electron&lt;/strong&gt;: Electron is a tool that uses &lt;em&gt;chromium&lt;/em&gt; (basically the Chrome browser) to let you write web apps that you actually install on your computer. It's popular because since it's Chrome based, you can write those apps and run them on almost any platform (Windows, Mac, Linux, etc). You write those apps in HTML, CSS and Javascript. So if you know those three, then you can easily learn Electron. Popular Electron apps include Slack, Discord and VS Code.

&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sass&lt;/strong&gt;: Sass is an enhanced version of CSS. It lets you write a bunch of extra syntax that you can't write in normal CSS in addition to regular CSS. Once it's written you use a little tool called a &lt;em&gt;preprocessor&lt;/em&gt; to convert that file into a regular CSS file. If you understand the fundamentals of CSS, you can easily learn SASS.

&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt;: React is a tool written in Javascript to make organizing and interacting with parts of the browser easier. Its syntax is basically a mix of HTML and Javascript together. Rather than having to manually write all the instructions for interacting with browser elements in Javascript, you can write re-usable React components to share behavior across different parts of your website or web app. Similar to SASS, a processor is then run over the React code to convert it into Javascript. If you understand the fundamentals of HTML and Javascript, then you can easily learn React.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are just three examples, but as I said the majority of topics on that roadmap could have similar descriptions. Most everything in the front-end ecosystem comes back around to HTML, CSS, and Javascript.&lt;/p&gt;

&lt;p&gt;HTML, CSS and Javascript &lt;em&gt;are&lt;/em&gt; the building blocks of the web, have been for decades, and despite what anyone says, there is no indication that is going to change anytime soon. Nothing is truly future proof, but those three are about as close as you get in the web development industry.&lt;/p&gt;

&lt;p&gt;So that basic introduction out of the way, let's talk about what being a &lt;em&gt;web developer&lt;/em&gt; really means.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a web developer?
&lt;/h3&gt;

&lt;p&gt;A &lt;em&gt;web developer&lt;/em&gt; is someone who contributes work to any part of a web page or application. It is a subset of the field of &lt;em&gt;software development&lt;/em&gt; describing someone who specifically works on projects that are accessed by users over the internet.&lt;/p&gt;

&lt;p&gt;It doesn't even necessarily mean writing code. For example you might build pages in Wix or Squarespace or Wordpress using drag-and-drop tools to place the elements where you want them.&lt;/p&gt;

&lt;p&gt;Anyone who works on building websites is a web developer (at least as far as I'm concerned). They're just using different tools.&lt;/p&gt;

&lt;p&gt;Nevertheless, the most common definition of a web developer is someone who uses HTML, CSS and Javascript to build websites and web apps.&lt;/p&gt;

&lt;p&gt;The majority of jobs out there hiring for a "developer" position are looking for those skills at absolute minimum. The majority of this tutorial will be focused on those three technologies.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the different between a Front-End, Back-End and Full-Stack developer?
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Front End Developer
&lt;/h3&gt;

&lt;p&gt;A front-end developer is someone whose focus is on the part of we pages and apps that the user sees. Their core tools are HTML, CSS and some Javascript.&lt;/p&gt;

&lt;p&gt;There is a very interesting article called &lt;a href="https://css-tricks.com/the-great-divide/" rel="noopener noreferrer"&gt;The Great Divide&lt;/a&gt; that discusses the divide in the front-end development world.&lt;/p&gt;

&lt;p&gt;At absolute minimum I would expect someone applying as a front-end developer to be able to work comfortably in HTML and CSS, with a basic knowledge of Javascript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Back End Developer
&lt;/h3&gt;

&lt;p&gt;A back-end developer is someone who works on the part of the sites and apps that relates to the data itself and how the user interacts with it.&lt;/p&gt;

&lt;p&gt;A back-end dev needs to understand network configuration, hosting, HTTP, &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/REST" rel="noopener noreferrer"&gt;REST&lt;/a&gt;, user authentication, be familiar with web servers like Apache and Nginx, and know how to work with databases like MySQL or MongoDB.&lt;/p&gt;

&lt;p&gt;Common programming languages you'll use to do back-end development are PHP, Python, Javascript, Java and C#.&lt;/p&gt;

&lt;h3&gt;
  
  
  Full Stack Developer
&lt;/h3&gt;

&lt;p&gt;Full-stack developers are simply devs who have experience working on both front-end and back-end. Often they will not have as much experience as a dedicated dev in either domain, but they are considered extremely valuable to companies for being a &lt;em&gt;jack of all trades&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Full-stack devs are more common now as many modern tools are built around the assumption of blurring lines between front and back end. It's more common than ever for companies to want to hire devs who can work with both.&lt;/p&gt;

&lt;p&gt;My recommendation to anyone would be to have a preference for either front or back, but at least be willing to learn the basics of the other. It will greatly benefit your career opportunities if you do.&lt;/p&gt;

&lt;p&gt;This guide will focus on tools and strategies needed to become a front-end developer, but we'll cover basic explanations of the fundamentals of back-end as well so you're at least aware of how they work if that's a path you decide you want to take.&lt;/p&gt;

&lt;h1&gt;
  
  
  Basic Tools and Concepts
&lt;/h1&gt;

&lt;h3&gt;
  
  
  What does a typical work day look like for a web developer?
&lt;/h3&gt;

&lt;p&gt;Let's consider an example workday for a front-end developer. We'll focus on a junior developer position since that is likely what you are going to be working toward.&lt;/p&gt;

&lt;p&gt;We'll use this opportunity to discuss topics and tools that are commonly used in real workplaces, that you should be aware of, but might not necessarily encounter when working alone including &lt;em&gt;meetings&lt;/em&gt;, &lt;em&gt;project management tools&lt;/em&gt;, &lt;em&gt;design systems&lt;/em&gt;, and &lt;em&gt;communication tools&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication Tools
&lt;/h3&gt;

&lt;p&gt;Your day will likely start with opening your email, then opening up a communication tool like &lt;a href="https://slack.com/" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; or &lt;a href="https://www.microsoft.com/en-us/microsoft-teams/group-chat-software" rel="noopener noreferrer"&gt;Microsoft Teams&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These tools are what you use to chat with your team in real time, particularly if you are working remote, but even within the office most communication is done through a tool like this.&lt;/p&gt;

&lt;p&gt;For video discussion you'll likely be using something like &lt;em&gt;Zoom&lt;/em&gt;, &lt;em&gt;Google Meet&lt;/em&gt; or &lt;em&gt;Skype&lt;/em&gt;. Most people these days are familiar with at least one of these tools, they are pretty interchangeable for the most part.&lt;/p&gt;

&lt;p&gt;Companies typically use these for basic communication for work to be done, or asking questions and clarifying assumptions. Bear in mind that when it comes to actually documenting work that needs to be done, tools like these are usually discouraged as they are not designed to manage tasks. We'll cover that when we get to &lt;em&gt;project management tools&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Once you've logged in and checked your emails, it's often time for the &lt;em&gt;daily standup&lt;/em&gt; or similar meeting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Meetings
&lt;/h3&gt;

&lt;p&gt;You begin your day often with a meeting called a "stand up". This is where other developers on your team and your team lead discuss the projects they are working on, what they have done, what they are planning to do, and whether there is anything "blocking" their work.&lt;/p&gt;

&lt;p&gt;An example of a "blocker" would be for example waiting for a client to send you a description of the new page they want built, which you need before you can begin working on it.&lt;/p&gt;

&lt;p&gt;Meetings are very common in the developer's workplace (often a source of jokes and memes), but humour aside there is a reason they are popular. Often it is beneficial to a project to discuss in real-time work that needs to be done, and the different approaches about how you plan to accomplish it.&lt;/p&gt;

&lt;p&gt;The most important thing to do to have successful meetings in the workplace is to document them and produce a list of &lt;em&gt;actionable tasks&lt;/em&gt;. Everyone should walk away from a meeting having a better idea of the work that needs to be done.&lt;/p&gt;

&lt;p&gt;At this point it's likely time to review the work that does need to be done that you are responsible for. This is usually done through issue ticketing systems. People within your organization will create &lt;em&gt;tickets&lt;/em&gt; that represent issues with your project or work that needs to be done in one of the many project management tools that exist out there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Management
&lt;/h3&gt;

&lt;h3&gt;
  
  
  What is Agile?
&lt;/h3&gt;

&lt;p&gt;It's a good idea to familiarize yourself with at least one of these tools before you start looking for employment. One of the simplest ones to play around with is called &lt;a href="https://trello.com/en" rel="noopener noreferrer"&gt;Trello&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It has a free plan and it would be a good idea for you to use it to keep track of work that needs to be done even if you are only working on personal projects for yourself, just to get familiar with the workflow of creating issues and marking them complete.&lt;/p&gt;

&lt;p&gt;Other more complex professional tools in that space you might use in your real job include &lt;a href="https://www.atlassian.com/software/jira" rel="noopener noreferrer"&gt;JIRA&lt;/a&gt;, &lt;a href="https://docs.github.com/en/issues/tracking-your-work-with-issues/about-issues" rel="noopener noreferrer"&gt;Github issues&lt;/a&gt; and &lt;a href="https://about.gitlab.com/" rel="noopener noreferrer"&gt;Gitlab&lt;/a&gt;. You don't need to know how they work, just being aware they exist is fine.&lt;/p&gt;

&lt;p&gt;In addition to the tools themselves, there are many different ways that you can choose to use them. This is where you may have heard terms like &lt;em&gt;agile&lt;/em&gt;, &lt;em&gt;waterfall&lt;/em&gt;, &lt;em&gt;kanban&lt;/em&gt;,and &lt;em&gt;scrum master&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;These are different project management methodologies that sound fancy, but ultimately are just different approaches to tracking work and making sure expected projects are delivered on time. Feel free to Google the above terms to learn more if you desire.&lt;/p&gt;

&lt;p&gt;As a developer you honestly really don't need to worry too much about these, you simply follow whatever methodology your company uses (oftentimes will be no specific methodology at all).&lt;/p&gt;

&lt;p&gt;So at this point you have found a ticket assigned to you. We're ready to do actual development work.&lt;/p&gt;

&lt;p&gt;The ticket looks something 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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1656878515%2Fblogs%2Fintro-to-web-development%2Fticket-example_tntuus.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1656878515%2Fblogs%2Fintro-to-web-development%2Fticket-example_tntuus.png" alt="Ticket Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an extremely simple example I whipped together on Trello, but it includes most of the fundamentals. You'll have a basic title that describes the issue, and a description that explains the work that needs to be done.&lt;/p&gt;

&lt;p&gt;Oftentimes you'll see additional things like a due date, priority list, tags for organizing and grouping related tickets etc. As a developer, particularly a junior developer, your only real concern will be the description of the ticket itself and marking it as "complete" when the work is finished.&lt;/p&gt;

&lt;p&gt;You'll notice here the description says to use the design in &lt;em&gt;Figma&lt;/em&gt; to complete the task. What is &lt;em&gt;Figma&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Before we can answer that question, first let's talk briefly about &lt;em&gt;Design Systems&lt;/em&gt; because the two are very closely connected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Systems
&lt;/h3&gt;

&lt;p&gt;As someone who does not pretend to be a designer nor a design expert, I have nevertheless come to appreciate the importance of good design and a good design system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A design system is a set of standards to manage design at scale by reducing redundancy while creating a shared language and visual consistency across different pages and channels.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;-- &lt;em&gt;Nielsen Norman Group&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;The further I go in my career the more I realize that proper design of a piece of software before development occurs can make or break the success and scalability of a product.&lt;/p&gt;

&lt;p&gt;Pay particular attention to the terms "shared language" and "consistency". Imagine you are building a massive product with hundreds of other developers. Here's just a couple examples among countless that might occur without a proper design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you don't all agree on the term used for a concept in your app, you may end up with a dozen different names for the same thing like "customer" vs "user" vs "employee" across the app and two developers may think they're working with totally different data when they're actually talking about the same thing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The designer may offer a specific hex code for "yellow" that is intended to use across the app, but if the relationship between that "yellow" is not defined between actual behavior, one developer may make it the default colour for "success" in one part of the app while another defines it as "warning" leading to a confusing UX experience when a user of your product can't easily tell if their action was correct or not.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples of famous design systems include Google's &lt;a href="https://material.io/design" rel="noopener noreferrer"&gt;Material Design&lt;/a&gt;, Apple's &lt;a href="https://developer.apple.com/design/human-interface-guidelines/guidelines/overview/" rel="noopener noreferrer"&gt;Human Interface&lt;/a&gt; and IBM's &lt;a href="https://carbondesignsystem.com/" rel="noopener noreferrer"&gt;Carbon Design System&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These systems are not necessarily exclusive to those companies, they are made publicly available specifically so they can be used by any designer and developer. Many open source tools like &lt;a href="https://mui.com/" rel="noopener noreferrer"&gt;Material UI&lt;/a&gt; for example (a React component library) are built on top of these basic principles and available to use by anyone.&lt;/p&gt;

&lt;p&gt;Depending on the company you work for, they might build on top of an existing design system while trying to modify it to their company's needs (for example just change the colours to match their brand colours). This has the benefit of being fast and inexpensive since you are working on top of existing verified designs already established.&lt;/p&gt;

&lt;p&gt;Alternatively many larger companies will opt to build their own design systems from scratch. This has the benefit of being more unique, while also being more expensive both from the design side and the development side.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(And then of course you may be unfortunate enough to land at a company that does neither and expects the developer themselves to handle both design and development and just "make it look good". If you find yourself in that situation.... good luck!)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you have established what kind of design system and design language you will be using, the next step is to pick the right design tool to foster the best collaboration between designer and developer you can.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Tools
&lt;/h3&gt;

&lt;h3&gt;
  
  
  What is Figma?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/" rel="noopener noreferrer"&gt;Figma&lt;/a&gt; is a design tool, and pretty much the de-facto current standard in the web development industry. Other similar tools exist like &lt;a href="https://www.adobe.com/ca/products/xd.html" rel="noopener noreferrer"&gt;Adobe XD&lt;/a&gt; and &lt;a href=""&gt;Zeplin&lt;/a&gt; but we're going to focus on Figma since it's most likely the one you will encounter.&lt;/p&gt;

&lt;p&gt;Again, like many other tools it's more about the basic concepts. Which specific one you use doesn't make a big difference as long as you understand the fundamentals.&lt;/p&gt;

&lt;p&gt;The general process at most companies (particularly large ones) when creating a new website or web app will be to built the wireframes about how they want it to work and function before development work actually begins.&lt;/p&gt;

&lt;p&gt;Remember your job as a web developer isn't to make decisions about how they work or how they look (that's the job of the &lt;em&gt;product manager&lt;/em&gt; and &lt;em&gt;UI/UX designer&lt;/em&gt; respectively).&lt;/p&gt;

&lt;p&gt;Your job is to implement those decisions and designs as code.&lt;/p&gt;

&lt;p&gt;Here's a small example of what you might see when you follow the link in the ticket to the Figma design they want you to implement:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1656878610%2Fblogs%2Fintro-to-web-development%2Ffigma-example_ojt1tx.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1656878610%2Fblogs%2Fintro-to-web-development%2Ffigma-example_ojt1tx.png" alt="Figma Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each element built by the designer can be clicked on and you can see all the details about it, often even the CSS code you can use to build your actual implementation off of.&lt;/p&gt;

&lt;p&gt;These designs will serve as the example of what the expectations are for how the site should look and function. When your code gets reviewed after it has been completed, the person doing the review will be comparing the work you did and checking to make sure it matches the intended design.&lt;/p&gt;

&lt;p&gt;Remember that a website or app includes both design &lt;em&gt;and&lt;/em&gt; function. As a front-end developer you are not just responsible for making sure images are laid out properly and that buttons are red, but also that the correct data is being displayed and correct logic is being used to display it. That's where the more complex programming aspects come into play.&lt;/p&gt;

&lt;p&gt;It's not necessarily easy to tell from this image, but your task might include &lt;em&gt;fetching&lt;/em&gt; data from an &lt;em&gt;API&lt;/em&gt; which includes a real time list of all the plants the company has in stock, and exactly what their inventory levels are. This data will be changing from minute to minute, which is why you can't just write those descriptions in by hand.&lt;/p&gt;

&lt;p&gt;All that and more is part of your responsibility as a front-end developer to create a working "New Arrivals" page. You will do this work almost entirely in the scope of HTML, CSS and Javascript.&lt;/p&gt;

&lt;p&gt;We briefly mentioned reviews, and that is the last topic we will touch on as part of your daily experience in your front-end developer role.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Reviews
&lt;/h3&gt;

&lt;p&gt;One last critical part of a developers job is also one of the most difficult to replicate and get experience with when you are learning: code reviews. Because you will be doing most of your work on your own, you won't get to benefit from having your work reviewed by others (unless you are lucky enough to find friends or peers online willing to do so, in which case I would highly recommend you take advantage of it).&lt;/p&gt;

&lt;p&gt;Code reviews are a critical part of the development process for most (unfortunately not all) companies. The reason they exist is to try and ensure only that all code written and implemented as part of the larger codebase meets a certain standard of quality.&lt;/p&gt;

&lt;p&gt;Code reviews are usually done through your version control system when your changes are committed. We'll speak more on these topics when we get to &lt;em&gt;git&lt;/em&gt;, but the basic idea is that your code can be viewed live in a browser on a website like &lt;em&gt;Github&lt;/em&gt; for other team members to see.&lt;/p&gt;

&lt;p&gt;They have the ability to leave comments and either "approve" or "deny" and send back with a request to fix errors, or make general improvements.&lt;/p&gt;

&lt;p&gt;It's important to look at code reviews as a positive opportunity for improvement. They are probably going to be one of the most important sources for your growth, and the best developers I know are those who seek out and ask for reviews from others so they can learn.&lt;/p&gt;

&lt;p&gt;Those doing the reviews are encouraged to focus on finding and fixing potential errors, as well as issues that may result in code that is difficult to maintain in the long run. They should be done from a perspective of positive encouragement and keeping in mind that it's not something to take personally. Done properly code reviews are one of the best tools a company has to create long term maintainable systems.&lt;/p&gt;

&lt;p&gt;Here's a &lt;a href="https://stackoverflow.blog/2019/09/30/how-to-make-good-code-reviews-better/" rel="noopener noreferrer"&gt;great blog post&lt;/a&gt; about how to do a code review effectively. Well worth reading if you are going to be joining a team working with other developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  What skills are critical for a successful junior developer?
&lt;/h3&gt;

&lt;p&gt;That brings us to about the end of the day, you've successfully finished your first day as a junior developer!&lt;/p&gt;

&lt;p&gt;There are two final closing thoughts I have that I feel are critical to be successful in a developer role that you may not necessarily get to practice much while learning on your own, so I think this is a good place to mention them:&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading Code
&lt;/h3&gt;

&lt;p&gt;Learn to &lt;em&gt;Read&lt;/em&gt; code -- not just write it.&lt;/p&gt;

&lt;p&gt;For many developers, particularly new ones, you will actually spend more time reading code than writing code in the real world.&lt;/p&gt;

&lt;p&gt;The reason for that is that as someone with less experience, you will not be tasked with building new systems, but rather making small improvements to existing ones.&lt;/p&gt;

&lt;p&gt;A lot of developers really underestimate how difficult it is to read code. Reading other people's code is &lt;em&gt;hard&lt;/em&gt;. Harder than writing code, because when you write code you know what your intention is, but when you read it you have to try and figure out other people's intentions through the code they have written.&lt;/p&gt;

&lt;p&gt;And unfortunately, the reality is that a lot of those code is going to be a mess. If you have any rose coloured glasses on regarding expectations of clean codebases and well documented requirements you're going to be in for a bit of a rough ride.&lt;/p&gt;

&lt;p&gt;Oftentimes that is the exception rather than the rule, so you need to be ready to dive into something that isn't necessarily straightforward and figure out what's going on in order to make the changes that need to be made.&lt;/p&gt;

&lt;p&gt;If this is something you would like to practice, once you have learned the basics of writing code, I would suggest looking into contributing to open source projects. It can be very intimidating at first, but also very rewarding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asking for Help
&lt;/h3&gt;

&lt;p&gt;My rule of thumb for someone new is to try figuring out something on your own for about 10-15 mins, and if you still haven't made progress, then ask for help. That time frame will gradually increase as you get more experience.&lt;/p&gt;

&lt;p&gt;Any good company that hires a new developer will understand that the goal is to get your trained and up to speed and will properly dedicate assets (other developers) to be available to mentor you and answer questions.&lt;/p&gt;

&lt;p&gt;If you ever find yourself in a position where you are new and other developers are "too busy" or "don't have time to help" then please know that is a failure of the company, not a failure of yours.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;h3&gt;
  
  
  How do I get started?
&lt;/h3&gt;

&lt;p&gt;Now that we have established the mindset you want to be in, and what bring a "web developer" really means, let's talk about getting all the tools you need and setting you up for success.&lt;/p&gt;

&lt;p&gt;There are five fundamental things that you should have before you get started&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Computer Hardware&lt;/li&gt;
&lt;li&gt;A Working Environment&lt;/li&gt;
&lt;li&gt;A Way to Test Your Work&lt;/li&gt;
&lt;li&gt;A Goal to Work Toward&lt;/li&gt;
&lt;li&gt;A Resource to Learn From&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Computer Hardware
&lt;/h3&gt;

&lt;p&gt;To have the most user friendly and effective setup, you are going to want to have a standard computer or laptop with either Windows, Mac OS or Linux installed.&lt;/p&gt;

&lt;p&gt;It is certainly &lt;em&gt;possible&lt;/em&gt; to learn programming on a Chromebook or even a tablet / phone, however you will encounter a lot more challenges in trying to do so than if you can get your hands on a computer with a traditional operating system.&lt;/p&gt;

&lt;p&gt;Whether you choose Windows, Mac or Linux makes absolutely no difference as a beginner. Even as a professional all three of them are perfectly good viable options. Don't ever let anyone tell you that you &lt;em&gt;need&lt;/em&gt; a Mac to be a developer. Or that you have to use Linux.&lt;/p&gt;

&lt;p&gt;You'll be perfectly fine to get through your learning experience on whatever you have available to you, and if your job ever requires a specific one, then the company will provide that one for you.&lt;/p&gt;

&lt;p&gt;If budget is an issue, I would recommend looking for a used laptop. Something with an least 4GB of RAM (that's about the minimum for most modern coding environments).&lt;/p&gt;

&lt;h3&gt;
  
  
  A Working Environment
&lt;/h3&gt;

&lt;p&gt;Although it is possible to learn web development entirely with tools in the browser, it will limit you significantly compared to setting up your own computer to do your development work on.&lt;/p&gt;

&lt;p&gt;You can technically do your development in any text editor (even something as simple as Notepad).&lt;/p&gt;

&lt;p&gt;The reason we use specialized code editors in the software field is because they can provide tons of added features to both speed up development and check for errors in your code automatically as you type it.&lt;/p&gt;

&lt;p&gt;You will see the shorthand &lt;em&gt;IDE&lt;/em&gt; which stands for &lt;strong&gt;integrated development environment&lt;/strong&gt; often. The most popular IDE by far is Microsoft's &lt;em&gt;Visual Studio Code&lt;/em&gt; referred to as VS Code for short.&lt;/p&gt;

&lt;p&gt;It's totally free and you can use it to help you write code in almost any programming language in existence.&lt;/p&gt;

&lt;p&gt;Later in this guide we will go into full detail on how to set up a simple web server on your computer that you can use to test and run your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Way to Test Your Work
&lt;/h3&gt;

&lt;p&gt;Once your code is written, how do you actually run it to see if it works?&lt;/p&gt;

&lt;p&gt;If you are learning web development, then you need something that sends your HTML, CSS and Javascript code to your browser to run. That "something" is called a &lt;em&gt;web server&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When you type an address into your browser's URL bar, that URL gets converted into an &lt;em&gt;IP address&lt;/em&gt; which identifies a particular machine somewhere on the web. If that machine is running a web server, then your browser will request data from it (usually HTML, CSS and Javascript) which it then parses and displays it on your screen for you..&lt;/p&gt;

&lt;p&gt;Later in this guide we will go into full detail on how to set up a simple web server on your computer that you can use to test and run your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Goal to Work Toward
&lt;/h3&gt;

&lt;p&gt;This one is relatively simple, but it's important to define it. Most people who begin their web development journey will have the goal of getting employed in a web developer job, which is a great goal!&lt;/p&gt;

&lt;p&gt;However some might simply wish to learn more about how websites or made, or have a hobby project in mind that they would like to learn how to build. Those are great goals as well.&lt;/p&gt;

&lt;p&gt;Regardless what your goals are it's critical that you establish a plan for how you will reach that goals.&lt;/p&gt;

&lt;p&gt;Early on in the process you will not even be aware of everything you need to learn, so setting specific timelines might not necessarily be realistic at the beginning.&lt;/p&gt;

&lt;p&gt;Instead try to focus on routine, decide how much time you can devote each day and each week to your learning and make sure you've done everything you need to do to ensure that time is available for you.&lt;/p&gt;

&lt;p&gt;Regular practice is far more important than singular long sessions. For example you will learn more from practicing for one hour every day than you will doing 5 hours on Saturdays and Sundays.&lt;/p&gt;

&lt;p&gt;The reason being that the long the gap between practice the less likely you are to retain things you have learned. Learning web development (and anything really) is all about repetition and consistent practice.&lt;/p&gt;

&lt;p&gt;And don't forget the importance of proper sleep for solidifying what you have learned at the end of each day.&lt;/p&gt;

&lt;p&gt;In terms of timelines, my experience from those I have worked with and talked to in the community, is that someone who dedicates themselves to learning web development full time (like a 9-5 job) will probably require at least 6 months to become proficient enough to begin applying for jobs.&lt;/p&gt;

&lt;p&gt;Those who are only learning just a few hours a week in their spare time will require more, likely at least a full year or more.&lt;/p&gt;

&lt;p&gt;These are by no means set in stone, everyone is different, everyone learns at different rates, so you should not hold yourself to any unrealistic deadlines that might put you at risk of burning out or giving up.&lt;/p&gt;

&lt;p&gt;It's a marathon, not a sprint.&lt;/p&gt;

&lt;p&gt;Once you have that plan in place then it's finally time to decide &lt;em&gt;how&lt;/em&gt; you will go about learning.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Resource to Learn From
&lt;/h3&gt;

&lt;p&gt;One of the most difficult parts of learning web development people often find is deciding which course they should take, or which tutorial they should follow, or which project they should build.&lt;/p&gt;

&lt;p&gt;In this guide I will provide a lot of recommendations, the vast majority of them free to use.&lt;/p&gt;

&lt;p&gt;The most important thing to keep in mind is again, that learning to be a developer is a constant never-ending learning journey. Each tutorial you follow and project you build will teach you a little more.&lt;/p&gt;

&lt;p&gt;Most people find that the most effective way to learn is through a combination of tutorials and self-directed projects. Start by following an online course that will guide you and hold your hand most of the way.&lt;/p&gt;

&lt;p&gt;After completion, try to build your own project using some of the things you learned. Select that project based around something that interests you. That's a very important step to help stay motivated to see it through.&lt;/p&gt;

&lt;p&gt;Keep the scope (size of the project) small. It's much better to start and finish a small project then to undertake a large project and quit when you realize you've taken on too much.&lt;/p&gt;

&lt;p&gt;The more projects you build the better you will get at properly estimating the scope of the workload.&lt;/p&gt;

&lt;p&gt;Your very first resource will be this guide. We will introduce you to the basics of HTML, CSS, and Javascript. We'll also touch on version control (git) and web servers.&lt;/p&gt;

&lt;p&gt;Finally we'll talk in brief detail about a number of other concepts you'll want to be aware of, even if you don't understand how they work.&lt;/p&gt;

&lt;h1&gt;
  
  
  Web Development Basics
&lt;/h1&gt;

&lt;h3&gt;
  
  
  How does a website get created?
&lt;/h3&gt;

&lt;p&gt;So how does a website get created? We'll begin by going and taking a look at one of the most poplar websites in the world: &lt;a href="//www.amazon.com"&gt;Amazon&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654391360%2Fblogs%2Fintro-to-web-development%2Famazon_gpmoi7.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654391360%2Fblogs%2Fintro-to-web-development%2Famazon_gpmoi7.png" alt="Amazon Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start by loading the home page.&lt;/p&gt;

&lt;p&gt;Now try &lt;em&gt;right clicking&lt;/em&gt; on any of the section titles. I've chosen "Shop by Category" but if yours appears different thats fine.&lt;/p&gt;

&lt;p&gt;When you right click choose &lt;strong&gt;"Inspect"&lt;/strong&gt; from the menu that comes up.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654392418%2Fblogs%2Fintro-to-web-development%2Famazon2_hwhgg1.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654392418%2Fblogs%2Fintro-to-web-development%2Famazon2_hwhgg1.png" alt="Amazon Example HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A menu will appear at the bottom of your screen.&lt;/p&gt;

&lt;p&gt;This is your browser's "Developer Console". The code-looking text you are seeing is called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML" rel="noopener noreferrer"&gt;HTML&lt;/a&gt;. It is a special kind of text designed to structure content.&lt;/p&gt;

&lt;p&gt;It is one of the three primary web languages you will need to need to learn to become a web developer (along with CSS and Javascript).&lt;/p&gt;

&lt;p&gt;What you are looking at is the complete HTML structure of the Amazon home page. This code is not designed to be hidden from you, in fact all code that runs in your browser on every site you visit is totally public and visible by using the "inspect" tool.&lt;/p&gt;

&lt;p&gt;You will find that the browser's inspector is one of many important tools you will become familiar with while learning.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I build a website or web app?
&lt;/h3&gt;

&lt;p&gt;The absolute easiest way for someone with no experience at all to start building their own website or web app is to use a tool called &lt;a href="https://codepen.io" rel="noopener noreferrer"&gt;Codepen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are many tools like this (code editors in your browser), I have simply chosen Codepen because it's one of the simplest and easiest to get started with.&lt;/p&gt;

&lt;p&gt;Create an account for yourself (using an account will allow you to save your work) and then click the &lt;a href="https://codepen.io/pen/" rel="noopener noreferrer"&gt;Pen&lt;/a&gt; button on the left menu. You'll be taken to a screen that looks 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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654392010%2Fblogs%2Fintro-to-web-development%2Fcodepen-blank_p8nytn.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654392010%2Fblogs%2Fintro-to-web-development%2Fcodepen-blank_p8nytn.png" alt="Codepen Blank"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember we were looking at some HTMl code on the Amazon website, so let's copy it over and see it if works here! I've doing to copy and paste this from the developer console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"a-color-base headline truncate-1line"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Shop by Category&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654392806%2Fblogs%2Fintro-to-web-development%2Fcodepen-first-html_b5w7ly.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654392806%2Fblogs%2Fintro-to-web-development%2Fcodepen-first-html_b5w7ly.png" alt="Codepen First HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that a couple of seconds after your paste it into the HTML block, some text appears in the white section of the bottom of your screen. That is Codepen render the result of your HTML!&lt;/p&gt;

&lt;p&gt;It looks just like it did on Amazon, even the font size is similar. The reason for that is that &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; represents a "header" and all browsers have built-in ways of deciding how they should look. You can customize them of course, but the browser handles the defaults.&lt;/p&gt;

&lt;p&gt;You now have an environment where you can learn and play with HTML. We'll go into more detail on HTML in a later section. For now I'd also like to introduce the other two important languages you will need to learn: CSS and Javascript.&lt;/p&gt;

&lt;p&gt;We'll begin with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS" rel="noopener noreferrer"&gt;Cascading Style Sheets&lt;/a&gt;. CSS is a special syntax used to change the way HTML looks. So as we mentioned, your browser has its own default options of how an &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; tag should look, but with CSS we can override those default styles and make it look however we like.&lt;/p&gt;

&lt;p&gt;In the second box on your Codepen marked as CSS let's add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;36px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654393277%2Fblogs%2Fintro-to-web-development%2Fcodepen-first-css_apa17m.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654393277%2Fblogs%2Fintro-to-web-development%2Fcodepen-first-css_apa17m.png" alt="Codepen CSS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how it changed the font size and colour of your text? That's what CSS does. The label outside the curly brackets says &lt;code&gt;h2&lt;/code&gt; which is called the &lt;code&gt;selector&lt;/code&gt;. That specifically says which HTML elements we want to apply these styles to.&lt;/p&gt;

&lt;p&gt;We'll get into CSS in much more detail in a coming section, but let's at least introduce the 3rd language you'll be learning: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" rel="noopener noreferrer"&gt;Javascript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Javascript is by far the most complex of the three, it's a full fledged programming language, but believe it or not you can actually build fully complete websites with just HTML and CSS alone.&lt;/p&gt;

&lt;p&gt;Javascript is only need to make your sites and apps interactive, and although that is an important part of the vast majority of the web these days, there are still many types of sites that need little to no Javascript.&lt;/p&gt;

&lt;p&gt;For example a business page for a local restaurant which simply lists the menu, store hours and a contact phone number. Or a blog which is just written content and images and links between pages. Neither of those examples would require Javascript to work.&lt;/p&gt;

&lt;p&gt;As soon as you start to want user interactivity, you are going to need it though. Let's show one of the simplest examples of Javascript at work: a button.&lt;/p&gt;

&lt;p&gt;Add the following to your Codepen in the Javascript 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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buyItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You bought an item!&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;What we've created there is a "function" which is basically something that performs a set of tasks. In our case the task is to show an alert banner on the screen that says "You bought an item!"&lt;/p&gt;

&lt;p&gt;In order to actually trigger our function though, we will have to connect it to HTML. We'll need a button we can click that will "invoke" this function. Add the following code to your HTML block on codepen after the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; that is already there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;... &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onClick=&lt;/span&gt;&lt;span class="s"&gt;"buyItem()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Buy Item&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654393930%2Fblogs%2Fintro-to-web-development%2Fcodepen-first-js_g5mlpi.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654393930%2Fblogs%2Fintro-to-web-development%2Fcodepen-first-js_g5mlpi.png" alt="Codepen Javascript"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A button that says "Buy Item" will appear in your little app. try clicking on it and you should get a little pop up window that says "You bought an item!"&lt;/p&gt;

&lt;p&gt;Honestly, that's web development in a nutshell right now. Obviously it just grows and gets bigger and more complex from here, but you now have experience using every core tool you need to build applications for the web.&lt;/p&gt;

&lt;p&gt;All the fancy tools you hear about like React, Angular, etc ultimately just transform your code into HTML/CSS/JS before it gets sent to your browser, so if you can learn the fundamentals and learn them &lt;em&gt;well&lt;/em&gt; then you will be in an extremely strong position to pick up the specialized tools which simply make developing apps easier and more efficient.&lt;/p&gt;

&lt;p&gt;Easier said than done of course, but we're going to walk through everything you need to know step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I build websites on my own computer?
&lt;/h3&gt;

&lt;p&gt;There's absolutely nothing wrong with continuing to use Codepen or similar services like &lt;a href="https://codesandbox.io" rel="noopener noreferrer"&gt;Codesandbox&lt;/a&gt;, &lt;a href="https://replit.com/" rel="noopener noreferrer"&gt;Replit&lt;/a&gt; or &lt;a href="https://glitch.com/" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt; while learning, but at some point you are probably going to want to know how to built websites using tools on your own computer.&lt;/p&gt;

&lt;p&gt;There are many benefits to doing it this way, you'll be able to store and manage your own files, as well as share them with others. You can customize your own tools to behave how you like, and you don't need to worry about always having access to an internet connected browser to build.&lt;/p&gt;

&lt;p&gt;Of course when you work for a real company the expectation is that you will be working on your own machine (or a company machine) so it will be expected that you know the basics of how to set up an editor.&lt;/p&gt;

&lt;p&gt;Absolutely any text editor can be used to write HTML, CSS and JS. Even basic Notepad. The main reason we choose something like VS Code (which this tutorial will teach you to use) is that we get major benefits designed to help people who write code.&lt;/p&gt;

&lt;p&gt;Some of the benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project organization (see all the files for our project in one place)&lt;/li&gt;
&lt;li&gt;Syntax highlighting (colouring text differently depending on what it does)&lt;/li&gt;
&lt;li&gt;Intellisense (autocomplete and tooltips that tell you what your code actually does)&lt;/li&gt;
&lt;li&gt;Error checking while you write&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many more benefits of course, but these are just some examples of the most useful ones!&lt;/p&gt;

&lt;p&gt;The next section will help you get VS Code installed on your machine and prepare you to setup your first web project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the event you don't have a computer you can install a text editor on, you can continue to use Codepen for the time being. Simply skip over the below section on setting up VS Code. You would also want to skip the section on configuring a web sever, but it's still worth reading as there are many concepts explained that are important to understand.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I set up a development environment on my computer?
&lt;/h2&gt;

&lt;p&gt;Start by installing VS Code. You can &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;download it here&lt;/a&gt; from the official site.&lt;/p&gt;

&lt;p&gt;The benefits you will get from automatic syntax highlighting, formatting, &lt;a href="https://code.visualstudio.com/docs/editor/intellisense" rel="noopener noreferrer"&gt;intellisense&lt;/a&gt; and other programming-specific features will not only improve the quality of your code, but also your experience in writing it.&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%2Fi.imgur.com%2FMrJYLf8.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%2Fi.imgur.com%2FMrJYLf8.png" alt="Install VS Code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will definitely want to download or bookmark the keyboard reference for your relevant OS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-windows.pdf" rel="noopener noreferrer"&gt;VS Code Keyboard Shortcuts (Windows)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-linux.pdf" rel="noopener noreferrer"&gt;VS Code Keyboard Shortcuts (Linux)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf" rel="noopener noreferrer"&gt;VS Code Keyboard Shortcuts (Mac)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The majority of the keyboard shortcuts in this tutorial work for both Windows and Linux, and Mac users can usually substitute the &lt;code&gt;Ctrl&lt;/code&gt; key for the &lt;code&gt;Option&lt;/code&gt; key.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next we are going to create a folder called &lt;code&gt;my-project&lt;/code&gt;. You can create this folder anywhere on your computer that you like. Once you have created it return to VS Code and select &lt;code&gt;File -&amp;gt; Open Folder&lt;/code&gt; then navigate to the &lt;code&gt;my-project&lt;/code&gt; folder you created.&lt;/p&gt;

&lt;p&gt;Now open up the &lt;code&gt;Explorer&lt;/code&gt; bar on the left side of VS Code. There are a few ways to do this, either press &lt;code&gt;Ctrl + Shift + E&lt;/code&gt; or use the little papers icon:&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%2Fi.imgur.com%2F2NgSCNr.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%2Fi.imgur.com%2F2NgSCNr.png" alt="VS Code Explorer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You are now ready to create files and write code.&lt;/p&gt;

&lt;p&gt;Before we continue any further, let's really start to dive deeper into what HTML is and teach you how to set up the shell for a standard website.&lt;/p&gt;

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

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

&lt;p&gt;HTML stands for &lt;em&gt;Hypertext Markup Language&lt;/em&gt; and it is the building block of all content on the web, and even many web applications. It is a way to represent different types of content, for example headers, paragraphs, links, images, lists etc so that another tool (for example a browser) can display them in a way that is easy for a user to consume.&lt;/p&gt;

&lt;p&gt;HTML is primarily concerned with the &lt;em&gt;content&lt;/em&gt; its and not its visual style; however there is some overlap and browsers all have their own set of default styles they use when they render HTML content.&lt;/p&gt;

&lt;p&gt;If we were to compare it to a house, HTML would be the foundation, the walls, the roof. Things like paint, trim, and even arrangement of the furniture would be someone else's job (for example the interior designer). Our job as HTML is to simply provide those building blocks to the designer.&lt;/p&gt;

&lt;p&gt;HTML is a series of &lt;em&gt;elements&lt;/em&gt;. An element is composed of three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The opening tag&lt;/strong&gt; - Contains the element name. For example a paragraph tag is &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;. That opening tag can also have &lt;em&gt;attributes&lt;/em&gt; inside of it which we will get to in a moment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The content&lt;/strong&gt; - Contains anything that goes inside the element. Can be just text, or another element, or multiple elements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The closing tag&lt;/strong&gt; - Tells whatever is rendering your markup that this element is finished. Looks similar to the opening tag with a slash character, so a paragraph closing tag looks like &lt;code&gt;&amp;lt;/p&amp;gt;&lt;/code&gt;. All elements have a closing tag (with a few exceptions called &lt;em&gt;void&lt;/em&gt; elements).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So taking what we know now, a paragraph element would look like &lt;code&gt;&amp;lt;p&amp;gt;Hello everyone!&amp;lt;/p&amp;gt;&lt;/code&gt; and would render on your wep page as simply text. Here's how it looks by default in Firefox:&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%2Fi.imgur.com%2FcvBDISq.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%2Fi.imgur.com%2FcvBDISq.png" alt="Firefox Hello Paragraph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we discussed the opening tag we mentioned the other important thing that an HTML elements can contain are &lt;em&gt;attributes&lt;/em&gt;. An attribute provides additional information or identifying characteristics about that element.&lt;/p&gt;

&lt;p&gt;A link for example which is defined by an &lt;em&gt;anchor&lt;/em&gt; element uses the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tag. Of course a link is useless without specifying where you want it to go. The destination of a link is specified with the &lt;code&gt;href&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Attributes are always placed within the opening tag of an element, and follow the rule &lt;code&gt;name="value"&lt;/code&gt; with the value in double quotes. So to set the &lt;code&gt;href&lt;/code&gt; attribute on our anchor it would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://www.google.com/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Link to Google&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The content of the element will be the text of the link. When we place this below our paragraph tag, our page now looks like:&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%2Fi.imgur.com%2Fjc7qTGR.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%2Fi.imgur.com%2Fjc7qTGR.png" alt="Firefox Link to Google"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on that link will take our browser directly to Google.&lt;/p&gt;

&lt;p&gt;Lastly let's take a look at the complete HTML content used to render these examples. The below code shows everything that is required to render out the most basic web page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My First Project&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello everyone!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://www.google.com/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Link to Google&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note that technically some of this could be removed and still rendered by the browser, when we say "minimum" we are referring to best practices of good HTML form, not the absolute minimum to get some content to appear)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You are already familiar with the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tags so let's look at the rest of the structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/code&gt; - Simply informs the browser that you are writing valid HTML. This element used to provide more functionality than it does in modern times. Simply including it is sufficient.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; - This is the root element that wraps your entire page, simply specifying &lt;em&gt;"this is where my HTML content can be found"&lt;/em&gt;. The &lt;code&gt;lang&lt;/code&gt; attribute specifies that the content we are writing is in English, this helps translation tools like &lt;em&gt;Google translate&lt;/em&gt; know what language to start with when doing the translation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; - This element wraps all the elements that provide information &lt;em&gt;about&lt;/em&gt; your web page that don't actually contain any content that renders on the page itself.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; - This is a general tag that provides &lt;em&gt;meta&lt;/em&gt; information about your HTML, for example above we are telling the browser that our HTML is written using the &lt;a href="https://en.wikipedia.org/wiki/UTF-8" rel="noopener noreferrer"&gt;UTF-8&lt;/a&gt; charset so you can expect any valid character in that set to appear. There are &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta" rel="noopener noreferrer"&gt;many other meta elements&lt;/a&gt; you can use as well.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; - Provides the title of your web page, you can see this most commonly as the label of your browser tab. This is very important for &lt;em&gt;SEO&lt;/em&gt; which we will get to later.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; - Contains the actual visible content of your site. Differentiate from the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element which contains both the visible body, but also the metadata in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There is lots more to learn, but this covers the absolute fundamentals. Check out the where can I learn more section to dive deeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use HTML?
&lt;/h2&gt;

&lt;p&gt;Here we will look at how you can take your knowledge of basic HTML structure and use it to build something.&lt;/p&gt;

&lt;p&gt;Presuming you followed the introduction about setting up VS Code, you are now ready to create your first HTML file.&lt;/p&gt;

&lt;p&gt;Note that VS Code is not required for any of this, it's simply a text editor. If for any reason you prefer other code editors like &lt;a href="https://atom.io/" rel="noopener noreferrer"&gt;Atom&lt;/a&gt; or &lt;a href="https://www.sublimetext.com/" rel="noopener noreferrer"&gt;Sublime&lt;/a&gt; they work just as well, and you can follow along exactly the same (just be aware the keyboard shortcuts and example images will not necessarily match up).&lt;/p&gt;

&lt;p&gt;Begin by opening the sidebar &lt;code&gt;(Ctrl + Shift + E)&lt;/code&gt; right clicking in it and selecting &lt;code&gt;"New File"&lt;/code&gt;. You can also press &lt;code&gt;Ctrl + N&lt;/code&gt; to create a new file.&lt;/p&gt;

&lt;p&gt;Our file will be called &lt;code&gt;index.html&lt;/code&gt;. The &lt;code&gt;html&lt;/code&gt; extension identifies that the file contains HTML, and the name &lt;code&gt;index&lt;/code&gt; is also special too. &lt;em&gt;index&lt;/em&gt; is the default filename a web server will look for when a browser makes a request. It's &lt;em&gt;not required&lt;/em&gt; to name your file &lt;code&gt;index.html&lt;/code&gt;, but if you don't then you would specifically need to tell your browser which file to get.&lt;/p&gt;

&lt;p&gt;We'll cover this and more in the section on web servers ahead.&lt;/p&gt;

&lt;p&gt;Once your file has been created you can copy &amp;amp; paste the code from the first section into it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My First Project&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello everyone!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://www.google.com/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Link to Google&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We were told this is valid HTML, but is there a way we can be sure? There is!&lt;/p&gt;

&lt;p&gt;If you would like to validate your HTML to ensure it meets modern standards you can use &lt;a href="https://validator.w3.org/" rel="noopener noreferrer"&gt;W3's HTML validation tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's paste our code into it to be sure:&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%2Fi.imgur.com%2FzPzK36w.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%2Fi.imgur.com%2FzPzK36w.png" alt="HTML Validation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fantastic, we've verified everything is good to go.&lt;/p&gt;

&lt;p&gt;Before we look at getting our code running in the browser, let's wrap up our discussion on HTML. Below are some great free resources for taking your HTML learning further, and I've also mentioned a few key topics you will want to learn more about as you build your skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else do I need to know about HTML?
&lt;/h2&gt;

&lt;p&gt;Semantic HTML is all about using tags that properly describe your content. For example using an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; for a header rather than putting your text in a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; tag. This allows things like web screen readers to better understand that the text is meaning to tell the user. More information below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML" rel="noopener noreferrer"&gt;Accessibility and Semantic HTML&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SEO stands for Search Engine Optimization and it is the field of creating your site in such a way that search engines (mostly Google) can scan them automatically and increase their ranking when users search for relevant terms. Things like semantic tags, page speed, colour contrast, text content and much more are considered when deciding your SEO score. More information below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/SEO" rel="noopener noreferrer"&gt;SEO&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning HTML?
&lt;/h2&gt;

&lt;p&gt;There are tons of great resources on learning HTML out there, and they're free!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/HTML" rel="noopener noreferrer"&gt;MDN&lt;/a&gt; for a complete resource that covers everything you need to know about HTML&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.theodinproject.com/paths/foundations/courses/foundations#html-foundations" rel="noopener noreferrer"&gt;The Odin Project&lt;/a&gt; HTML foundations portion of the full stack curriculum&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.codecademy.com/learn/learn-html" rel="noopener noreferrer"&gt;Codeacademy&lt;/a&gt; for a more academic "course style" approach to learning HTML&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://validator.w3.org/" rel="noopener noreferrer"&gt;HTML Validator&lt;/a&gt; - The HTML markup validation service&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/ananyaneogi/html-can-do-that-c0n"&gt;HTML Can do that?&lt;/a&gt; - A great blog post on dev.to showing some amazing browser native features that can be accomplished in pure HTML without CSS or Javascript&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Web Servers
&lt;/h1&gt;

&lt;p&gt;Now we are ready to get back to the HTML code we wrote in the previous section. We would like to view the contents of that HTML file in the browser.&lt;/p&gt;

&lt;p&gt;But how do we do that? Where exactly does the browser get the HTML code from to display it? We need a way to test and view the HTML we have written.&lt;/p&gt;

&lt;p&gt;This section will teach you everything you need to know about how that code gets up and running in your browser. This is not specific to getting it running on our machine, the concepts you are going to learn are exactly the same concepts real web servers use that let us access real websites and web apps from the internet every day!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Web Server?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(Note that although I would consider this sub-section to be &lt;strong&gt;extremely important&lt;/strong&gt; for every aspiring web developer to understand, it's not required understanding to complete this tutorial. If you would prefer to skip understanding how a web page gets to to your browser, you can jump ahead to How do I run a web server?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;That said I would highly recommend you at least briefly read through it if only to become familiar with the basic terminology.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A web server is a fancy name for software on a computer that is connected to a network and has the ability to send content over a protocol called &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/HTTP" rel="noopener noreferrer"&gt;HTTP&lt;/a&gt;. Most commonly this is an HTML page, but a web server can serve up any type of data you like.&lt;/p&gt;

&lt;p&gt;It can be something running on a farm of supercomputers across the ocean, handling millions of requests per second, or it can be something running on your own machine to practice writing HTML.&lt;/p&gt;

&lt;p&gt;Our tutorial, to no one's surprise, will focus on the latter.&lt;/p&gt;

&lt;p&gt;Before we get into &lt;em&gt;how&lt;/em&gt; to run a web server, let's start with &lt;em&gt;why&lt;/em&gt; we need one. A web server exists to provide data to your browser, so that you (the user) can request different web pages and data. The HTML file we created in the previous section is not really any different from a web page you would request on the internet. So how does a web server know which file to send to the browser?&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a web request?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Domain
&lt;/h3&gt;

&lt;p&gt;When you enter a URL into your browser and press enter, it makes what's called a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET" rel="noopener noreferrer"&gt;GET&lt;/a&gt; request to a server. Let's pretend that address is &lt;code&gt;https://www.google.com/&lt;/code&gt;. Presumably we are trying to get the Google homepage.&lt;/p&gt;

&lt;p&gt;How does it know which server, of all the servers in the world, to get the Google homepage from?&lt;/p&gt;

&lt;p&gt;A server is identified the same as any other computer, with an &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/IP_Address" rel="noopener noreferrer"&gt;IP address&lt;/a&gt;. Notice we don't see any IP address in &lt;code&gt;http://www.google.com/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When a domain name is used, the IP address is acquired through a system called &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/DNS" rel="noopener noreferrer"&gt;DNS&lt;/a&gt; which transforms the domain name into an IP address. There are DNS servers all over the world with giant address books of all the domain names and the IP addresses they are registered to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Port
&lt;/h3&gt;

&lt;p&gt;So now that we have identified the Google server, your browser makes an HTTP GET request to that server. In addition to the IP address, a request also always includes a &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Port" rel="noopener noreferrer"&gt;port number&lt;/a&gt; which helps to identify which process (think which piece of software) that request should go to.&lt;/p&gt;

&lt;p&gt;Imagine you are mailing a letter. Think of the IP address as the &lt;em&gt;house&lt;/em&gt; your letter is addressed to, and the port as the name of the &lt;em&gt;person&lt;/em&gt; inside the house that the letter is for.&lt;/p&gt;

&lt;p&gt;HTTP requests by &lt;em&gt;default&lt;/em&gt; use &lt;code&gt;port 80&lt;/code&gt;, so you don't have to specify it manually. You can still specify the port manually with a colon and the port number. So a request to &lt;code&gt;http://www.google.com/&lt;/code&gt; is equivalent to a request to &lt;code&gt;http://www.google.com:80/&lt;/code&gt;. Try it yourself! Anything other than port 80 should give you a timeout error because no process on the Google server is listening on that port (or if they are, they aren't listening for your type of request).&lt;/p&gt;

&lt;h3&gt;
  
  
  Path
&lt;/h3&gt;

&lt;p&gt;The final part of the URL that is relevant to our example is the &lt;em&gt;path&lt;/em&gt; of the data we are requesting. A similar term you might also hear in this context is the &lt;em&gt;route&lt;/em&gt;. That's the part that tells the server what data or page specifically we are looking for.&lt;/p&gt;

&lt;p&gt;In our example it is the &lt;code&gt;/&lt;/code&gt; on the end of the URL which is often referred to as the &lt;em&gt;root&lt;/em&gt; directory. Think of it similar to filers and folders on your computer. It represents a path on a file system where you cannot go "up" any further.&lt;/p&gt;

&lt;p&gt;In the context of web servers, it typically represents the directory the server is running in. This way it provides a layer of security. If you run a web server in &lt;code&gt;c:\Users\my-server&lt;/code&gt; then requests made it it will only be able to access files within that &lt;code&gt;my-server&lt;/code&gt; directory (and directories inside of it). Users would not have access to anything in the &lt;code&gt;c:\users&lt;/code&gt; directory or above.&lt;/p&gt;

&lt;p&gt;Let's give an example. I create a directory (folder) called &lt;code&gt;my-server&lt;/code&gt; on my computer, and run my web server software inside that directory. Let's say the IP address of my computer is &lt;code&gt;127.0.0.1&lt;/code&gt; (this is a actually a special IP that always refers to your own machine, so this is a valid way to make requests to your own machine).&lt;/p&gt;

&lt;p&gt;If I enter &lt;code&gt;http://127.0.0.1/&lt;/code&gt; into my browser, the web server will go looking in the &lt;em&gt;root&lt;/em&gt; directory, which means the directory the server software was started in. In our example that is the &lt;code&gt;my-server&lt;/code&gt; directory. By default most web servers will look first for a file called &lt;code&gt;index.html&lt;/code&gt; and send it back to whoever is requesting (our browser in this example). If it finds that file, the browser will render it, if not, you'll likely get an error.&lt;/p&gt;

&lt;p&gt;What if we make a request next to &lt;code&gt;http://127.0.0.1/something-else&lt;/code&gt; ?&lt;/p&gt;

&lt;p&gt;Our web server will now look for a directory called &lt;code&gt;something-else&lt;/code&gt; inside of the &lt;em&gt;root&lt;/em&gt; directory and follow the same behavior: look for an &lt;code&gt;index.html&lt;/code&gt; file. This is how we can create &lt;em&gt;routes&lt;/em&gt; on our website. Let's say we put relevant info about our business into an &lt;code&gt;index.html&lt;/code&gt; file in our root directory. Then we create another &lt;code&gt;index.html&lt;/code&gt; file with our business hours and phone # and put it in a folder named &lt;code&gt;contact-us&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can now access the main page at &lt;code&gt;http://127.0.0.1/&lt;/code&gt; and our contact info at &lt;code&gt;http://127.0.0.1/contact-us&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I run a web server?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(This section will cover the basics of how to run a web server on your own computer so that you may test your website/app while working on it. If you are looking for how to actually put your website/app somewhere so it can be accessed publicly by anyone, check out How do I put my website on the internet)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Furthermore, if you are looking for more information about how to a production web server for a real world website or application that needs to handle both large amounts of traffic and guarantees about service &amp;amp; uptime, then you will want to reach more about a professional web server like &lt;a href="https://www.nginx.com/" rel="noopener noreferrer"&gt;Nginx&lt;/a&gt; rather than the more hobby-level approaches described below)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We've covered the basics you need to understand about what a web server is an what it does. At this point you should be able to comfortably run one yourself and explain in simple terms what it is doing.&lt;/p&gt;

&lt;p&gt;Let's now look at how to run a web server yourself and get the HTML you wrote in the previous section to render in your browser on your machine.&lt;/p&gt;

&lt;p&gt;In this section we are going to learn how to add some extensions to the tools you are already using (VS Code or Chrome) to serve up your web content and view it in the browser.&lt;/p&gt;

&lt;p&gt;If you would like to learn how to run your own web server on your own machine (which is surprisingly easy) I have written a separate tutorial for this: &lt;em&gt;(Note that this tutorial presumes you have a basic familiarity with the terminal on your machine, at least enough to be able to copy and paste commands)&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g"&gt;Understanding the Modern Web Stack: Running a Local Web Server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If that sounds a bit beyond your understanding, then no problem at all! For this tutorial we are going to focus on the &lt;strong&gt;absolutely simplest&lt;/strong&gt; way to simply get your content running in your browser. We will provide three options, choose the one that fits your situation best:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Option 1&lt;/strong&gt;: Choose this option if you have installed VS Code on your machine&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Option 2&lt;/strong&gt;: Choose this option if you have installed Node.js on your machine, you understand how to install an NPM package and you want more control over your server than the VS Code extension provides.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Option 3&lt;/strong&gt;: Choose this option if you are using the web version of VS Code, or any editor &lt;strong&gt;other than&lt;/strong&gt; VS Code, or are on an OS besides Windows/Linux/Mac (a Chromebook for example)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Option 4&lt;/strong&gt;: Choose this option if you are on a public computer like a school or library where you do not have permission to install software&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Option 1: VS Code Extension
&lt;/h3&gt;

&lt;p&gt;We are going to install the VS Code &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer" rel="noopener noreferrer"&gt;Live Server&lt;/a&gt; extension. Start by clicking the &lt;em&gt;Extensions&lt;/em&gt; icon or pressing &lt;code&gt;Ctrl + Shift + X&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FyzwJDLa.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%2Fi.imgur.com%2FyzwJDLa.png" alt="Extension Icon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next search for &lt;em&gt;Live Server&lt;/em&gt; or the unique id of the extension: &lt;code&gt;ritwickdey.liveserver&lt;/code&gt; and click it, then click &lt;code&gt;install&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fw8h4RUu.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%2Fi.imgur.com%2Fw8h4RUu.png" alt="Install Live Server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(This is a reminder if you are using the &lt;a href="https://vscode.dev/" rel="noopener noreferrer"&gt;web version of VS Code&lt;/a&gt; that this extension does not work, please use Option 2)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once installed, a &lt;code&gt;Go Live&lt;/code&gt; icon will appear on the blue bar at the lower right corner of VS Code:&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%2Fi.imgur.com%2Fnoq3ClG.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%2Fi.imgur.com%2Fnoq3ClG.png" alt="Go Live Icon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Another alternative option is to simply right click on &lt;code&gt;index.html&lt;/code&gt; and select &lt;code&gt;"Open With Live Server"&lt;/code&gt; which is a new option that will appear when the extension is installed)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Regardless of which method you choose, you will be able to view your web page at whatever port the server decides, the default URL being &lt;a href=""&gt;http://localhost:5500&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FLOEVk8m.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%2Fi.imgur.com%2FLOEVk8m.png" alt="Local Web Server Live"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have any difficulty you can refer to the full documentation &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: HTTP Server
&lt;/h3&gt;

&lt;p&gt;If you have Node.js installed on your machine and are familiar with the basics of the command line, you can get a simple web server up and running in a few seconds.&lt;/p&gt;

&lt;p&gt;Navigate to the folder that has the web files you want to host (usually that means the directory with your &lt;code&gt;index.html&lt;/code&gt; file) and run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx http-server . -p 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note there is a period character before the &lt;code&gt;-p&lt;/code&gt; which indicates "this directory")&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That will start the server running in the directory you are in and serve the files. The &lt;code&gt;-p&lt;/code&gt; indicates the port which I've set as &lt;code&gt;8080&lt;/code&gt; which is the default, but you can run your server on any port you choose.&lt;/p&gt;

&lt;p&gt;You will be able to view your website's &lt;code&gt;index.html&lt;/code&gt; file by visiting this URL:&lt;/p&gt;

&lt;p&gt;&lt;a href=""&gt;http://localhost:8080&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obviously change the &lt;code&gt;8080&lt;/code&gt; if you decide to use a different port. And remember that &lt;code&gt;localhost&lt;/code&gt; is simply a special shorthand name for the IP address &lt;code&gt;127.0.0.1&lt;/code&gt; also known as the &lt;em&gt;home&lt;/em&gt; address.&lt;/p&gt;

&lt;p&gt;When you are done with your server simply press &lt;code&gt;ctrl+c&lt;/code&gt; to close it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 3: Chrome Extension
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;(Reminder that you only need to choose one option, if you already have your HTML running in the browser then skip ahead)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are using the web version of VS Code or another editor and just want to get your code up in the browser, another easy option is the Chrome browser extension. This option requires you to use the Chrome browser.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(If you cannot use the Chrome browser, or would prefer to run your own on your own machine via the command line then jump ahead to option 3)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Start by installing the extension called &lt;a href="https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb" rel="noopener noreferrer"&gt;Web Server for Chrome&lt;/a&gt; in your Chrome browser&lt;/p&gt;

&lt;p&gt;Next navigate to &lt;a href="https://dev.tochrome://apps/"&gt;chrome://apps/&lt;/a&gt; in your Chrome browser. There you should see and be able to click on your new Chrome app.&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%2Fi.imgur.com%2FTCDFo5S.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%2Fi.imgur.com%2FTCDFo5S.png" alt="Web Server for Chrome App"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the menu that appears select &lt;code&gt;"CHOOSE FOLDER"&lt;/code&gt; and navigate to your project, the &lt;code&gt;/my-project&lt;/code&gt; directory that contains your &lt;code&gt;index.html&lt;/code&gt; file inside of it that you created in the first section.&lt;/p&gt;

&lt;p&gt;Finally go to the URL that the extension shows in the menu, by default it is &lt;a href=""&gt;&lt;/a&gt;. If all goes well you will see your page!&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%2Fi.imgur.com%2FPqtvV99.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%2Fi.imgur.com%2FPqtvV99.png" alt="My Page in Chrome Server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 4: No server at all
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;(Reminder that you only need to choose one option, if you already have your HTML running in the browser then skip ahead)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are unable for any reason to install software on your machine (or even extensions in your browser) then we still have an option for being able to write code and test it in the browser.&lt;/p&gt;

&lt;p&gt;The title of &lt;em&gt;"no server at all"&lt;/em&gt; is a bit of a misnomer as there is still a server; it's just being run by someone else and you are simply providing the code to be served.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This option would technically work even for a device like a phone or tablet.  Though I would not recommend trying to code on a small touch device; I will say that maybe a tablet with a big enough screen and a bluetooth keyboard you might be able to get yourself a viable environment for practicing (if you have no other alternatives).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the first section of this tutorial we use Codepen to demonstrate how to quickly write some HTML, CSS and Javascript. Unfortunately Codepen does not provide an easy free way to mimic the file structure of a real project.&lt;/p&gt;

&lt;p&gt;For this example we are going to use &lt;a href="https://replit.com/" rel="noopener noreferrer"&gt;Replit&lt;/a&gt;. It's an absolutely fantastic tool that supports browser-based coding environments in all kinds of programming languages. It does require you to sign up however, but doing so will give you the big benefit of being able to save your projects, share them with others, and come back to them later.&lt;/p&gt;

&lt;p&gt;Start by navigating to &lt;a href=""&gt;https://replit.com/&lt;/a&gt; and creating an account. Once you are logged in you will see a &lt;code&gt;Create&lt;/code&gt; option with a &lt;code&gt;+&lt;/code&gt; button:&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%2Fi.imgur.com%2Fw0nv6iR.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%2Fi.imgur.com%2Fw0nv6iR.png" alt="Replit Create Project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click that button and you will have a number of templates you can choose from the dropdown. Select &lt;code&gt;HTML, CSS, JS&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4DuilyI.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%2Fi.imgur.com%2F4DuilyI.png" alt="Replit Templates"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point you will have your own web editor that looks quite similar to VS Code. On the left are all your files generated and setup for you, with default templates provided. GO ahead and replace the content of &lt;code&gt;index.html&lt;/code&gt; with our example and press the &lt;code&gt;Run&lt;/code&gt; button. You will see the same output that we have on our local server:&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%2Fi.imgur.com%2FsJOo8Rk.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%2Fi.imgur.com%2FsJOo8Rk.png" alt="Replit Running Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You now have an environment you can continue to follow along and write code in directly in your browser.&lt;/p&gt;

&lt;p&gt;In future tutorials (and as you learn more and your projects get more complex) you will likely begin to run into limitations of what you can do with this tool, but if your goal is to learn the fundamentals of HTML, CSS and JS then this tool can easily take you the majority of the way if you need it to.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else do I need to know about web servers?
&lt;/h2&gt;

&lt;p&gt;Some topics related to web servers that are worth learning about as you build your skills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Domain" rel="noopener noreferrer"&gt;Domains &amp;amp; Subdomains&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.cloudflare.com/en-ca/learning/cloud/what-is-the-cloud/" rel="noopener noreferrer"&gt;Cloud services&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/firewall" rel="noopener noreferrer"&gt;Firewalls&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security" rel="noopener noreferrer"&gt;Security&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview" rel="noopener noreferrer"&gt;HTTP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/https" rel="noopener noreferrer"&gt;HTTPS &amp;amp; SSL&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning web servers?
&lt;/h2&gt;

&lt;p&gt;There are tons of great resources on learning HTML out there, and they're free!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP" rel="noopener noreferrer"&gt;MDN&lt;/a&gt; again is your best friend for learning the fundamentals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When you are ready to learn how to configure your own real web server then I would suggest a &lt;a href="https://www.digitalocean.com/products/droplets/" rel="noopener noreferrer"&gt;Digital Ocean Droplet&lt;/a&gt;. That page might look overwhelming, but it's just a fancy name for remote access to one of their computers you can put your web content on, and let other people access. They have a great tutorial on setting up one of the most popular web servers called &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04" rel="noopener noreferrer"&gt;Nginx&lt;/a&gt; (pronounced engine-X).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  CSS
&lt;/h1&gt;

&lt;p&gt;At this stage of the tutorial we are operating under the assumption that you were able to successfully get one of the three options for running a local server up and running, and you have the ability to view your HTML in the browser.&lt;/p&gt;

&lt;p&gt;In this section of the tutorial we will begin to learn about how we can &lt;em&gt;style&lt;/em&gt; our content with CSS.&lt;/p&gt;

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

&lt;p&gt;CSS stands for &lt;em&gt;Cascading Style Sheets&lt;/em&gt; and it represents a syntax for describing for HTML content should look. Someone who is well versed in CSS can take the same HTML content and make two completely different looking pages out of it, such that you might hardly recognize it comes from the same HTML source.&lt;/p&gt;

&lt;p&gt;A great resource to demonstrate this idea is &lt;a href="http://www.csszengarden.com/" rel="noopener noreferrer"&gt;CSS Zen Garden&lt;/a&gt;. On the right side of the page are links you can click on to apply different CSS stylesheets to the site. The HTML content doesn't change, but with the power of CSS each design feels like an entirely different site!&lt;/p&gt;

&lt;p&gt;Before we discuss the concepts, you should be familiar with the most basic syntax. Let's begin with a simple example of some CSS, and explain what it is and how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&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;Take a look at what happens when this CSS is applied to the HTML from the example in our previous section:&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%2Fi.imgur.com%2FE6lpBuT.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%2Fi.imgur.com%2FE6lpBuT.png" alt="CSS Simple Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note you don't need to create any files or do any coding along with this section, we are just using this as an example to learn the syntax, you will learn how to create your own &lt;code&gt;.css&lt;/code&gt; files and add them to our project in the next section)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It should be fairly straightforward what has happened based on the example above. Our &lt;code&gt;"Hello everyone!"&lt;/code&gt; text has been formatted with the styles we described in the CSS.&lt;/p&gt;

&lt;p&gt;These style descriptions like &lt;code&gt;color: green&lt;/code&gt; are calledCSS &lt;em&gt;properties&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Properties
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/property/CSS" rel="noopener noreferrer"&gt;CSS properties&lt;/a&gt; are combination of a name (e.g. color) and value (e.g. green) separated by a colon that describe what styles to apply to the elements you have selected.&lt;/p&gt;

&lt;p&gt;There are more properties out there than any one person is likely going to learn in an entire career. Fortunately you &lt;em&gt;do not need to learn them all&lt;/em&gt;. Many of them are either not supported anymore, or their use is strongly discouraged.&lt;/p&gt;

&lt;p&gt;Focus on trying to learn the core properties &lt;strong&gt;well&lt;/strong&gt; rather than trying to learn a lot of different properties. Like many things in life you'll find than a small number of them end up comprising the vast majority of usage.&lt;/p&gt;

&lt;p&gt;Here is a hand picked list of the most common properties you will encounter, and the most important ones to learn (the rest can be picked up as you encounter them):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;display&lt;/li&gt;
&lt;li&gt;position&lt;/li&gt;
&lt;li&gt;box-sizing&lt;/li&gt;
&lt;li&gt;width (including min-width and max-width)&lt;/li&gt;
&lt;li&gt;height (including min-height and max-height)&lt;/li&gt;
&lt;li&gt;margin&lt;/li&gt;
&lt;li&gt;padding&lt;/li&gt;
&lt;li&gt;border&lt;/li&gt;
&lt;li&gt;color&lt;/li&gt;
&lt;li&gt;background-color&lt;/li&gt;
&lt;li&gt;background-image&lt;/li&gt;
&lt;li&gt;font-family&lt;/li&gt;
&lt;li&gt;font-style&lt;/li&gt;
&lt;li&gt;font-weight&lt;/li&gt;
&lt;li&gt;z-index&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MDN also has a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Properties_Reference" rel="noopener noreferrer"&gt;slightly larger opinionated list&lt;/a&gt; that you can use as a quick reference to learn about these and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Selectors, Combinators and Specificity
&lt;/h3&gt;

&lt;p&gt;In our CSS example above, why did the styles apply to the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element and not the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element? The reason is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors" rel="noopener noreferrer"&gt;CSS selectors&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our example we are using a &lt;code&gt;tag selector&lt;/code&gt; for the &lt;code&gt;p&lt;/code&gt; tag. You can see that before the opening of the first curly brace &lt;code&gt;p {&lt;/code&gt;. This will apply all styles in that block (between the curly braces) to all &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements on the page.&lt;/p&gt;

&lt;p&gt;Selectors are one of the most basic features of CSS, they describe which specific elements that your styles should be applied to; but what happens if multiple selectors try and apply the same CSS property to an element?&lt;/p&gt;

&lt;p&gt;The default is that the styles that come later would overwrite. So in the example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&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;All &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements on the page with this CSS would render as red. This is where the concept of the &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance" rel="noopener noreferrer"&gt;cascade&lt;/a&gt; in &lt;em&gt;Cascading Style Sheets&lt;/em&gt; comes from.&lt;/p&gt;

&lt;p&gt;However this only applies if the selectors are exactly the same level of &lt;em&gt;specificity&lt;/em&gt;. They are in this example because they are identical (each one is a &lt;code&gt;tag selector&lt;/code&gt; for &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tags.) There are many different kinds of selectors though, and ones that are considered &lt;em&gt;more specific&lt;/em&gt; would take precedence even if they came earlier on the sheet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity" rel="noopener noreferrer"&gt;Specificity&lt;/a&gt; is what determines which property gets applied to an element in a scenario where a property is set from more than one selector.&lt;/p&gt;

&lt;p&gt;Let's take a look at each possible level of selector in &lt;em&gt;order of specificity&lt;/em&gt;. This means that each one of the examples below is more specific than the last, so it would override those styles even if they appeared first on the style sheet:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Global Selector&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&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 asterisk is called the &lt;code&gt;global selector&lt;/code&gt; and it targets every single element in your HTML. There are not many cases when you want to apply a style to every element in your page, so it doesn't get used too often.&lt;/p&gt;

&lt;p&gt;It can be handy for debugging, for example to place a &lt;code&gt;border&lt;/code&gt; around every element on your page to help quickly get a visual indication of the size of eah element.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Tag Selector&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&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 above example shows two tag selectors. It will apply a green color to all &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements on the page and a height of 100px to all &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; elements.&lt;/p&gt;

&lt;p&gt;If you used the &lt;code&gt;*&lt;/code&gt; selector to set the color of all elements, this would overwrite that color value for &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;div&lt;/code&gt; tags.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Class selector&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.example-class&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"example-class"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;I will be green&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;class selector&lt;/code&gt; uses a period &lt;code&gt;.&lt;/code&gt; before the term of your selector and will target all HTML elements with that term on the class attribute. In our example the term is &lt;code&gt;example-class&lt;/code&gt; but that term can be anything you like.&lt;/p&gt;

&lt;p&gt;The class selector is more specific than the tag selector, so green is applied.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;ID Selector&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.example-class&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#example-id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"example-class"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"example-id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;I will be green&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ID selector&lt;/code&gt; uses a pound symbol &lt;code&gt;#&lt;/code&gt; before the term of your selector and will target all HTML elements with that term on the ID attribute. In our example the term is &lt;code&gt;example-id&lt;/code&gt; but that term can be anything you like.&lt;/p&gt;

&lt;p&gt;The ID selector is more specific than the class selector, so green is applied.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Inline styles&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#example-id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"example-id"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color: green;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;I will be green&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a selector per-se, since it gets set directly on your HTML element as an attribute rather than within your CSS.&lt;/p&gt;

&lt;p&gt;HTML elements all have an attribute called &lt;code&gt;style&lt;/code&gt; that allows you to set CSS properties directly. These properties are so specific they will override even ID selectors.&lt;/p&gt;

&lt;p&gt;It can be convenient to quickly set styles directly on the element, however you should be cautious as it is often considered a bad practice. The reason being that they are difficult to override elsewhere, and that they exist outside of your stylesheets. Having styles in more than one location can make it difficult to reason about how styles are being applied.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;!important&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#example-id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt; &lt;span class="cp"&gt;!important&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"example-id"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color: green;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;I will be red&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Often called the &lt;em&gt;nuclear option&lt;/em&gt; when all else fails and you can't figure out why your styles are being overwritten, CSS supports a very powerful option called &lt;code&gt;!important&lt;/code&gt; that essentially says &lt;em&gt;this style cannot be overwritten&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Notice in our example it even takes precedence over inline styles.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;!important&lt;/em&gt; is nearly always considered very bad practice for reasons that should be obvious. The entire concept behind &lt;em&gt;cascading&lt;/em&gt; style sheets is that styles are designed to be overwritten at different levels of specificity. &lt;em&gt;!important&lt;/em&gt; breaks that model entirely.&lt;/p&gt;

&lt;p&gt;To give an example: consider a scenario where your downloaded a library of "cool buttons" that looked fantastic and fit the needs exactly for your clients product. Your client says "they're perfect, we just need them to be blue instead of green". You find out to your dismay the button library author used &lt;code&gt;background-color: green !important;&lt;/code&gt; when styling them. There are ways around this, but your job has just become significantly harder than it needed to be.&lt;/p&gt;

&lt;p&gt;In summary, avoid &lt;code&gt;!important&lt;/code&gt; entirely unless you are absolutely sure you know what you're doing.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Multiple Selectors&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;You can combine styles together and apply them to more than one selector with a comma. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bold&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;Will apply the &lt;em&gt;bold&lt;/em&gt; style to all &lt;code&gt;h1&lt;/code&gt; and &lt;code&gt;h2&lt;/code&gt; elements on your page.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Combinators&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The last aspect of CSS we need to address before going into our example is &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators" rel="noopener noreferrer"&gt;combinators&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Combinators work in tandem with selectors. They allow you to chain multiple selectors together to get more specific. They are applied most often when dealing with nested elements. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;I am black text&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;I am white text and 20px size&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;I am white text but regular size&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two combinators in this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;div p&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;div &amp;gt; p&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one uses the &lt;em&gt;space&lt;/em&gt; combinator, a space between selectors means &lt;em&gt;all children of elements targeted by the first selector&lt;/em&gt;. So styles in &lt;code&gt;div p&lt;/code&gt; would apply to every &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element that is a child of a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;In our example this is necessary. Since we gave our &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; a black background, the text in the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements would be invisible if we did not set it to white.&lt;/p&gt;

&lt;p&gt;The second one uses the angle bracket &lt;code&gt;&amp;gt;&lt;/code&gt;, it means &lt;em&gt;direct child of this element&lt;/em&gt;, so any &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element that is a &lt;strong&gt;direct&lt;/strong&gt; child of a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element will be targeted with the styles we write here.&lt;/p&gt;

&lt;p&gt;Notice the word &lt;em&gt;direct&lt;/em&gt; in this example only applies to &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements that have a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; as a direct parent. Our first &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; has no parent and our third &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element has a &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; as a parent, so only the second one has the &lt;code&gt;font-size: 20px&lt;/code&gt; style applied.&lt;/p&gt;

&lt;p&gt;You can find a great quick reference for selectors and combinators &lt;a href="https://specifishity.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we have covered all of the basics, let's take a look at a real world example that we can continue to iterate on for the remainder of this tutorial!&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use CSS?
&lt;/h2&gt;

&lt;p&gt;There are three primary ways to apply CSS to your HTML:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using the &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;style&lt;/code&gt; HTML attribute&lt;/li&gt;
&lt;li&gt;Using a &lt;code&gt;.css&lt;/code&gt; file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Option #3 is by far the most common and nearly always the best practice, however since we are here to learn we'll quickly begin by showing an example of options #1 and #2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Example&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;I am green&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"color: red;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;I am red&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example demonstrates the use of the &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag in the header applying a green colour to all &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; elements.&lt;/p&gt;

&lt;p&gt;Within the HTML itself the second &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element has a &lt;code&gt;style&lt;/code&gt; attribute which is setting the &lt;code&gt;color&lt;/code&gt; property to red. This has more specificity than the tag selector, so the second paragraph element will render as red.&lt;/p&gt;

&lt;p&gt;To demonstrate the third and most common option (a &lt;code&gt;.css&lt;/code&gt; file) we are going to construct a more complex example and take the time to break each selector and property down to get some experience working with something that looks more like a stylesheet you might encounter in a real world site.&lt;/p&gt;

&lt;p&gt;Begin by creating an &lt;code&gt;index.html&lt;/code&gt; file in the root directory of a project (you can use the one you already created it you are following along) and paste the following code into it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My Animal Blog&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My Favourite Animals&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Enjoy these furry friends&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
          &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://res.cloudinary.com/dqse2txyi/image/upload/v1657421273/blogs/intro-to-web-development/cat_k4fcww.png"&lt;/span&gt;
          &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Cat Playing Chess"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card__container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Chess Cat&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;He's planning his next move.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;copy;&lt;/span&gt; 2022&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key line to look at in the above example is this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This element tells your browser that you want to link an external stylesheet, and the filename is &lt;code&gt;style.css&lt;/code&gt;. It looks in the root directory by default. As of right now, you do not have a &lt;code&gt;style.css&lt;/code&gt; file in the root directory of your project.&lt;/p&gt;

&lt;p&gt;Without any CSS at all, this page looks like:&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%2Fi.imgur.com%2FWyqOsI7.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%2Fi.imgur.com%2FWyqOsI7.png" alt="Unstyled Page Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not too bad, but we can make it look a lot better. Create a new file in the root directory next to &lt;code&gt;index.html&lt;/code&gt; and call it &lt;code&gt;style.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Leave it empty to start. We're going to add some CSS little by little to clean it up a bit and give you an idea how to craft an extremely simple, but still modern and responsive page design. We'll also explain each piece in detail as we go.&lt;/p&gt;

&lt;p&gt;So feel free to add each of these pieces to your &lt;code&gt;style.css&lt;/code&gt; file as you read them, one after the other &lt;em&gt;(it's not necessary though if you would prefer to just read, we'll post the full file contents at the end)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So let's begin styling our animal blog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body" rel="noopener noreferrer"&gt;body&lt;/a&gt; in HTML defines where all the content is. The body is inside the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element, which by default will span the entire width of the page.&lt;/p&gt;

&lt;p&gt;Let's look at each property in the body tag selector, to see what they do and why we chose them.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;max-width: 800px;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Typically in many modern web pages you'll find it common for the actual content not to span the entire width of a user's screen. People often use very wide monitors these days and it can be challenging to read content, particularly text that spans from one edge to the other.&lt;/p&gt;

&lt;p&gt;For an easy example of this go to Google and search. You'll see that the search results only span a small portion of the screen before the text wraps (on my 1920px monitor the results are 600px wide).&lt;/p&gt;

&lt;p&gt;We are doing something similar for our blog. Body content can only be a maximum of 800px wide, and will shrink down automatically on smaller screens.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;margin-auto;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With only &lt;code&gt;max-width&lt;/code&gt; our content will still be left justified on the page. We would like it to be centred. That's what having an auto margin does in this context.&lt;/p&gt;

&lt;p&gt;On the top and bottom it will do nothing since the default height of &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; is only the height of our content; however the width is the width of thr full screen. The difference between that screen width and the 800px content will automatically become margin on the left and right.&lt;/p&gt;

&lt;p&gt;This has the result of placing the content in the centre.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;color: #333333;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Pure black text on a pure white background creates a fairly stark contrast. It's not terrible, but it's fairly common to use a not-quite-black color instead of black for text on a white background.&lt;/p&gt;

&lt;p&gt;Here we have chosen a &lt;a href="https://en.wikipedia.org/wiki/Web_colors#Hex_triplet" rel="noopener noreferrer"&gt;hex colour&lt;/a&gt; that is close to black, but not quite.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;font-family: Helvetica, sans-serif;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After setting the color we are also setting the default font of our site. We've chosen Helvetica because it is one of the &lt;a href="https://web.mit.edu/jmorzins/www/fonts.html" rel="noopener noreferrer"&gt;safe web fonts&lt;/a&gt; that are available on the majority of web browsers and operating systems.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;font-family&lt;/code&gt; property allows as many font names as you like separated by commas. It will chose the first one it finds from left to right that exists on a user's system. The final option &lt;code&gt;sans-serif&lt;/code&gt; simply says &lt;em&gt;worst case give me any &lt;a href="https://en.wikipedia.org/wiki/Sans-serif" rel="noopener noreferrer"&gt;sans-serif&lt;/a&gt; font you have&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here's a look at what we have so far with our &lt;code&gt;body&lt;/code&gt; styles:&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%2Fi.imgur.com%2FDPtY0uB.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%2Fi.imgur.com%2FDPtY0uB.png" alt="CSS Example 1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;footer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;italic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;lighter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;margin-bottom: 40px;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We added this to give a bit of space at the bottom of all the main content before the footer, so the copyright symbol doesn't press up directly against the text.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;text-align: center;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As described, this centre aligns the text in the header and footer. Since the header includes both an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; element each one will automatically &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/inherit" rel="noopener noreferrer"&gt;inherit&lt;/a&gt; that property.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;font-family, font-style, font-weight&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Each property sets the font properties as described.&lt;/p&gt;

&lt;p&gt;Similar to the previous, but now our fonts are updated and our texts are centred:&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%2Fi.imgur.com%2FaKhsrxa.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%2Fi.imgur.com%2FaKhsrxa.png" alt="CSS Example 2"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;350px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;width: 350px;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We are going to set our &lt;code&gt;card&lt;/code&gt; elements to be 350px wide. This is simply a value I have chosen based on common screen sizes. Very few modern smartphones have a width smaller than 375px, so setting our cards to 350px means they will fit nicely (without having to be shrink) on nearly every device.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;margin: auto;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Used again for centring, this time to centre the card inside the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;. Since the card is 350px and the body is 800px this will set margins on either side to fill the difference and centre the element.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Easily the most complex of all our properties, but a good example to break down because it will not be uncommon to encounter this type of property in your CSS journey.&lt;/p&gt;

&lt;p&gt;First the property itself, &lt;code&gt;box-shadow&lt;/code&gt; creates a shadow like effect around the edge of an element. The thickness of it depends on some numeric values. In this case it is the four numeric values you see &lt;code&gt;0 4px 8px 0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Whenever you see a CSS property with four consecutive numeric values it typically refers to the sides of a box in clockwise order from the top. This image from MDN illustrates:&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%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FCSS%2FShorthand_properties%2Fborder4.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%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FCSS%2FShorthand_properties%2Fborder4.png" alt="CSS Four Side Properties"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So in our example, there is no shadow on the top, 4px on the right, 8px on the bottom and no shadow on the left. In CSS when using the number 0 it is standard to leave off the &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units" rel="noopener noreferrer"&gt;unit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The final fifth value on box shadow indicates the colour. For an &lt;code&gt;rgba&lt;/code&gt; colour &lt;code&gt;0, 0, 0&lt;/code&gt; is black and the final value is the alpha; think of as the opacity. That's what makes the shadow look more natural and diffuse rather than a solid black at 0.2.&lt;/p&gt;

&lt;p&gt;If you managed to follow this one, well done! If not, don't feel bad about skipping over it. This type of syntax will grow on you naturally as you encounter it more often.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;border-radius: 10px;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A border radius will give us rounded corners. The larger the value the more rounded. It's common to use this property to create circles by giving a radius of 50%. For our case 10px give a nice rounded edge to the card.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;overflow: hidden;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is necessary to keep the image from going over our rounded corners. Since the image has rectangular images and sits above the card &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; it would hide the rounded corners of the card.&lt;/p&gt;

&lt;p&gt;Hiding the card's overflow keeps the image inside the card and the edges visibly round.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&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;Setting the width of our image (using the direct child combinator) to 100% will stretch it to the edge of its part, the 350px card. Setting the height to &lt;code&gt;auto&lt;/code&gt; ensures that the aspect ratio remains correct.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card__container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&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;For our class selector here we have used a common practice to help with CSS &lt;em&gt;scoping&lt;/em&gt;. Imagine we had just called this class &lt;em&gt;container&lt;/em&gt;. It's a pretty common term, what if we have a container somewhere else on the site? The styles of that &lt;em&gt;container&lt;/em&gt; class would overlap and mix unintentionally with these ones.&lt;/p&gt;

&lt;p&gt;I've chosen to prefix the class name with the name of the parent &lt;em&gt;card&lt;/em&gt; with two underscores between. This is a common practice based on a methodology called &lt;a href="http://getbem.com/introduction/" rel="noopener noreferrer"&gt;BEM&lt;/a&gt; or &lt;em&gt;block-element-modifier&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Essentially it's just a way of naming things to avoid unintentional collisions between unrelated elements. There are many different ways of doing this, you should choose whatever feels right to you as you gain more experience.&lt;/p&gt;

&lt;p&gt;The property itself &lt;code&gt;padding: 16px&lt;/code&gt; will create a buffer of space inside the border of the element. This keeps the text from pressing up against the edge of the box border, and makes things look a lot cleaner.&lt;/p&gt;

&lt;p&gt;Now finally with all properties applied, or styling for this example is done. Take a look:&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%2Fi.imgur.com%2FhnBHPbA.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%2Fi.imgur.com%2FhnBHPbA.png" alt="CSS Example 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What else do I need to know about CSS?
&lt;/h2&gt;

&lt;p&gt;The "cascade" is how CSS decides which styles actually get applied to an element when multiple different rules are applying values to the same property.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance" rel="noopener noreferrer"&gt;Cascade &amp;amp; inheritance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The box model describes the way every element in CSS is rendered on the page and all the factors (padding, margin, border) etc that go into deciding its size and how it flows with the rest of the content.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model" rel="noopener noreferrer"&gt;The Box Model&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Flexbox is one of the most popular ways of laying out content on a web page. Modern browsers will support &lt;code&gt;Grid&lt;/code&gt; which is even more powerful for full 2D layouts, but any modern CSS developer must understand Flexbox when contributing to web projects professionally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/flex" rel="noopener noreferrer"&gt;Flexbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Media queries are used to change which CSS styles are applied depending on what media the user is using to view it. Most commonly used to change styles for mobile devices.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries" rel="noopener noreferrer"&gt;Media Queries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many different units in CSS (px, em, rem, etc) and it's important to understand the difference between them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units" rel="noopener noreferrer"&gt;CSS Units&lt;/a&gt;
DEBUGGING CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What are the best free resources for learning CSS?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.theodinproject.com/paths/foundations/courses/foundations#css-foundations" rel="noopener noreferrer"&gt;The Odin Project&lt;/a&gt; - The Odin Project CSS foundations curriculum&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://flukeout.github.io/" rel="noopener noreferrer"&gt;CSS Diner&lt;/a&gt; - A fun and effective way of learning CSS selectors&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://flexboxfroggy.com/" rel="noopener noreferrer"&gt;Flexbox Froggy&lt;/a&gt; - A fun and effective way of learning Flexbox&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://mastery.games/post/flexboxzombies2/" rel="noopener noreferrer"&gt;Flexbox Zombies&lt;/a&gt; - Another fun way to learn Flexbox&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://knightsoftheflexboxtable.com/" rel="noopener noreferrer"&gt;Knights of the Flexbox Table&lt;/a&gt; - Another fun way to learn Flexbox&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cssgridgarden.com/" rel="noopener noreferrer"&gt;Grid Garden&lt;/a&gt; - A fun way to learn CSS Grid&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/" rel="noopener noreferrer"&gt;Complete Guide to CSS Flexbox&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://css-tricks.com/snippets/css/complete-guide-grid/" rel="noopener noreferrer"&gt;Complete Guide to CSS Grid&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://specifishity.com/" rel="noopener noreferrer"&gt;Specificity Cheatsheet&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.w3schools.com/cssref/css_selectors.asp" rel="noopener noreferrer"&gt;Selectors Reference&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Properties_Reference" rel="noopener noreferrer"&gt;Properties Reference&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Javascript
&lt;/h1&gt;

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

&lt;p&gt;Javascript is a programming language, originally developer to run code in web browsers to make pages more interactive. Since then its potential usages have expanded significantly, however for the purposes of this tutorial, web page manipulation is the use we are going to focus on.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use Javascript?
&lt;/h2&gt;

&lt;p&gt;There are a lot of ways to use Javascript. If you just want to write your very first code you can do so in a matter of seconds. THe quickest and easiest place to write and run Javascript code is directly in your web browser.&lt;/p&gt;

&lt;p&gt;Hit the F12 button to open up the browser's development console (alternatively you can look for a "Dev Tools" option in your browser's settings menu).&lt;/p&gt;

&lt;p&gt;It will open be an attached bar, on either the bottom or the right side of the browser window (depending on the browser). You will see a number of tabs across the top, these values will vary between browsers, but all the major ones (Edge / Firefox / Chrome) will have a tab called &lt;em&gt;console&lt;/em&gt; as highlighted in the below screenshot.&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%2Fi.imgur.com%2FOoxW46B.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%2Fi.imgur.com%2FOoxW46B.png" alt="Browser Console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Within the browser's console you can type and run any code you like. We'll begin by running the simplest possible Javascript code, the traditional "hello world!" program. Type the following into your browser's console and hit enter:&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello world!&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;Your output should match what you see in the screenshot above. Below the code the text "hello world!" is printed out. Your code asked for the browser's &lt;code&gt;console&lt;/code&gt; to use its &lt;code&gt;log&lt;/code&gt; method and print out the "hello world!" &lt;code&gt;string&lt;/code&gt; (a string is a sequence of text characters).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Strings&lt;/em&gt; are a &lt;em&gt;primitive value&lt;/em&gt; in Javascript. A type of data that is built-in and supported by the language. Another example is the &lt;em&gt;number&lt;/em&gt; data type. You can read more about primitive data types &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you like.&lt;/p&gt;

&lt;p&gt;Now as you can probably imagine, very few people write their Javascript directly in the browser console. For many reasons, but the simplest of which is that the code is gone as soon as you close your browser. We'd like to be able to write some Javascript that sticks around! To do that we need the HTML &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;Before we return to our code from the previous section, let's use the simplest example we can. Create an &lt;code&gt;index.html&lt;/code&gt; file that looks like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My First Javascript Project&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello world!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;My Javascript Test Page&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we have included some Javascript code in the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag? Try opening up your page on your local web server and checking your result. You should see the "My Javascript Test Page" text from the &lt;code&gt;body&lt;/code&gt; as expected, but if you open your browser console again you will see your message.&lt;/p&gt;

&lt;p&gt;Just as before, using the &lt;code&gt;console.log&lt;/code&gt; function we have instructed out browser to print the "hello world!" string in the console.&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%2Fi.imgur.com%2F0FSQgNi.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%2Fi.imgur.com%2F0FSQgNi.png" alt="Javascript Test Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great, but there's still one final step. Similar to CSS, although originally the standard was to write Javascript code directly in your HTML, at some point everyone realized that it made more sense to separate it into its own file. Let's look at how to load a Javascript file into our site.&lt;/p&gt;

&lt;p&gt;Begin by creating a &lt;code&gt;script.js&lt;/code&gt; file (again the filename doesn't matter, you can call it anything you like as long as it ends with a &lt;code&gt;.js&lt;/code&gt; extension):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello world!&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;And then update your HTML file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My First Javascript Project&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;My Javascript Test Page&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how our &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;src&lt;/code&gt; attribute is the filename and path of the file that you want to load.&lt;/p&gt;

&lt;p&gt;Save both files and refresh your &lt;code&gt;index.html&lt;/code&gt; page. You'll see once again that "hello world!" appears in the console, but this time the code is being loaded in from the &lt;code&gt;.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;At this point you now have the knowledge of how to set up a working Javascript environment and run any code you like. Of course this is only the tip of the iceberg, the ocean of JS is very deep, but the wonderful thing is that you can even as a beginner you can accomplish a lot with just a little.&lt;/p&gt;

&lt;p&gt;Teaching the Javascript language itself is beyond the scope of this tutorial (I would highly recommend &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript#for_complete_beginners" rel="noopener noreferrer"&gt;MDN's tutorial&lt;/a&gt; as usual for that) but we will take the time to explore just a little bit deeper into some of the most common use cases.&lt;/p&gt;

&lt;p&gt;One of the main usages of Javascript is for manipulating the &lt;em&gt;DOM&lt;/em&gt;. The DOM is a term you will come across frequently in web development and it can be a little confusing at first, but we'll make sure to describe exactly what it is in the next section, and how you can use that knowledge to make your web pages more interactive.&lt;/p&gt;

&lt;h3&gt;
  
  
  The DOM
&lt;/h3&gt;

&lt;h2&gt;
  
  
  What is the DOM?
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;DOM&lt;/em&gt; stands for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model" rel="noopener noreferrer"&gt;Document Object Model&lt;/a&gt; and most simply put it just means the actual structure of the page built by your browser when following the instructions described by your HTML.&lt;/p&gt;

&lt;p&gt;Think of your HTML file as the blueprints of a house, and the DOM as the house itself.&lt;/p&gt;

&lt;p&gt;You can use a single set of blueprints (HTML) to build as many houses (pages in the browser) as you want. Maybe in one of those houses you might choose to change the colour of the exterior paint from white to blue. This change of paint colour would be analogous to what Javascript does.&lt;/p&gt;

&lt;p&gt;When you change the paint colour of your house you change it on the &lt;em&gt;house&lt;/em&gt; itself, you don't necessarily update the blueprints to say "all houses must be blue." Similarly, when you use Javascript to change the background colour of your page, you are changing it on the &lt;em&gt;DOM&lt;/em&gt; and it's updating the background colour of the page in your browser. It's not changing the HTML file itself.&lt;/p&gt;

&lt;p&gt;The DOM is represented in the browser as a &lt;a href="https://en.wikipedia.org/wiki/Tree_(data_structure)" rel="noopener noreferrer"&gt;tree&lt;/a&gt; structure. Don't worry if that looks confusing, you've already used the structure before when writing your HTML. Your elements have a hierarchy and elements can be nested inside of other elements. This represents the tree structure. All elements (except for the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element) have a parent element.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I view the DOM?
&lt;/h2&gt;

&lt;p&gt;Browsers make it very easy to take a look at the DOM directly. Open up your web page again and right click on the "My Javascript Test Page" text. You will se an option to &lt;em&gt;Inspect&lt;/em&gt;. This option is available on all browsers.&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%2Fi.imgur.com%2Fxh0pQzq.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%2Fi.imgur.com%2Fxh0pQzq.png" alt="Browser Inspect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inspecting the element will open up the dev tools console, but this time it will default to the DOM tab (it may be called "Elements" or "Inspector" depending on your browser.) Here you can see the DOM structure that has been built by your browser based on the instructions provided by the HTML.&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%2Fi.imgur.com%2FilcuM2G.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%2Fi.imgur.com%2FilcuM2G.png" alt="DOM Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With a simple page it is likely that the DOM structure will look identical to your HTML file. This isn't absolutely necessary though. We could have some Javascript that changed the DOM structure after it has built so that it no longer looks the same. Let's try that now.&lt;/p&gt;

&lt;p&gt;Click on the &lt;em&gt;Console&lt;/em&gt; tab of your browser's dev tools like we did before so that we can write some Javascript. This time, instead of using the &lt;code&gt;console.log&lt;/code&gt; function we are going to call a different function.&lt;/p&gt;

&lt;p&gt;All browsers provide Javascript with an &lt;em&gt;interface&lt;/em&gt; for interacting with the DOM through code. You can change, add, remove, clone, and generally just do almost anything you can think of with the elements on the page.&lt;/p&gt;

&lt;p&gt;First type the following code into the browser console and press enter:&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&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;When you hit enter you will see the result of your code directly below, it looks like a little &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element.&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%2Fi.imgur.com%2FviOdJy1.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%2Fi.imgur.com%2FviOdJy1.png" alt="Query Selector"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's break this line down and see exactly what it's doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;document&lt;/strong&gt; - This is a Javascript &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables" rel="noopener noreferrer"&gt;variable&lt;/a&gt; provided by the browser. It represents a reference to the page you are currently looking at (for example in your current tab). You can use it to find out all kinds of information, for example the width of the user's page, the current URL, and many more. In this example we are using it so we know which specific page to search for the element we want to change.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;querySelector&lt;/strong&gt; - Is a &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Function" rel="noopener noreferrer"&gt;function&lt;/a&gt; that exists on the &lt;em&gt;document&lt;/em&gt;. It's an incredibly powerful function that allows you to use CSS Selectors that we have already learned about to target particular elements on our page with Javascript. It's great because it lets you leverage skills you already learned in CSS and apply them to Javascript.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;"p"&lt;/strong&gt; - in this context "p" is a Javascript &lt;em&gt;string&lt;/em&gt; that represents our CSS selector. As you may remember, just &lt;code&gt;p&lt;/code&gt; on its own is a &lt;code&gt;tag selector&lt;/code&gt;. Our goal is to select the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element on our page. Although this is a very simple one, you can use any kind of CSS Selector you like. For example &lt;code&gt;document.querySelector("#example")&lt;/code&gt; is a valid function that would get a reference to any element with &lt;code&gt;id="example"&lt;/code&gt; that exists in the DOM.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when you combine the three of these together you get a Javascript function that searches the DOM for a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element and returns it to you (if there is more than one &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element on the page it will return the first one it finds, starting from the top and moving down the tree).&lt;/p&gt;

&lt;p&gt;Once you have that reference you have the ability to modify it. As we mentioned before we just want to change the content that is inside of the tag, the text that says &lt;em&gt;"My Javascript Test Page"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When you ran the &lt;code&gt;querySelector&lt;/code&gt; function in your console you got that little &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element returned on the next line. If you haven't done so already &lt;em&gt;click on it&lt;/em&gt;. You might be overwhelmed at first by try not to be. There are far more options and bits of information on a DOM node than the average developer will ever need. Just let them wash over you like background noise.&lt;/p&gt;

&lt;p&gt;Look for one called &lt;code&gt;innerText&lt;/code&gt; that should have a &lt;em&gt;string&lt;/em&gt; version of the text that we put inside of our &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element. This is the one we are going to update to change our page.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(In case you are wondering why we chose &lt;code&gt;innerText&lt;/code&gt; instead of &lt;code&gt;innerHTML&lt;/code&gt;, which looks exactly the same at a glance, the answer is that if you are just working with text (like we are) rather than adding new HTML, then &lt;code&gt;innerText&lt;/code&gt; is safer (though both would technically work). More information &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you are curious)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FzkyhWK9.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%2Fi.imgur.com%2FzkyhWK9.png" alt="DOM innerText"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now that we know the element that we want to change, how do we change it? When we run our &lt;code&gt;querySelector&lt;/code&gt; we get that &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element back, but we don't know how to change it yet.&lt;/p&gt;

&lt;p&gt;There are a number of options available, but this would be a good opportunity to introduce the concept of &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables" rel="noopener noreferrer"&gt;variables&lt;/a&gt;. You can use variables to store information in your program that you will need at a later time.&lt;/p&gt;

&lt;p&gt;Let's demonstrate how to save a reference to our &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; DOM node in a variable:&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;var&lt;/span&gt; &lt;span class="nx"&gt;myParagraph&lt;/span&gt; &lt;span class="o"&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&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;This is the same code as before, except this time we have &lt;em&gt;declared&lt;/em&gt; a variable that we've named &lt;code&gt;myParagraph&lt;/code&gt; and set it equal to the paragraph node in the DOM. This gives us an easy way to reference and make changes to that node.&lt;/p&gt;

&lt;p&gt;To bring it all together, the code to update our paragraph node on our page looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;myParagraph&lt;/span&gt; &lt;span class="o"&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;myParagraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&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 Updated Javascript Test Page&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;&lt;em&gt;(If you're wondering about the name of the &lt;code&gt;myParagraph&lt;/code&gt; variable, Javascript uses a naming convention called &lt;a href="https://developer.mozilla.org/en-US/docs/MDN/Guidelines/Code_guidelines/JavaScript#variables" rel="noopener noreferrer"&gt;camelCase&lt;/a&gt;. This is not mandatory, but is considered a best practice.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can run it in the console yourself to see:&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%2Fi.imgur.com%2FyoNXuT9.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%2Fi.imgur.com%2FyoNXuT9.png" alt="Updating the DOM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we've seen how we can interact with the DOM, let's move this code over to our &lt;code&gt;script.js&lt;/code&gt; file so that it runs every time we load the page. With this in place you will essentially never see the &lt;em&gt;"My Javascript Test Page"&lt;/em&gt; text, since the script will run immediately on page load and replace it with the &lt;em&gt;"My Updated Javascript Test Page"&lt;/em&gt; text.&lt;/p&gt;

&lt;p&gt;There are two necessary steps. First, update your &lt;code&gt;script.js&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;myParagraph&lt;/span&gt; &lt;span class="o"&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;myParagraph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&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 Updated Javascript Test Page&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;And a reminder that your &lt;code&gt;index.html&lt;/code&gt; should look like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My First Javascript Project&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;My Javascript Test Page&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you load the page now, even though this is the same code we used in the console, you'll notice that it doesn't work! Why not?&lt;/p&gt;

&lt;p&gt;The reason it doesn't work in this case is because of the &lt;em&gt;oder&lt;/em&gt; we are running it in. In the console we were running our &lt;code&gt;document.querySelector&lt;/code&gt; function in the console after the page had finished loading.&lt;/p&gt;

&lt;p&gt;If you look at our &lt;code&gt;index.html&lt;/code&gt; file above, imagine you are the browser parsing the file from the beginning and working your way down. You will get to the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element and run that &lt;code&gt;.js&lt;/code&gt; file before you've even reached and created the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element. So the &lt;code&gt;querySelector&lt;/code&gt; runs, finds nothing, and then its done its job. Nothing is telling it to run again after the page has loaded.&lt;/p&gt;

&lt;p&gt;There is a very easy fix for this, all we need to do is instruct out &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element to hold off and wait to run that code until the page has finished loading. We use the &lt;code&gt;defer&lt;/code&gt; attribute for this. Update your &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And try refreshing the page again., you should see &lt;em&gt;"My Updated Javascript Page"&lt;/em&gt; as expected as soon as the page is loaded.&lt;/p&gt;

&lt;p&gt;At this point you now have a very basic familiarity with Javascript, including how to run your code and some of the ways it can be used to manipulate DOM nodes on your page &lt;em&gt;(remember that _DOM nodes&lt;/em&gt; is just the term used to describe HTML elements that have been built into a page in the browser)_&lt;/p&gt;

&lt;p&gt;The last section in our Javascript introduction will go through an example of using Javascript to solve a real-world problem you might encounter.&lt;/p&gt;

&lt;p&gt;We'll continue where we left off at the end of the CSS section with our "Animal Blog" and the cool little card that we created.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I add Javascript to a website?
&lt;/h2&gt;

&lt;p&gt;Let's say we've been tasked with adding some new functionality to our animal blog. We want people to be able to "like" the images of cats that we are adding to our blog. A user need to be able to &lt;em&gt;interact&lt;/em&gt; and make a &lt;em&gt;change&lt;/em&gt; to our element, so we recognize immediately that it's a perfect use case for Javascript.&lt;/p&gt;

&lt;p&gt;First we will pull up our previous example. In case you don't have it handy, we need three files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;index.html&lt;/li&gt;
&lt;li&gt;style.css&lt;/li&gt;
&lt;li&gt;script.js&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My Animal Blog&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My Favourite Animals&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Enjoy these furry friends&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
          &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://res.cloudinary.com/dqse2txyi/image/upload/v1657421273/blogs/intro-to-web-development/cat_k4fcww.png"&lt;/span&gt;
          &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Cat Playing Chess"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card__container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Chess Cat&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;He's planning his next move.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onCLick=&lt;/span&gt;&lt;span class="s"&gt;"likeButton()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Like&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;copy;&lt;/span&gt; 2022&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;style.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;footer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;italic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;lighter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;350px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&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;At the moment we don't have any content in our &lt;code&gt;script.js&lt;/code&gt; file, leave it empty for now.&lt;/p&gt;

&lt;p&gt;There is a single difference between this file and the final versions of the examples at the end of our CSS section, in &lt;code&gt;index.html&lt;/code&gt; we have added a &lt;em&gt;Like&lt;/em&gt; button inside the card:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Like&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you serve the page in your browser you'll see it rendered:&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%2Fi.imgur.com%2FP85K087.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%2Fi.imgur.com%2FP85K087.png" alt="Animal Blog With Button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course at this point clicking it does nothing. In order to connect some Javascript to our button, first we have to write a Javascript &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions" rel="noopener noreferrer"&gt;function&lt;/a&gt;, give it a name, and finally attach it to our button.&lt;/p&gt;

&lt;p&gt;A function is essentially a block of JS code that you don't want to run right away. Another common use for functions is to create blocks of code that you might want to run &lt;em&gt;more than once&lt;/em&gt;. Both are great reasons to create a function.&lt;/p&gt;

&lt;p&gt;There are a number of ways to create functions as the JS language has evolved over many years. Here for simplicity we will teach the traditional method that works in all browsers. Later as you get more comfortable you can learn about the various shorthand forms.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;likeButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Like button has been pressed&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;When you load your &lt;code&gt;script.js&lt;/code&gt; file, the code inside of this function &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block" rel="noopener noreferrer"&gt;block&lt;/a&gt; (the code between the curly braces) is not run right away. You have to first &lt;em&gt;call&lt;/em&gt; the function (sometimes called &lt;em&gt;invoke&lt;/em&gt;) which basically means "run the code inside the function when i tell you to". The syntax in Javascript to &lt;em&gt;call&lt;/em&gt; a function is the function name followed by open and closed parentheses.&lt;/p&gt;

&lt;p&gt;So calling our &lt;code&gt;likeButton&lt;/code&gt; function would look like:&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="nf"&gt;likeButton&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;alert&lt;/code&gt; function is another built-in browser function like &lt;code&gt;console.log&lt;/code&gt;, but this time instead of printing a string to the console, it pops it up in your face with one of those annoying pop up messages. Great for testing, but never &lt;em&gt;ever&lt;/em&gt; use them for a real site.&lt;/p&gt;

&lt;p&gt;So now that we have this function declared, we can update the &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element in &lt;code&gt;index.html&lt;/code&gt; to call the function whenever the button is click. We learned the syntax for calling the function, so the final thing we need to learn is how to connect them. We do that with the HTML &lt;code&gt;onclick&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;onclick&lt;/code&gt; attribute is available and most any elements in HTML, but for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility" rel="noopener noreferrer"&gt;accessibility&lt;/a&gt; reasons you want to aim to use it primarily on elements that are designed to be click (like buttons or links).&lt;/p&gt;

&lt;p&gt;We can tell our &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; in our &lt;code&gt;index.html&lt;/code&gt; file to run the function when it is clicked by updating it like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"likeButton()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Like&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, inside of the &lt;code&gt;onclick&lt;/code&gt; attribute we can technically write any Javascript code that we want. Even as much as you want (separated by semicolons) although that gets very messy very fast, and is considered bad practice. If you want a button to perform multiple tasks, put them all into a function and simply call that function.&lt;/p&gt;

&lt;p&gt;When we load our page and click the like button we are greeted with:&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%2Fi.imgur.com%2FxSlG3fN.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%2Fi.imgur.com%2FxSlG3fN.png" alt="Press Like Button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Excellent! Our page is interactive now. If your button does not work try some common troubleshooting tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verify your &lt;code&gt;script.js&lt;/code&gt; is being loaded in &lt;code&gt;index.html&lt;/code&gt; like &lt;code&gt;&amp;lt;script defer src="script.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Verify that you've saved all your files after editing them&lt;/li&gt;
&lt;li&gt;Check your spelling and case. Javascript is case sensitive so &lt;code&gt;onclick&lt;/code&gt; and &lt;code&gt;likeButton&lt;/code&gt; are very particular.&lt;/li&gt;
&lt;li&gt;Make sure you are calling the function: it's &lt;code&gt;onclick="likeButton()"&lt;/code&gt; and not &lt;code&gt;onclick="likeButton"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point we've verified that we can create a function, and call it by clicking a button. That's fantastic progress. The next step is to update the button to show it has been "liked".&lt;/p&gt;

&lt;p&gt;Here is the code for your &lt;code&gt;script.js&lt;/code&gt; file. Remove the old function and replace it with the following.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Adds 1 to the number of likes, and updates the text of the button&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;likeButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&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;var&lt;/span&gt; &lt;span class="nx"&gt;myButton&lt;/span&gt; &lt;span class="o"&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;myButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&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="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;likes&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;Let's break down each piece above to see what it does:&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;var&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a new variable named &lt;em&gt;likes&lt;/em&gt; that stores a number. This number keeps track of how many likes our animal picture has received so far. By default we will start at zero.&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;// Adds 1 to the number of likes, and updates the text of the button&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is something we haven't used yet, it's an extremely common part of programming called a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#comments" rel="noopener noreferrer"&gt;comment&lt;/a&gt;. They are used to provide information to other team members (or yourself in the future) looking at your code to help explain what the code does.&lt;/p&gt;

&lt;p&gt;You do &lt;strong&gt;not&lt;/strong&gt; need to add comments for every line, the vast majority of code (if you use descriptive variable names like &lt;code&gt;likes = 0&lt;/code&gt; rather than &lt;code&gt;x = 0&lt;/code&gt;) will be self-descriptive. Comments would only serve to add bloat. Reserve your comments for code that is less easy to understand fro ma quick glance, or to describe the entirely of what a function does as we have above.&lt;/p&gt;

&lt;p&gt;Comments are supported in HTML, Javascript and CSS. Each one uses a slightly different syntax:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML&lt;/strong&gt; &lt;code&gt;&amp;lt;!-- This is a comment --&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS&lt;/strong&gt; &lt;code&gt;/* This is a comment */&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Javascript&lt;/strong&gt; &lt;code&gt;// This is a one-line comment&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Javascript&lt;/strong&gt; &lt;code&gt;/* This is a comment that can span multiple lines */&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the real world most developers, particularly senior level developers, will actually spend more of their time &lt;em&gt;reading&lt;/em&gt; code than writing it, so good commenting and clean formatting are essential.&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;likeButton&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;This creates a function called &lt;code&gt;likeButton&lt;/code&gt;. The code inside the curly braces will not be run when the &lt;code&gt;.js&lt;/code&gt; file is loaded, but we can call the &lt;code&gt;likeButton()&lt;/code&gt; function at a later time to run the code when we choose.&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;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes out likes variable and increments it by one. THe new value is equal to the current value plus one. The first time the button is pressed it will become one (0 + 1). The second time two (1 + 1) etc.&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;var&lt;/span&gt; &lt;span class="nx"&gt;myButton&lt;/span&gt; &lt;span class="o"&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&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;As we learned in the introduction, &lt;code&gt;document.querySelect&lt;/code&gt; uses CSS selector syntax to search for elements on a page. This will save a reference to the first &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; it finds, so it's operating on the very fragile assumption that we only have one.&lt;/p&gt;

&lt;p&gt;If you were to add more buttons in the future you would need to return and refactor (update) this code. One option would be to add a class, say &lt;code&gt;&amp;lt;button class="like-button"&amp;gt;Like&amp;lt;/button&amp;gt;&lt;/code&gt;. You could then target that specific button with the CSS class selector like so: &lt;code&gt;document.querySelector(".like-button")&lt;/code&gt;. Notice the &lt;code&gt;.&lt;/code&gt; prefix indicating it's a class selector.&lt;/p&gt;

&lt;p&gt;For the moment however, the &lt;em&gt;Like&lt;/em&gt; button is our only button, and this code gets the job done just fine.&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;myButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&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="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final piece here is what updates the text inside the button itself. We update and replace the &lt;code&gt;innerText&lt;/code&gt; of the button with a thumbs up emoji, then we use the &lt;code&gt;+&lt;/code&gt; operator to &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Strings#concatenating_strings" rel="noopener noreferrer"&gt;concatenate&lt;/a&gt; the value of the likes variable onto the end of the string.&lt;/p&gt;

&lt;p&gt;This can be a bit tricky for newcomers as the &lt;code&gt;+&lt;/code&gt; operator is being used for something other than math. It depends on the &lt;em&gt;context&lt;/em&gt;. If you have two numbers on either side like &lt;code&gt;1 + 1&lt;/code&gt; then Javascript will evaluate that as a math operation and return a value of &lt;code&gt;2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If &lt;em&gt;either one&lt;/em&gt; of those values is a string (or both) then Javascript will instead treat them both like strings and concatenate them together. So &lt;code&gt;"hello" + 1&lt;/code&gt; would evaluate to &lt;code&gt;"hello1"&lt;/code&gt;. It's one of those fun &lt;a href="https://i.imgur.com/qJsWdJR.png" rel="noopener noreferrer"&gt;quirks&lt;/a&gt; of the language that becomes second nature after awhile, but it certainly does cause some confusion when first learning. The best way to become comfortable with it is simply repetition and practice.&lt;/p&gt;

&lt;p&gt;So for our example, if the button has been clicked once, then &lt;code&gt;"👍 " + likes&lt;/code&gt; will be the same as &lt;code&gt;"👍 " + 1&lt;/code&gt; which will be evaluated as &lt;code&gt;"👍 1"&lt;/code&gt; and that's the string that will be placed as the &lt;code&gt;innerText&lt;/code&gt; of our button.&lt;/p&gt;

&lt;p&gt;Of course we won't know until we try it out. Load the page with the updated Javascript, and start mashin' that like button!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Adds 1 to the number of likes, and updates the text of the button&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;likeButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&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;var&lt;/span&gt; &lt;span class="nx"&gt;myButton&lt;/span&gt; &lt;span class="o"&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;myButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&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="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FTA3XGF3.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%2Fi.imgur.com%2FTA3XGF3.png" alt="Like Button Complete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How many likes can you get to before your hand gets tired? Congratulations, you've created the world's most uninteresting game.&lt;/p&gt;




&lt;p&gt;At this point we will bring our discussion on Javascript to a close. We've only just scratched the surface of what's possible, but I hope you've got enough of an introduction and confidence to begin branching out and trying new things.&lt;/p&gt;

&lt;p&gt;Remember don't be afraid to mess around. Copy and paste from the internet. Come up with crazy ideas and try to build them. Keep it small to start so you don't get overwhelmed, but don't be afraid to fail.&lt;/p&gt;

&lt;p&gt;Javascript isn't something you just "learn" and then you're done. It's an ongoing process that will probably continue for your entire career. I've been writing Javascript for six years now, and I learned something new while writing this &lt;em&gt;complete beginner's tutorial&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The best thing you can do in your development journey is keep your mind constantly open to learning new things and improving.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning Javascript?
&lt;/h2&gt;

&lt;p&gt;Kyle Simpson's digital book series &lt;em&gt;You Don't Know JS&lt;/em&gt; is the gold standard for deep diving into learning all the ins and outs of the language. Highly recommend, and totally free to red online&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/getify/You-Dont-Know-JS" rel="noopener noreferrer"&gt;You Don't Know JS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Written by Douglas Crockford, creator of the JSON data format, this book distills all the important stuff about the Javascript language you need to know. This is the first book I ever read about JS, and I give it a lot of credit for helping teach me the fundamentals (ok I guess this one isn't free, but it's good):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742" rel="noopener noreferrer"&gt;Javascript: The Good Parts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a quick reference for all things JS, there is no better resource than:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=""&gt;https://javascript.info/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Node.js
&lt;/h3&gt;

&lt;h2&gt;
  
  
  What is Node.js
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; is a program that can run Javascript code outside of a browser.&lt;/p&gt;

&lt;p&gt;It is one of the main reasons why Javascript has become one of the most popular programming languages in the world.&lt;/p&gt;

&lt;p&gt;With Node, you are no longer restricted to requiring a web browser open to run your Javascript code. You can write Javascript for things like renaming photos on your computer, or sending automated emails, or even full blown desktop applications with tools like &lt;a href="https://www.electronjs.org/" rel="noopener noreferrer"&gt;Electon&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To try Node yourself, simply follow the instructions on the site and download and install it. Once installed you should be able to open a command line terminal and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And get an output like &lt;code&gt;v16.13.2&lt;/code&gt; depending on what the latest version is when you installed it.&lt;/p&gt;

&lt;p&gt;To you is you simply type &lt;code&gt;node&lt;/code&gt; followed by a Javascript file. Here's a simple example, I'll create a file called &lt;code&gt;script.js&lt;/code&gt; in the directory we are currently in:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello world!&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 save it and run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see "Hello world!" appear on your terminal.&lt;/p&gt;

&lt;p&gt;It's as simple as that. The applications just get bigger and more complex from there.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note that because your code isn't running in the browser, you will not have access to some of the common browser-specific APIs you might be familiar with. For example &lt;code&gt;document.querySelector&lt;/code&gt; which returns a DOM node -- something that doesn't make much sense without the context of a browser)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of the most common uses of Node.js is to build web servers. It's very popular because it allows you to write both your website (front-end) and web server (back-end) which provides the necessary data for the front-end both in Javascript.&lt;/p&gt;

&lt;p&gt;Although you can write your whole web server entirely with code specific to Node itself, to simplify the process most people use a library like &lt;a href="https://www.npmjs.com/package/express" rel="noopener noreferrer"&gt;Express&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning Node.js?
&lt;/h2&gt;

&lt;p&gt;There are tons of great resources on learning Node.js out there, and they're free!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction" rel="noopener noreferrer"&gt;MDN&lt;/a&gt; will introduce you to Node and cover building a simple web server with a tool called Express&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.theodinproject.com/paths/full-stack-javascript/courses/nodejs" rel="noopener noreferrer"&gt;The Odin Project&lt;/a&gt; full free curriculum for teaching Node.js and Express&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/playlist?list=PL4cUxeGkcC9jsz4LDYc6kv3ymONOKxwBU" rel="noopener noreferrer"&gt;Node.js Crash Course&lt;/a&gt; great YouTube video series on Node.js from The Net Ninja&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Command Line Terminal
&lt;/h1&gt;

&lt;p&gt;If you are going to be working in any kind of web development job, you're going to need to become familiar with the command line terminal. Many of the programs you will use don't have a graphical interface and are designed to be run on the terminal.&lt;/p&gt;

&lt;p&gt;Fortunately you don't need to be an expert, and this tutorial will go through the basic commands you need to know.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use the command line terminal?
&lt;/h2&gt;

&lt;p&gt;How you access the terminal will depend on your system. If you are on Mac or Linux it'll be called "Terminal", on Windows you might choose to use PowerShell which is very similar. PowerShell comes bundled with Windows automatically, you can find it in your start menu.&lt;/p&gt;

&lt;p&gt;Or you can download something like &lt;a href="https://git-scm.com/downloads" rel="noopener noreferrer"&gt;Git bash&lt;/a&gt; which comes included when you install Git and will give you a unix-style terminal even if you are using Windows.&lt;/p&gt;

&lt;p&gt;I'll be using &lt;a href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)" rel="noopener noreferrer"&gt;bash&lt;/a&gt; for this tutorial. Even if you are using PowerShell on Windows most of the commands will be the same or similar.&lt;/p&gt;

&lt;p&gt;When you open your terminal it will look something 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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654458840%2Fblogs%2Fintro-to-web-development%2Fterminal-example-1_wn8q7q.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654458840%2Fblogs%2Fintro-to-web-development%2Fterminal-example-1_wn8q7q.png" alt="Terminal Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most terminals will show the directory directory you are in on the left. Right now I am in the &lt;code&gt;~&lt;/code&gt; directory which is an alias for my "home" directory. On Windows it would be something like &lt;code&gt;c:\Users\YOUR_NAME&lt;/code&gt; on Linux it might be something like &lt;code&gt;/home/YOUR_NAME&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's create a new folder called &lt;code&gt;example-folder&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="nb"&gt;mkdir &lt;/span&gt;example-folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will create &lt;code&gt;example-folder&lt;/code&gt; in your home directory. Now let's "change directory" into that folder with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd example-folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Protip: use the &lt;code&gt;tab&lt;/code&gt; key to help autocomplete when working on the terminal. It's one of the most powerful shorthands you'll be able to use for efficiency (and avoiding spelling errors).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our terminal directory is now in the folder we just created. Let's create a file!&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;touch &lt;/span&gt;hello.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(This one will be different on PowerShell, you'll need to type &lt;code&gt;New-Item hello.txt&lt;/code&gt;).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654459345%2Fblogs%2Fintro-to-web-development%2Fterminal-example-2_icea7k.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1654459345%2Fblogs%2Fintro-to-web-development%2Fterminal-example-2_icea7k.png" alt="Terminal Example 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you navigate to that folder in your graphical interface you'll be able to see it has been created!&lt;/p&gt;

&lt;p&gt;Now let's go back to the terminal and take a look at the contents of this folder.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;That command means "list" and lists the contents of the directory. You should see your &lt;code&gt;hello.txt&lt;/code&gt; file show up.&lt;/p&gt;

&lt;p&gt;That's enough of that file, we can delete it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm &lt;/span&gt;hello.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;ls&lt;/code&gt; again and should be gone.&lt;/p&gt;

&lt;p&gt;Let's return to the parent 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;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two dots ".." is a shorthand for "parent directory" and a single dot "." is a shorthand for "this directory".&lt;/p&gt;

&lt;p&gt;Finally let's remove that folder we created.&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;rmdir &lt;/span&gt;example-folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's the absolute basics of navigating around on the command line. You're now at least equipped with the ability to navigate between folders which is one of the most common operations you will use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else do I need to know about the command line terminal?
&lt;/h2&gt;

&lt;p&gt;Make sure you understand the &lt;a href="http://www.differencebetween.net/technology/difference-between-absolute-and-relative-path/" rel="noopener noreferrer"&gt;difference between absolute and relative paths&lt;/a&gt;. This is not just for the command line, you'll need to understand the different when writing your code as well. You often need to import "modules" from other files and you need to describe to the editor where to find those files.&lt;/p&gt;

&lt;p&gt;Get familiar with one of the command line text editing tools so that you can quickly make changes to text and code files without having to boot up VS Code. I prefer &lt;a href="https://www.nano-editor.org/" rel="noopener noreferrer"&gt;Nano&lt;/a&gt; for quick edits but there are lots of options including emacs, vi, and more.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(If your terminal opens files in &lt;code&gt;vi&lt;/code&gt; and you can't figure out how to get out, type &lt;code&gt;escape&lt;/code&gt; then &lt;code&gt;:q&lt;/code&gt;. Quitting vi is one of those rights of initiation for anyone working in a terminal).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You'll want to know how to open up the help pages for any program you are using. Say you just installed &lt;code&gt;git&lt;/code&gt; but have no idea how to use it. Depending on your platform it will either be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;man git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OR&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git --help
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can replace &lt;code&gt;git&lt;/code&gt; with the name of whatever program you are trying to learn about. Usually one of the other will get you what you want. The &lt;code&gt;man&lt;/code&gt; command stands for "manual" and is intended to open up the manual.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning the command line terminal?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.theodinproject.com/lessons/foundations-command-line-basics" rel="noopener noreferrer"&gt;The Odin Project&lt;/a&gt; command line basics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jlevy/the-art-of-command-line#readme" rel="noopener noreferrer"&gt;The Art of the Command Line&lt;/a&gt; beginner's tutorial&lt;/p&gt;

&lt;p&gt;&lt;a href="https://files.fosswire.com/2007/08/fwunixref.pdf" rel="noopener noreferrer"&gt;Unix/Linux Command Cheatsheet&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Git
&lt;/h1&gt;

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

&lt;h2&gt;
  
  
  What is a Version Control System (VCS)?
&lt;/h2&gt;

&lt;p&gt;Having a good understanding of Git is critically important for working in almost any software job. I'd go so far as to say that if you company doesn't use it (or at least an equivalent version control tool) you may want to consider another position.&lt;/p&gt;

&lt;p&gt;It's &lt;em&gt;that&lt;/em&gt; important to a healthy software lifecycle. So for that reason I want to make sure I explain it well, because despite its important, it can be very daunting to learn and understand for a beginner who isn't used to thinking this way.&lt;/p&gt;

&lt;p&gt;Git is a &lt;em&gt;version control system&lt;/em&gt; which is a fancy way of saying that it's a tool for taking snapshots of data at a certain point in time.&lt;/p&gt;

&lt;p&gt;If you've ever worked on a file and made a copy of it called &lt;code&gt;Resume.doc&lt;/code&gt; and &lt;code&gt;Resume-backup.doc&lt;/code&gt; and &lt;code&gt;Resume-FINAL.doc&lt;/code&gt; etc then you can imagine why a tool like Git might need to exist.&lt;/p&gt;

&lt;p&gt;It works for any kind of file and is not specific to coding or software development, although that's where it's most commonly used.&lt;/p&gt;

&lt;p&gt;Software developers and teams use it for two primary purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;To create a saved state at a certain point in time in case an issue comes up later and changes need to be reverted back to how they used to be, for one file or many files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To allow multiple developers to work on files in a project at the same time, in the same directory and often even the same file. Git keeps track of who is making changes where, and helps you resolve and merge those changes together, ideally automatically without any input from the people making the changes at all.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, if you have a big Javascript file called &lt;code&gt;my-code.js&lt;/code&gt; with 1000 lines, developer A could make edits to line 200, and developer B could make edits to line 300. Afterward they would perform a Git command called &lt;code&gt;merge&lt;/code&gt; and Git would take care of combining the separate changes both devs made on their lines on their individual files into a single file with both changes.&lt;/p&gt;

&lt;p&gt;There are a number of ways to use Git, the most common is through the command line terminal but there are many tools out there designed to make it easier to use. See &lt;a href="https://dev.towhat-are-the-best-free-resources-for-learning-git"&gt;this section&lt;/a&gt; for more info.&lt;/p&gt;

&lt;p&gt;Let's take a quick look at how you can use Git&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use Git?
&lt;/h2&gt;

&lt;p&gt;First you need to install it on your machine. Check out &lt;a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git" rel="noopener noreferrer"&gt;this link&lt;/a&gt; for instructions on how to install depending on what operating system you are on.&lt;/p&gt;

&lt;p&gt;You will know you are successful when you are able to open a command line terminal and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see a response like &lt;code&gt;git version 2.35.1&lt;/code&gt; or whatever version is currently the newest when you install yours. If it says anything like &lt;code&gt;command "git" not found&lt;/code&gt; then you need to double check your installation. Sometimes you need to close and re-open your terminal for newly installed programs to be visible.&lt;/p&gt;

&lt;p&gt;Now I am going to create a new folder. You can create it anywhere that you like as long as you know how to navigate to it in your terminal. You can make it with the &lt;code&gt;mkdir git-example&lt;/code&gt; command or you can just "Create New Folder" with your mouse and call it &lt;code&gt;git-example&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657417444%2Fblogs%2Fintro-to-web-development%2Fgit-example-1_ixxc25.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657417444%2Fblogs%2Fintro-to-web-development%2Fgit-example-1_ixxc25.png" alt="Git Example 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the folder is created open up your editor (I'll be using VS Code) and go &lt;code&gt;File -&amp;gt; Open Folder&lt;/code&gt; and find that folder you just created.&lt;/p&gt;

&lt;p&gt;You can see I have my VS Code terminal open there, it will automatically navigate you to the folder you have open. To open your terminal you can use &lt;code&gt;ctrl + ~&lt;/code&gt; or simply use the menu with &lt;code&gt;View -&amp;gt; Terminal&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Just before we get started you'll want to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global init.defaultBranch main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are on a newer version of git the default branch will already be named &lt;code&gt;main&lt;/code&gt;, but if you are on an older version it will be called &lt;code&gt;master&lt;/code&gt;. This command just makes sure that your defaults match what we will be using for this tutorial.&lt;/p&gt;

&lt;p&gt;The first command you will always need to use if you are creating a new "repository" (the name for a collection of folders and files tracked by the git program). The command is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will receive a message that says &lt;code&gt;Initialized empty Git repository in...&lt;/code&gt; with your folder path. That means &lt;code&gt;git-example&lt;/code&gt; directory is now a git repository. Any files or folders created within that directory can be tracked as part of your "project".&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that if you join an existing project/team, you will not need to initialize Git. When you &lt;code&gt;clone&lt;/code&gt; a copy of their work it will already have been initialized for you, we only need to &lt;code&gt;git init&lt;/code&gt; when we are creating a new project ourselves from scratch.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now let's create a new file called &lt;code&gt;sample.txt&lt;/code&gt;. To create a new file in VS Code simply right click on the left side under &lt;code&gt;git-example&lt;/code&gt; and &lt;code&gt;New File&lt;/code&gt;. Inside it I'm going to add some text, quite literally the phrase &lt;em&gt;"Some example text"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now I will introduce you to a couple of the first git commands you should learn, &lt;code&gt;git add&lt;/code&gt; and &lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;git add&lt;/code&gt;: Will tell git to add new files to "track" in your project. Presuming that you want to keep track of every file in the directory (this is very common) then you can simply use the &lt;code&gt;.&lt;/code&gt; character which in most terminals is a shorthand for "this directory". So &lt;code&gt;git add .&lt;/code&gt; means "add all files in this directory to my git project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;git commit&lt;/code&gt;: Will tell git that you want to save a snapshot of all tracked files at this current moment. Most commonly you will also include the &lt;code&gt;-m&lt;/code&gt; flag which means "message". A commit message is a description of the changes you have made since the last time you committed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;(Worth noting that you can create a file called &lt;code&gt;.gitignore&lt;/code&gt; in the root directory of your project and put the names of any files and directories you &lt;strong&gt;don't&lt;/strong&gt; want to include in your repository, so even if you run the &lt;strong&gt;add .&lt;/strong&gt; command those files will not get added. Useful if you have things like environment files that contain secrets and passwords you don't want to upload publicly with the rest of your code)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With that new knowledge in mind our commands will be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .
git commit -m 'initial commit'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657418180%2Fblogs%2Fintro-to-web-development%2Fgit-example-2_gap2pt.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657418180%2Fblogs%2Fintro-to-web-development%2Fgit-example-2_gap2pt.png" alt="Git Example 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might be able to come up with a better message than that, though it's a common one for the first commit on a project. The common standard for commit message is to write your message as if it follows the start of the sentence &lt;em&gt;"When applied, this commit will..."&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So an example would be "change the primary button colour to blue". So that is the format you should use rather than something like "I changed the primary button to blue". Consistent subject and tense makes commit messages in large projects much easier to read and understand.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(If you want to get really deep down the rabbit hole, you can encourage your team to adopt something like &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;conventional commits&lt;/a&gt; which applies strict rules about how commit messages are written.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So now that you have created your first commit, let's learn how to create another one, and navigate back and forth through time and change the state of our project.&lt;/p&gt;

&lt;p&gt;Add another line to your &lt;code&gt;sample.txt&lt;/code&gt; file. Something like &lt;em&gt;"Some more text"&lt;/em&gt; on the next line below the first line. Doesn't matter what the text says, we just want to update the file.&lt;/p&gt;

&lt;p&gt;Now run these commands again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .
git commit -m 'add a new line of text'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically the &lt;code&gt;git add&lt;/code&gt; in this scenario does nothing since we didn't create any new files, but it's not a bad habit to get into as normally creating new files in projects is common, and you want to make sure you add them unless they are being explicitly excluded.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657418555%2Fblogs%2Fintro-to-web-development%2Fgit-example-3_xs8tcn.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657418555%2Fblogs%2Fintro-to-web-development%2Fgit-example-3_xs8tcn.png" alt="Git Example 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you have two commits, and two "saved" states of your project, you can go back to one if you need to. Let's say that you just want to "see" how things were before, but not actually lose your newest changes.&lt;/p&gt;

&lt;p&gt;Start with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If will show you a list of all your commits, with their messages, and a unique string character hash (purple arrow points to in image below) that you can use as an identifier. Note that yours will not be the same as mine, they are randomly generated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657419127%2Fblogs%2Fintro-to-web-development%2Fgit-example-4_lxtc5v.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657419127%2Fblogs%2Fintro-to-web-development%2Fgit-example-4_lxtc5v.png" alt="Git Example 4"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To go back to that state simply type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout YOUR_COMMIT_HASH_HERE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So in my case it would be &lt;code&gt;git checkout c849819c6f45ef72429abc36b1ee3891c3ede779&lt;/code&gt; but that value will be different for you.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657419270%2Fblogs%2Fintro-to-web-development%2Fgit-example-5_dc4ywm.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657419270%2Fblogs%2Fintro-to-web-development%2Fgit-example-5_dc4ywm.png" alt="Git Example 5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This brings us back to the first commit we did, notice that the content of your &lt;code&gt;sample.txt&lt;/code&gt; doesn't have the second line you added. It's not gone, we are simply looking at a different state of the project in the timeline.&lt;/p&gt;

&lt;p&gt;At any point you wish to return to the most up to date state just use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this context &lt;code&gt;main&lt;/code&gt; is the name of the branch you are on. If you have been following this tutorial you will have set your default branch to &lt;code&gt;main&lt;/code&gt; at the start. You can always double check what branch you are currently on by typing &lt;code&gt;git status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Branching is a critically important part of git. The idea of branching is that you create a separate place to track changes, outside of the &lt;code&gt;main&lt;/code&gt; branch that acts as the central source of truth for your project. For example, whenever you release a new version of your website or app, that release is almost always done off main.&lt;/p&gt;

&lt;p&gt;If you are working on a new feature on a separate branch, those changes won't be released when the &lt;code&gt;main&lt;/code&gt; branch is released. Only when you &lt;code&gt;merge&lt;/code&gt; the changes from your branch into &lt;code&gt;main&lt;/code&gt; will those changes actually be included in the main product.&lt;/p&gt;

&lt;p&gt;I'm not going to get into branching for this tutorial, but make sure that you are at least familiar with it before you apply for your first role. You can learn more about git branching &lt;a href="https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So at this stage, if you have learned the basics of &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;commit&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt; and &lt;code&gt;checkout&lt;/code&gt; (to switch between branches).&lt;/p&gt;

&lt;p&gt;That covers most of the fundamentals you need to know to work with git locally as a solo developer.&lt;/p&gt;

&lt;p&gt;But as you've probably heard, git is also used to track changes in a project between developers working on different machines. How does it do that? Well that's where additional tools like &lt;em&gt;Github&lt;/em&gt; come into play.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the difference between Git and Github?
&lt;/h2&gt;

&lt;p&gt;A common source of confusion for new developers is the difference between &lt;em&gt;git&lt;/em&gt; and &lt;em&gt;Github&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Git&lt;/strong&gt; is a free open source program that runs on your computer and helps keep track of file changes within a project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Github&lt;/strong&gt; is a website owned and operated my Microsoft that hosts git repositories online so that you can have access to your files wherever you go and share them with other developers. Think of it like Dropbox with a bunch of extra features specifically designed around working with git repositories.&lt;/p&gt;

&lt;p&gt;Github will always have a "copy" of your Git repository and whenever you like you can use git commands like &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;pull&lt;/code&gt; to synchronize changes you've done on your computer with the ones hosted on Github.&lt;/p&gt;

&lt;p&gt;If you are working by yourself it can simply act as a backup system, and help you track issues and to-do's within your project.&lt;/p&gt;

&lt;p&gt;If you are working with other developers then it will act as the central location where all changes made by all team members are pushed to and synchronized.&lt;/p&gt;

&lt;p&gt;Let's show an example of working with a repository on Github. I'm going to create one locally and show you how to move it up to Github from the command line so that other developers can download or even contribute code to it.&lt;/p&gt;

&lt;p&gt;First I am going to make a new project from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir example-git-project
cd example-git-project
git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I am going to copy the files I created for the tutorials we did on HTML, CSS and Javascript.&lt;/p&gt;

&lt;p&gt;If you did not complete those tutorials, don't worry, you don't actually have to understand HTMl, CSS or Javascript for this. We're not even going to run that code, we are simply trying to save a copy of it remotely where other devs can view it.&lt;/p&gt;

&lt;p&gt;You can copy the three files directly from the Simple Website Template section.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Don't worry about what they do, that's not the focus of this tutorial, we are simply trying to show how to push those files to your remote repository.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After adding those files, run these commands to add them and make your first commit for this project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .
git commit -m 'first commit'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When complete your &lt;code&gt;example-git-project&lt;/code&gt; directory should look 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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657422104%2Fblogs%2Fintro-to-web-development%2Fgit-example-6_tx8owy.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657422104%2Fblogs%2Fintro-to-web-development%2Fgit-example-6_tx8owy.png" alt="Git Example 6"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we are ready to move this project up to Github.&lt;/p&gt;

&lt;p&gt;If you don't already have a Github account, create one now.&lt;/p&gt;

&lt;p&gt;Once you have an account and are logged in, navigate to &lt;em&gt;"Your repositories"&lt;/em&gt; and then look for the green "&lt;em&gt;New"&lt;/em&gt; button to create a new repository.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657422312%2Fblogs%2Fintro-to-web-development%2Fgit-example-7_zo6w3q.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657422312%2Fblogs%2Fintro-to-web-development%2Fgit-example-7_zo6w3q.png" alt="Git Example 7"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a project following this basic template, give it a name and a description. The name does not have to match the same folder name you used when you created your local repository, but it helps if you want to avoid confusion between the two.&lt;/p&gt;

&lt;p&gt;Make sure it is set to &lt;em&gt;public&lt;/em&gt; if you want other people to be able to view and contribute to the code.&lt;/p&gt;

&lt;p&gt;Once it is created you will get a screen that looks like the below. It will include all the commands that you need, the only difference will be that they will use your Github username rather than mine that you see in the screenshot:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657422468%2Fblogs%2Fintro-to-web-development%2Fgit-example-8_qx1nzl.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657422468%2Fblogs%2Fintro-to-web-development%2Fgit-example-8_qx1nzl.png" alt="Git Example 8"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the commands you need are now visible on the screen for you. We would like to push the repository we created on our computer to this remote repository.&lt;/p&gt;

&lt;p&gt;The first step is to tell git on our machine that this repository we created is the &lt;em&gt;remote&lt;/em&gt; version of our repository. To do that we run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add origin YOUR_REPOSITORY_URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command tells git to create a new remote with the name &lt;code&gt;origin&lt;/code&gt;. The URL that you use will depend on how you have Github setup. You can use either an HTTPS or an SSH URL. SSH is normally preferred but you will likely want to go through the What is SSH section first to set it up if you are not familiar.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(The long and short of it is that HTTPS will require you to enter your username and password every time you interact with the Github repository. Setting up SSH means you don't need to do that because the auth key will exist on your machine and be provided automatically.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you have added the remote repository you can confirm it is correct with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote get-url origin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657422773%2Fblogs%2Fintro-to-web-development%2Fgit-example-9_xy52pa.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657422773%2Fblogs%2Fintro-to-web-development%2Fgit-example-9_xy52pa.png" alt="Git Example 9"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the highlighted text in the above example that the origin is correct for the repository I just created.&lt;/p&gt;

&lt;p&gt;With that complete you are ready to upload your code. To do that we use the &lt;code&gt;git push&lt;/code&gt; command. Push says to "push the current state of my local repository to a remote one."&lt;/p&gt;

&lt;p&gt;The first time you do this to a new repository you have to state what remote branch you want to push your current local branch to. In almost all cases this is simply a remote branch with the same name. The command looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;-u&lt;/code&gt; stands for &lt;em&gt;upstream&lt;/em&gt;. In this example we are on the main branch, but if you were working for another branch called &lt;code&gt;cool-feature&lt;/code&gt; for example, the command would instead be &lt;code&gt;git push -u origin cool-feature&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You only need to do this once, from now on just typing &lt;code&gt;git push&lt;/code&gt; will default to pushing to the same upstream branch unless you change it.&lt;/p&gt;

&lt;p&gt;Once this push command has been run you should see some upload status messages in your command line, and when you next refresh your Github repository URL it will look 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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657423004%2Fblogs%2Fintro-to-web-development%2Fgit-example-10_osymsj.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657423004%2Fblogs%2Fintro-to-web-development%2Fgit-example-10_osymsj.png" alt="Git Example 10"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seeing this indicates you have successfully made your first Github push. Congratulations!&lt;/p&gt;

&lt;p&gt;You can now share your Github URL with other people (or even yourself on other machines) and they can instantly get a copy of this project.&lt;/p&gt;

&lt;p&gt;Feel free to try it yourself. CLick the green &lt;em&gt;"code"&lt;/em&gt; button and then copy the repository URL from there. Create a totally branch new directory anywhere on your machine and run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone YOUR_GITHUB_URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;YOUR_GITHUB_URL&lt;/code&gt; is the URL of your repository. In my case it's &lt;code&gt;git clone git@github.com:alexeagleson/example-git-project.git&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When the command finishes you will have an exact copy of your repo with all the files you added and committed in this new directory elsewhere on your machine. You can make changes and commit them to update the remote repo with the &lt;code&gt;git add&lt;/code&gt;, &lt;code&gt;git commit&lt;/code&gt; and &lt;code&gt;git push&lt;/code&gt; commands same as always.&lt;/p&gt;

&lt;p&gt;This applies to other developers on other machines as well!&lt;/p&gt;

&lt;p&gt;There's certainly more to learn, but just having these basics down will position you very strongly for using git effectively with any large project at your company.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else do I need to know about Git?
&lt;/h2&gt;

&lt;p&gt;Important topics you should make sure to learn about include:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell" rel="noopener noreferrer"&gt;Branching&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes" rel="noopener noreferrer"&gt;Working With Remote Repositories&lt;/a&gt; like Github for example&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging" rel="noopener noreferrer"&gt;Merging&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning Git?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/book/en/v2" rel="noopener noreferrer"&gt;The Git Book&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.theodinproject.com/paths/foundations/courses/foundations#git-basics" rel="noopener noreferrer"&gt;The Odin Project&lt;/a&gt; curriculum on Git basics&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learngitbranching.js.org/" rel="noopener noreferrer"&gt;Learn Git Branching&lt;/a&gt; is a little interactive game that is great for teaching you more about the concept of branching&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ohmygit.org/" rel="noopener noreferrer"&gt;Oh my Git!&lt;/a&gt; an open-source game designed to help people learn git.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.github.com/en/get-started/quickstart/hello-world" rel="noopener noreferrer"&gt;Github documentation&lt;/a&gt; will teach you how to use git and Github at the same time.&lt;/p&gt;

&lt;h1&gt;
  
  
  APIs
&lt;/h1&gt;

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

&lt;p&gt;API stands for &lt;em&gt;application programming interface&lt;/em&gt; and (in context of web development) it has become basically a catch all term for any system that your code communicates with outside of the code.&lt;/p&gt;

&lt;p&gt;The reason that we need an API is because we never want to gives users direct access to your data. Imagine you had a social network that displayed things like name, age, etc about your users.&lt;/p&gt;

&lt;p&gt;If you let browsers request that raw data directly, they could also choose to display things like password, or credit card numbers, or any other sensitive data that your app might have stored for one reason or another.&lt;/p&gt;

&lt;p&gt;Those are extreme examples but the fact is that even if something isn't critically sensitive, most of the time we want to protect our data and only share it with those people who should have access to it.&lt;/p&gt;

&lt;p&gt;For that reason we create APIs. I will allow my web server direct access to all my data, and then the app that is running in the browser may "request" some of that data. My web server will decide if the app / user requesting it should have access to that data, and return it if so, or return an error if not.&lt;/p&gt;

&lt;p&gt;A front-end developer needs to know how to &lt;em&gt;read&lt;/em&gt; from an existing API. That might mean one developed by back-end developers on their team at their company, or even publicly available ones on the internet.&lt;/p&gt;

&lt;p&gt;There are many public APIs out there you can start working with when building an app. Some popular ones include the &lt;a href="https://openweathermap.org/api" rel="noopener noreferrer"&gt;open weather API&lt;/a&gt;, the &lt;a href="https://pokeapi.co/" rel="noopener noreferrer"&gt;PokeAPI&lt;/a&gt;, and the &lt;a href="https://www.thecocktaildb.com/api.php" rel="noopener noreferrer"&gt;cocktail API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These services allow you to query data and display it in your app. Regardless of what type you are working with you usually need to &lt;em&gt;authenticate&lt;/em&gt; yourself to use them due to the fact that internet bandwidth is not free, so every time you query for data there is a cost associated with that being paid by whoever is hosting the API. (Most of them do offer free tiers for low traffic apps though.)&lt;/p&gt;

&lt;p&gt;If you are a back-end developer you will be responsible for &lt;em&gt;creating&lt;/em&gt; the APIs. This means you will write the code for them in a language like Javascript, or other common back-end languages like C#, Java, Go, Python, or Rust.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I create an API?
&lt;/h2&gt;

&lt;p&gt;You can create an API very easily with just Javascript and NodeJS. Make sure you have read those sections and are familiar with those tools first.&lt;/p&gt;

&lt;p&gt;Open up VS Code and start a new blank project. Create a single file called &lt;code&gt;my-api.js&lt;/code&gt; with the following contents:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;my-api.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&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;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8000&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;requestHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &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="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;setHeader&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weatherData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;toronto&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;humidityPercent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weatherDataString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weatherData&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;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weatherDataString&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;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;server&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;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Listening at http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&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;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first line loads the built-in &lt;a href="https://nodejs.org/api/http.html" rel="noopener noreferrer"&gt;HTTP module in Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next we define variables to set the &lt;code&gt;host&lt;/code&gt; and &lt;code&gt;port&lt;/code&gt; that our server will run on.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;requestHandler&lt;/code&gt; is a function which is designed to take two arguments, variables that represent the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview#http_messages" rel="noopener noreferrer"&gt;request and response of an HTTP message&lt;/a&gt;. The values in these variables are populated by the Node HTTP module whenever requests are made to your server.&lt;/p&gt;

&lt;p&gt;Inside the function we call built in Node HTTP methods like &lt;code&gt;setHeader&lt;/code&gt; and &lt;code&gt;writeHead&lt;/code&gt; to begin crafting the response and HTTP status codes.&lt;/p&gt;

&lt;p&gt;If you do not understand these concepts please take the time to read up on web servers.&lt;/p&gt;

&lt;p&gt;Next we save some imaginary API data into the &lt;code&gt;weatherData&lt;/code&gt; variable. In a real API this data was likely fetched from a database which itself was populated by data from some kind of hardware device like a digital thermometer. Web servers are not an appropriate place to &lt;em&gt;store&lt;/em&gt; data since all data is lost when they are rebooted or shut down, hence why we need databases.&lt;/p&gt;

&lt;p&gt;For our simple example though we are just creating some dummy data as an example. This data represents an imaginary weather server response from someone who has made a request to our server for the current weather in Toronto, Ontario, Canada.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;weatherData&lt;/code&gt; object is then converted into a string so that it can be sent over the network. &lt;code&gt;weatherDataString&lt;/code&gt; is converted into &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/JSON" rel="noopener noreferrer"&gt;JSON&lt;/a&gt;, a textual string representation based on Javascript objects (hence the name).&lt;/p&gt;

&lt;p&gt;Since it's just text, it does not technically require Javascript to use, any language can output data in JSON format. You can convert a Javascript object to a JSON string with the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify" rel="noopener noreferrer"&gt;JSON.stringify()&lt;/a&gt; function.&lt;/p&gt;

&lt;p&gt;Finally the &lt;code&gt;end&lt;/code&gt; method is what we call when we are done settings the headers and ready to return the data to the device which is making the request to our API.&lt;/p&gt;

&lt;p&gt;Let's give it a try!&lt;/p&gt;

&lt;p&gt;Save your &lt;code&gt;my-api.js&lt;/code&gt; file and open the command line terminal in the same directory as your &lt;code&gt;.js&lt;/code&gt; file and run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node my-api.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the output &lt;code&gt;Listening at http://localhost:8000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open up your browser and go to [&lt;a href="http://localhost:8000" rel="noopener noreferrer"&gt;http://localhost:8000&lt;/a&gt;] to get a response that looks like:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1662314320%2Fblogs%2Fintro-to-web-development%2Fapi_bbc4qs.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1662314320%2Fblogs%2Fintro-to-web-development%2Fapi_bbc4qs.png" alt="API Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depending on your browser it may look slightly different since different ones format JSON responses in different ways, but either way, there you have it!&lt;/p&gt;

&lt;p&gt;Remember that the primary purpose of most APIs is to send raw data so websites and web apps can be built using that data. Rather than actually displaying it raw like we do here your app would realistically query that URL using Javascript with something like the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch" rel="noopener noreferrer"&gt;fetch method&lt;/a&gt; and then display it on the screen wrapped in some pretty HTML and CSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning APIs?
&lt;/h2&gt;

&lt;p&gt;If you simply want to learn about the concept of APIs, why they are needed and how they are designed here's a fantastic &lt;a href="https://stackoverflow.com/questions/671118/what-is-restful-programming" rel="noopener noreferrer"&gt;Stack Overflow response and discussion&lt;/a&gt; on the topic that covers all the fundamentals.&lt;/p&gt;

&lt;p&gt;For more information of building your own API (at least from a Javascript perspective) check out the resources listed in What are the best free resources for learning Node.js?&lt;/p&gt;

&lt;h1&gt;
  
  
  Libraries and Package Management
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What is a library?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What is a package?
&lt;/h2&gt;

&lt;p&gt;In the context of web development, a library (also sometimes called a package, or even a framework in different contexts) is typically used to refer to &lt;em&gt;"someone else's Javascript code"&lt;/em&gt; that you download from the internet and add to your code.&lt;/p&gt;

&lt;p&gt;Libraries are a necessary and fundamental part of building websites and web applications. Without them it would require us to re-write the same basic code over and over again each time we start a new project.&lt;/p&gt;

&lt;p&gt;To give a very simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"p-tag"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;hello world&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pTag&lt;/span&gt; &lt;span class="o"&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="s2"&gt;p-tag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;pTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pTag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example we are loading the popular &lt;a href="https://lodash.com/" rel="noopener noreferrer"&gt;lodash&lt;/a&gt; Javascript library from a CDN inside the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;That loads all the Javascript code from that library. Lodash (hence the name) stores its functions on a variable whose name is just the underscore character.&lt;/p&gt;

&lt;p&gt;We then use Javascript to grab the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; element by its ID and replace its lowercase "hello world" text with the return value of Lodash's &lt;code&gt;startCase&lt;/code&gt; function. The &lt;code&gt;startCase&lt;/code&gt; function transforms any string so the first letter of each world is capitalized.&lt;/p&gt;

&lt;p&gt;There is no built-in Javascript function which does this (only all lowercase or uppercase) so either we write one ourselves, or simply add this library to do it for us.&lt;/p&gt;

&lt;p&gt;Of course there are many other considerations you need to be aware of, this whole library for example has a lot more code in it than just the &lt;code&gt;startCase&lt;/code&gt; function so it might slow your websites average load time down.&lt;/p&gt;

&lt;p&gt;Everything in web development is a trade-off so you and your team always need to consider the pros and cons when making a decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a package manager?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What are NPM and Yarn?
&lt;/h2&gt;

&lt;p&gt;NPM is something called a "package manager" and it's a tool that is automatically installed on your system when you install Node.js.&lt;/p&gt;

&lt;p&gt;Make sure you don't confuse NPM the tool (which you run on your command like like &lt;code&gt;npm install PACKAGE_NAME&lt;/code&gt;) and NPM the online repository that stores those packages which you can explore at &lt;a href=""&gt;https://www.npmjs.com/&lt;/a&gt;. They both have the same name, but can mean one or the other depending on context you are talking in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://yarnpkg.com/" rel="noopener noreferrer"&gt;Yarn&lt;/a&gt; is an alternative to NPM you can install on your system which works very similarly. For a beginner you will not notice any difference between Yarn and NPM, so I would only recommend you try it if you are curious, or if your project/company is using it.&lt;/p&gt;

&lt;p&gt;You can create a branch new NPM project in an folder with this command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;After the project has been initialized you will see a &lt;code&gt;package.json&lt;/code&gt; file which describes all the libraries and packages your project has access to. You can add a new one anytime from the command line like so:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;PACKAGE_NAME&lt;/code&gt; is the name of the package listed on &lt;a href=""&gt;https://www.npmjs.com/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You would learn what functions are available to use from the library in the example above) typically by reading the library's documentation.&lt;/p&gt;

&lt;p&gt;That documentation may exist right on the NPM page, or it might be on the Github source code for the project, or most commonly at the project's official website.&lt;/p&gt;

&lt;p&gt;Here's an example of the &lt;a href="https://api.jquery.com/" rel="noopener noreferrer"&gt;API documentation for the jQuery library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's take a look at a practical example using the &lt;code&gt;lodash&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;Create a new folder in the terminal, navigate to it and run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init

npm &lt;span class="nb"&gt;install &lt;/span&gt;lodash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember you can replace &lt;code&gt;lodash&lt;/code&gt; with any other library you find on the &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;NPM registry&lt;/a&gt;. That is the source for Javascript packages, and after running the &lt;code&gt;npm install&lt;/code&gt; command you will be able to use them in your code as follows if you create a fill called &lt;code&gt;script.js&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash&lt;/span&gt;&lt;span class="dl"&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello world&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;The above will print the start-case'd "Hello World" to the console when you run &lt;code&gt;node script.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Remember that libraries available on NPM are public and free to use, so don't hesitate to play and experiment!&lt;/p&gt;

&lt;h1&gt;
  
  
  Databases
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What is a database?
&lt;/h2&gt;

&lt;p&gt;In the context of web development, a database is simply the location where your website or web app will store its data. Basically a fancy hard drive that is accessible over the internet.&lt;/p&gt;

&lt;p&gt;The main difference between and standard hard drive and a database is that a database assumes you will be accessing data constantly and will be optimized to provide ways to search for that data extremely quickly.&lt;/p&gt;

&lt;p&gt;A database uses a concept called &lt;em&gt;indexes&lt;/em&gt; which are exactly like you would expect if you're familiar with the index of a large book, a list of terms or keys that it creates to identify the exact location of information based on certain criteria (an index on text data might be &lt;em&gt;alphabetical&lt;/em&gt; for example).&lt;/p&gt;

&lt;p&gt;Databases used on the web are usually classified into one of two categories: relational and non-relational (also often called SQL and NoSQL).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(SQL stands for "structured query language" and is usually pronounced as "sequel", but some people prefer S-Q-L.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some examples of popular relational databases are &lt;em&gt;MySQL, PostgreSQL, and Microsoft SQL Server&lt;/em&gt;. An example of a popular NoSQL database is &lt;em&gt;MongoDB&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you are just learning then deciding which one to use and learn makes little difference, either option will introduce you at least to the fundamentals of working with databases including &lt;em&gt;indexes, schemas, creates, reads, updates, and deletes&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Typically the responsibility for working with databases will fall on the back-end developer. The front-end developer will have little to no direct exposure to the database.&lt;/p&gt;

&lt;p&gt;The backend developer will be responsible for creating an &lt;em&gt;API&lt;/em&gt; (see also What is an API?), which is basically code that reads information from the database and transforms it into a shape that the front-end client can use.&lt;/p&gt;

&lt;p&gt;If your back-end is written in Javascript, then the developer would write Javascript code that uses an &lt;a href="https://www.npmjs.com/package/mysql" rel="noopener noreferrer"&gt;NPM package that gives them access to the database&lt;/a&gt; and write SQL queries that are sent to Javascript functions and then onward to the database.&lt;/p&gt;

&lt;p&gt;Let's say that you want to build a page that shows current in-stock levels for a website that sells plants.&lt;/p&gt;

&lt;p&gt;In your database you have a &lt;em&gt;table&lt;/em&gt; which contains both the name of each plant your store carries and the number that are in stock.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(If you've used Microsoft Excel or Google Sheets before then you can think of a database as very similar, just significantly more powerful and able to store and process orders of magnitude more data.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Typically in a real relational database the items and stock levels would be in separate tables and marked with an ID number, a process called normalization, but we are keeping it simple for now)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A SQL query to get plant name and inventory information for plants that are &lt;strong&gt;&lt;em&gt;currently in-stock&lt;/em&gt;&lt;/strong&gt; might look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_in_stock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;plants&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;num_in_stock&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;plants&lt;/code&gt; is the name of the table and &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;num_in_stock&lt;/code&gt; are the names of the columns that contain the data inventory data.&lt;/p&gt;

&lt;p&gt;Once this data is returned the back-end developer writes more code to provide an API &lt;em&gt;endpoint&lt;/em&gt; that the website can send requests to in order to get that plant inventory data and display it on the page.&lt;/p&gt;

&lt;p&gt;An &lt;em&gt;endpoint&lt;/em&gt; is simply an URL identifier designed to provide specific data, for example &lt;code&gt;https://www.myplantstore.com/inventory&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's important to understand that the website itself cannot query the database directly, because to do so would require you to include the login and password of your database on the website, which would then be accessible to everyone. It wouldn't long for someone (or some bot) to gain access and control of your database.&lt;/p&gt;

&lt;p&gt;So one of the reasons we create and use an API is to provide a very specific interface via URL that only allows data to be requested from certain trusted sources, and is only programmed to return specific types of data.&lt;/p&gt;

&lt;p&gt;Maybe we also store customer names and addresses in the database, but as long as we don't write code on our back-end to query that data and provide an interface for it to be accessed, then it will be safe as long as nobody (except those with permission) have direct access to the database.&lt;/p&gt;

&lt;p&gt;Ultimately all you need to remember as a front-end developer is that a database is a place to permanently store data for your web app, and the back-end developer is responsible for providing you (the front-end dev) access to specific parts of it that you need in order to build your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use a database?
&lt;/h2&gt;

&lt;p&gt;This question can be interpreted in a few different ways. Someone working as a DBA (database administrator) would interpret this question as &lt;em&gt;How do I install and setup a database?&lt;/em&gt; likely including follow up questions like &lt;em&gt;what kind of data will I need to store?&lt;/em&gt;, &lt;em&gt;should it be SQL or NoSQL?&lt;/em&gt;, &lt;em&gt;how much data and traffic am I expecting?&lt;/em&gt; etc etc etc.&lt;/p&gt;

&lt;p&gt;As a back-end developer you might &lt;em&gt;may or may not&lt;/em&gt; need to include yourself in these discussions. Usually it depends on the size of the company. In small companies back-end developers often find themselves playing the role of the DBA as well as developing the API. At large companies that is less likely to be the case.&lt;/p&gt;

&lt;p&gt;The way we are going to answer this question is specifically on the software development side since that is the focus of this tutorial. In most cases a database will already be set up for you, and your job will be to develop an API that can query it, maybe process the data a bit, and then return it to the user (usually front-end dev) in a shape that aligns with their needs to display it on a page to the user.&lt;/p&gt;

&lt;p&gt;For our example we will be using a fantastic and user friendly SQL database which is totally free called &lt;a href="https://www.sqlite.org/index.html" rel="noopener noreferrer"&gt;SQLite&lt;/a&gt;. All the basic queries you would use for managing data in SQLite like &lt;em&gt;SELECT&lt;/em&gt;, &lt;em&gt;INSERT&lt;/em&gt;, &lt;em&gt;CREATE TABLE&lt;/em&gt; etc are the same as you would use when working in all the industry standard SQL databases like MySQL, PostgreSQL etc.&lt;/p&gt;

&lt;p&gt;SQLite has bindings for Node.js, which is a fancy way of saying your can just install it as an NPM package and get up and running in seconds.&lt;/p&gt;

&lt;p&gt;We can create our SQLite database in one of two ways: either create it right in the code when the program loads (called doing it "in memory") or load up the database from a file on your computer.&lt;/p&gt;

&lt;p&gt;Loading from a file mimics a real world use case a little closer, but requires some more configuration so we'll be doing it in memory in this example. If you want to learn how to load the database from a file here's a &lt;a href="https://www.sqlitetutorial.net/sqlite-nodejs/" rel="noopener noreferrer"&gt;tutorial you can check out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As we have learned already in the what is an API? section, an API typically involves a web server that acts as a middleman between a website/app and a database. So we are going to extend the example we showed in the API section to now include querying from a database.&lt;/p&gt;

&lt;p&gt;We'll begin by navigating on our command line to the folder containing the &lt;code&gt;my-api.js&lt;/code&gt; file from the How do I create an API? example and run the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Go through the question prompts with all the defaults then run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(If you aren't sure what we are doing here you may need to revisit the What is a package manager? section)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, update the &lt;code&gt;my-api.js&lt;/code&gt; as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;my-api.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Database setup&lt;/span&gt;

&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sqlite3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sqlite3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;verbose&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;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;:memory:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serialize&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="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CREATE TABLE weather (city TEXT, temp INTEGER)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 4&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INSERT INTO weather VALUES (?, ?)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toronto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vancouver&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Web server config&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&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;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8000&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;requestHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &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="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;setHeader&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&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="c1"&gt;// 5&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;requestedCity&lt;/span&gt; &lt;span class="o"&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;switch &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="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/toronto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;requestedCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toronto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/vancouver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;requestedCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vancouver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 6&lt;/span&gt;
  &lt;span class="nx"&gt;db&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;SELECT * from weather WHERE city = ?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// 7&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;requestedCity&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;row&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="c1"&gt;// 8&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weatherDataString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&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;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weatherDataString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Web server start&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;server&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;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Listening at http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&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;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is getting a bit more complex, so I'll added a few numbered comments I'll refer to below explaining what is going on here. I do not include any explanations for the web server code since it was covered in the APIs section already.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load the &lt;code&gt;sqlite3&lt;/code&gt; package that we installed from NPM. What this literally means "look at the &lt;code&gt;package.json&lt;/code&gt; file in the &lt;code&gt;node_moudles/sqlite3&lt;/code&gt; directory and see if there is a field called "main" which tells me the location of a Javascript file to start loading and running code from. The next line creates a new SQLite database based on the classes defined in that JS file, and &lt;code&gt;:memory:&lt;/code&gt; tells it we will be creating the DB from memory and not from a file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;serialize&lt;/code&gt; is an SQLite function that means "run all the commands inside this function one at a time making sure each one finishes before the next one starts".&lt;/li&gt;
&lt;li&gt;Standard SQL syntax for creating a table.&lt;/li&gt;
&lt;li&gt;Prepare an &lt;code&gt;INSERT&lt;/code&gt; statement to add data into our database. We prepare the statement first since the statement itself doesn't change, only the values we are inserting (represented by the &lt;code&gt;?&lt;/code&gt; character). Once this is finalized and run we will have two rows in our database, one for each &lt;code&gt;run&lt;/code&gt; function called, with temps for Toronto and Vancouver.&lt;/li&gt;
&lt;li&gt;We jump ahead to the point after our web server has been initialized. We introduce one new concept to our server itself and that's &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html" rel="noopener noreferrer"&gt;routing&lt;/a&gt;. I wanted the user to be able to define which city they want the weather for, rather than getting every single city every time, which is a waste of resources. &lt;code&gt;req.url&lt;/code&gt; will have the route portion of the request, so if the URL is &lt;code&gt;http://localhost:8000/toronto&lt;/code&gt; then &lt;code&gt;req.url&lt;/code&gt; will be &lt;code&gt;/toronto&lt;/code&gt;. We then save that city data into a variable called &lt;code&gt;requestedCity&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Next we invoke the &lt;code&gt;get&lt;/code&gt; function on our SQLite database and run a basic &lt;code&gt;SELECT&lt;/code&gt; SQL query for the data. The &lt;code&gt;?&lt;/code&gt; in the statement is replaced with the value in our variable which presumably will be either &lt;code&gt;toronto&lt;/code&gt; or &lt;code&gt;vancouver&lt;/code&gt; (or fail if the user requests anything else). It's important that we use the &lt;code&gt;?&lt;/code&gt; syntax to insert the variables that came from the user. Remember that all user provided data must be considered potentially malicious, so using prepared statements and the &lt;code&gt;?&lt;/code&gt; substitution instead of directly concatenating the value onto the strings to help project against &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/SQL_Injection" rel="noopener noreferrer"&gt;SQL injection&lt;/a&gt; attacks.&lt;/li&gt;
&lt;li&gt;This array is where the variable values are taken from to replace the &lt;code&gt;?&lt;/code&gt; characters in the strings. There should be exactly as many values in this array as there are &lt;code&gt;?&lt;/code&gt; characters in your statement.&lt;/li&gt;
&lt;li&gt;The query result is returned inside of this variable we've called &lt;code&gt;row&lt;/code&gt; because it represents a row in your database &lt;code&gt;weather&lt;/code&gt; table. If you're not familiar with this syntax here (the function as an argument that takes &lt;code&gt;row&lt;/code&gt; and &lt;code&gt;err&lt;/code&gt; as arguments) it's called a &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Callback_function" rel="noopener noreferrer"&gt;callback function&lt;/a&gt; and it's one of the more challenging topics to learn as a new Javascript dev, so don't worry if you don't get it right away. This &lt;code&gt;row&lt;/code&gt; is returned as an object so we can &lt;code&gt;JSON.stringify()&lt;/code&gt; it and return it as the payload for our HTTP request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's give it a try! Boot up your web server with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node my-api.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;a href=""&gt;http://localhost:8000/toronto&lt;/a&gt; in your browser to GET the weather from Toronto that is saved in your database! Try changing the route to &lt;code&gt;/vancouver&lt;/code&gt; and see what happens as well!&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1662323831%2Fblogs%2Fintro-to-web-development%2Fapi2_a7bggg.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1662323831%2Fblogs%2Fintro-to-web-development%2Fapi2_a7bggg.png" alt="API Database Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This example here provides you with a really solid introductory example of what a "day in the life" is like of a backend developer. You'll likely be writing SQL statements, creating and updating tables in databases, writing code to query tables in the database and returning that data to users by creating "endpoints" using routes that follow a specific set of rules you control for how data is accessed and who is allowed to access it through &lt;a href="https://en.wikipedia.org/wiki/Authentication" rel="noopener noreferrer"&gt;authentication&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Authorization" rel="noopener noreferrer"&gt;authorization&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning databases?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.sqlitetutorial.net/sqlite-nodejs/" rel="noopener noreferrer"&gt;SQLite Tutorial for Node.js&lt;/a&gt; to keep going further with the Node.js based exmaple of working with SQL beyond what we've done so far.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://university.mongodb.com/" rel="noopener noreferrer"&gt;MongoDB Univeristy&lt;/a&gt; for those devs going the NoSQL route, MongoDB is one of the most popular databases in that space (particularly in the Node and Javascript world) and one you are likely to encounter at some point in your career.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.khanacademy.org/computing/computer-programming/sql" rel="noopener noreferrer"&gt;Khan Academy's Introduction to SQL&lt;/a&gt; includes videos and tutorials on everything SQL&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/user/CS186Berkeley/videos" rel="noopener noreferrer"&gt;CS 186 Berkeley&lt;/a&gt; an amazing free course that covers pretty much everything you need to know about databases as a back-end developer&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.redbook.io/" rel="noopener noreferrer"&gt;The Red Book&lt;/a&gt; the classic book on database theory available to read free online. Although it's extremely comprehensive, it's also fairly academic and probably more than the majority of back-end developers will need. Recommended when you have all the basics down and are ready to dive deeper into the fundamentals.&lt;/p&gt;

&lt;h1&gt;
  
  
  Front End Frameworks
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What is a front end framework?
&lt;/h2&gt;

&lt;p&gt;New developers often hear that they "need to learn a framework" in order to get a job, and that of course begs the question: &lt;em&gt;"What is a framework?"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There is no one-size-fits-all answer to that. Many people have different definitions, but the simplest one in the context of Javascript and web development is that it is &lt;em&gt;a library/package that provides structure and opinions on how you should organize your code, and typically also provides tools and helper functions to build the code itself.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are React, Angular, Vue, Svelte and jQuery?
&lt;/h2&gt;

&lt;p&gt;Popular front end frameworks in the web development world include &lt;em&gt;React, Angular and Vue&lt;/em&gt;. These tools are chosen because they provide much better ways of building and managing re-usable code templates for UI elements than the native browser does.&lt;/p&gt;

&lt;p&gt;To give an example, you could create a &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; component called &lt;code&gt;Card&lt;/code&gt; which includes &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags wrapped in a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;. It is created as a Javascript function that takes an object as an input argument with text/links to fill in those values. Once built you now have a "component" you can use like an HTML tag in the format &lt;code&gt;&amp;lt;Card&amp;gt;&lt;/code&gt; over and over to build, for example, a page with a list of employee profiles.&lt;/p&gt;

&lt;p&gt;The language used to build these components is called &lt;code&gt;JSX&lt;/code&gt; and is basically a mix of HTML and Javascript. Here's an example of how the &lt;code&gt;Card&lt;/code&gt; we just described would look in React:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(In the below example, &lt;code&gt;props&lt;/code&gt; is a Javascript object with three properties: url, title, and text, each of which are strings)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Card.jsx&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then using your custom component on your website/app looks like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;App.jsx&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"www.example.com/steven.png"&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Steven Lastname"&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Steven is a wonderful employee!"&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;Card&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"www.example.com/nancy.png"&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Nancy Lastname"&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Nancy is here to help!"&lt;/span&gt;
  &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each framework has different levels of how opinionated they get. For example React is a lot more flexible as to how you set up your file structure, but it provides very strict rules about how its components are built.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://angular.io/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; is also very opinionated about how components are structured, but much more than React enforces a particular directory and file structure within your project as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue&lt;/a&gt; and &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; are much less opinionated in that regard.&lt;/p&gt;

&lt;p&gt;Another one you may have heard of is &lt;a href="https://jquery.com/" rel="noopener noreferrer"&gt;jQuery&lt;/a&gt;. In its heyday, jQuery was te go-to JS tool for providing additional functions that made creating and updating the DOM (the elements on your website) much easier. Much of the reasons developers no longer reach for it is that many of its functions have now been implemented into the Javascript built-in standard itself (for example &lt;code&gt;document.querySelector&lt;/code&gt; for DOM manipulation and &lt;code&gt;fetch&lt;/code&gt; for AJAX calls), so the language would not be what it is today without jQuery having paved the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a CSS framework?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What are Bootstrap and TailwindCSS?
&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;CSS framework&lt;/em&gt; is a term typically used to refer to packaged code that focuses on provided pre-written CSS rather than Javascript (though many CSS frameworks including Bootstrap also include Javascript code as well to provide additional functionality).&lt;/p&gt;

&lt;p&gt;Two popular CSS frameworks worth knowing about are &lt;a href="https://getbootstrap.com/" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt; and &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Both libraries focus on simplifying and reducing the amount of CSS you need to write, and creating systems to make things like margins, paddings and layout more consistent across your site so you don't need to build and implement your own design system.&lt;/p&gt;

&lt;p&gt;Bootstrap popularized the &lt;em&gt;12 column grid system&lt;/em&gt; you'll see in many layout tools these days, for example using a CSS class like &lt;code&gt;col-3&lt;/code&gt; to represent 3/12 (or 25%) of the screen.&lt;/p&gt;

&lt;p&gt;Bootstrap is far more opinionated of the two (and therefore a larger footprint in terms of size in your application) but provides some great defaults for developers who are not design savvy and prefer to focus on the function of their application. Bootstrap, similar to jQuery, was far more of a standard in the earlier days of web development as has gradually fallen out of favour, but you'll still find it commonly used in many applications still in operation today.&lt;/p&gt;

&lt;p&gt;TailwindCSS on the other hand has seen a massive rise in popularity in recent years mostly due to its small form factor and simple to use classes, as well as being easy to customize. Tailwind is a great choice for devs and designers who want to get a nice looking up up off the ground quickly, while still leaving room to customize it to your desired look and feel.&lt;/p&gt;

&lt;p&gt;If you want to really quickly get a feel for what using a CSS framework is like, the simplest way is to simply include the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag example from the &lt;code&gt;Include via CDN&lt;/code&gt; section on the front page of &lt;a href=""&gt;https://getbootstrap.com/&lt;/a&gt; in your &lt;code&gt;index.html&lt;/code&gt; file and use the Bootstrap documentation to try out some of the different classes.&lt;/p&gt;

&lt;p&gt;Here's a super minimal example of a site that loads and uses bootstrap. The &lt;code&gt;class="btn btn-primary"&lt;/code&gt; and other classes on buttons is what's hooking those elements into the Bootstrap styles.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt;
      &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css"&lt;/span&gt;
      &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;
      &lt;span class="na"&gt;integrity=&lt;/span&gt;&lt;span class="s"&gt;"sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx"&lt;/span&gt;
      &lt;span class="na"&gt;crossorigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Primary&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-secondary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Secondary&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-success"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Success&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1662331134%2Fblogs%2Fintro-to-web-development%2Fbootstrap_u1mszp.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1662331134%2Fblogs%2Fintro-to-web-development%2Fbootstrap_u1mszp.png" alt="Bootstrap Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use a front end framework?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How do I use React?
&lt;/h2&gt;

&lt;p&gt;Once you have a strong grasp of the HTML/CSS/Javascript fundamentals, it's a good idea to get familiar with at least one framework (the most popular of which at the time of this writing is React).&lt;/p&gt;

&lt;p&gt;Kent C. Dodds has a good introduction on the &lt;a href="https://kentcdodds.com/blog/javascript-to-know-for-react" rel="noopener noreferrer"&gt;specific Javascript you'll want to know for React&lt;/a&gt; before diving in.&lt;/p&gt;

&lt;p&gt;I highly recommend you get yourself to a comfortable level with Javascript and understand all of the topics in the above link before you start. Many frustrations people often experience with React when starting with it too early are actually Javascript frustrations.&lt;/p&gt;

&lt;p&gt;The fastest and easiest way to start writing React is to use a pre-configured tool like &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt; or &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create React App (CRA) has been the de-facto standard for many years, also Vite has been picking up traction recently. From the perspective of a beginner learning the basics it won't make much of a difference. Let's start a react app with CRA using the following command on the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app@latest my-cool-app

cd my-cool-app

npm run start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the first command is &lt;code&gt;npx&lt;/code&gt; and not &lt;code&gt;npm&lt;/code&gt;. The third argument is just the name of the app you want to make. The second command &lt;code&gt;cd&lt;/code&gt; is to change into that directory when the installation is complete.&lt;/p&gt;

&lt;p&gt;Then when you run &lt;code&gt;npm run start&lt;/code&gt; in that new directory you browser will be opened automatically and you'll be taken to &lt;a href=""&gt;http://localhost:3000&lt;/a&gt; where your new app is being served on. It should look like a big animated spinning atom with some title text describing how to edit your app.&lt;/p&gt;

&lt;p&gt;Create React App provides a "live reload" dev server which means that changes to your app will be reflected in the browser instantly, making it very easy to make changes to your app and quickly see and debug the results. Try making changes to the &lt;code&gt;src/App.js&lt;/code&gt; file and seeing what happens!&lt;/p&gt;

&lt;h2&gt;
  
  
  What else do I need to know about React?
&lt;/h2&gt;

&lt;p&gt;You should know the difference between functional components and class components. Class components are still perfectly valid, though are considered the "old" way to doing things and all modern React features and syntax are designed primarily to support functional components moving forward.&lt;/p&gt;

&lt;p&gt;You should know what &lt;a href="https://beta.reactjs.org/learn#using-hooks" rel="noopener noreferrer"&gt;hooks&lt;/a&gt; are.&lt;/p&gt;

&lt;p&gt;You should know what &lt;a href="https://beta.reactjs.org/learn/render-and-commit" rel="noopener noreferrer"&gt;rendering&lt;/a&gt; a components means in the context of React.&lt;/p&gt;

&lt;p&gt;You should understand React &lt;a href="https://beta.reactjs.org/learn/managing-state" rel="noopener noreferrer"&gt;state&lt;/a&gt; and understand why React prefers to replace values rather than mutate (hint: it's to make it easier to keep track of when something changes to know when to update the DOM)&lt;/p&gt;

&lt;p&gt;You should understand what a lifecycle effect and how you can use a hook like &lt;code&gt;useEffect&lt;/code&gt; to watch values and trigger different actions/events when those values change.&lt;/p&gt;

&lt;p&gt;You should know what global state management solutions are and why people use them. This includes bu not limited to ReduX, MobX, Zustand, Recoil, etc (there's tons). You should also understand the Context API and when it does and &lt;a href="https://blog.isquaredsoftware.com/2021/01/context-redux-differences/" rel="noopener noreferrer"&gt;doesn't act as a global state management tool&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning React?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7"&gt;My Blog Post on React&lt;/a&gt; shameless plug for my blog post where I go into more detail into how to configure a React project from the group up to get a better understanding of what's going on&lt;/p&gt;

&lt;p&gt;&lt;a href="https://reactjs.org/docs/getting-started.html" rel="noopener noreferrer"&gt;Official Documentation&lt;/a&gt; and &lt;a href="https://beta.reactjs.org/" rel="noopener noreferrer"&gt;The Official Beta Docs&lt;/a&gt; written by the React team should be your first source of information. The beta docs are quite new, but they are much improved and updated to use modern React syntax, so you should always check them first before falling back on the original docs if you can't find what you're looking for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reactiflux.com/learning" rel="noopener noreferrer"&gt;Reactiflux&lt;/a&gt; mark Erikson's (developer of Redux) suggested path for learning React.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.codecademy.com/catalog/language/javascript" rel="noopener noreferrer"&gt;Codeacademy&lt;/a&gt;'s React course.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.roadtoreact.com/" rel="noopener noreferrer"&gt;The Road to React&lt;/a&gt; by Robin Wieruch. Not a free resource I admit, though I felt I should include it because I did read it while learning React and think it was extremely helpful for improving my understanding.&lt;/p&gt;

&lt;h1&gt;
  
  
  Typescript
&lt;/h1&gt;

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

&lt;h2&gt;
  
  
  What is the difference between Typescript and Javascript?
&lt;/h2&gt;

&lt;p&gt;Typescript is an absolutely incredible programming language. It is largely responsible for adoption of Javascript to build large-scale business applications that might otherwise never have been possible or realistic without it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Typescript is Javascript&lt;/em&gt;&lt;/strong&gt;. That's one of those really critical things to realize.&lt;/p&gt;

&lt;p&gt;Typescript is just Javascript code with additional syntax added on top of it to check for correctness and potential errors while you are writing it that otherwise would not be caught until you actually run the program with standard Javascript.&lt;/p&gt;

&lt;p&gt;If you are proficient in Javascript, you still may not know how to write Typescript. However, if learn Typescript, then you also know Javascript as well. A good TS developer would be more than qualified for any JS job.&lt;/p&gt;

&lt;p&gt;It can be difficult to explain to new developers why Typescript is so important. Often they will find it frustrating that they cannot get code to work, or it feels too complex with little payoff.&lt;/p&gt;

&lt;p&gt;When it comes down to it, if you want to be employed as a web developer professionally, Typescript is unquestionably the way to go. You will severely limit your job prospects if you only learn JS.&lt;/p&gt;

&lt;p&gt;This is probably a good time to show an example of the difference between JS and TS:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;script.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&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 first JS example is pretty simple. It takes two arguments, and adds them together. If you run the following:&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will be &lt;code&gt;7&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What if we did the following though?&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3&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;4&lt;/span&gt;&lt;span class="dl"&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What would the output be? The answer is the strong "34" because each argument was actually a string, so Javascript just assumed you meant "concatenate" when you used the plus sign.&lt;/p&gt;

&lt;p&gt;Next let's take a look at the second example above that was labelled as &lt;code&gt;script.ts&lt;/code&gt;. It's the same function but the parameters are annotated as &lt;code&gt;number&lt;/code&gt; and &lt;code&gt;number&lt;/code&gt; also appears after the parentheses to indicate that the return value should also be a number.&lt;/p&gt;

&lt;p&gt;The screenshot below demonstrates what you would see when writing this using VS Code:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657081289%2Fblogs%2Fintro-to-web-development%2Ftypescript_n4m96n.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657081289%2Fblogs%2Fintro-to-web-development%2Ftypescript_n4m96n.png" alt="Typescript Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So although this is a simple example, you can immediately see one of the many benefits. Typescript has stopped us from making a simple syntax error and using our function incorrectly.&lt;/p&gt;

&lt;p&gt;Remember that even if you look at this and think &lt;em&gt;"I would never make such a simple mistake"&lt;/em&gt;, in reality, when working on large projects for long hours &lt;em&gt;everyone&lt;/em&gt; makes small stupid mistakes. All the time.&lt;/p&gt;

&lt;p&gt;And even if you don't, your coworkers will.&lt;/p&gt;

&lt;p&gt;Typescript is there to help you with a warning as soon as you make these errors so you can correct them and get back to working on your code.&lt;/p&gt;

&lt;p&gt;So that's great, but how do you actually use it? &lt;code&gt;.ts&lt;/code&gt; files?&lt;/p&gt;

&lt;p&gt;Browsers do not understand Typescript. They only understand Javascript. So modern working setups are created to allow you to write Typescript code, but then &lt;em&gt;transpile&lt;/em&gt; _convert) it into Javascript code when you are ready to run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use Typescript?
&lt;/h2&gt;

&lt;p&gt;The easiest way to practice and learn it is with the &lt;a href="https://www.typescriptlang.org/play" rel="noopener noreferrer"&gt;Typescript playground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you move beyond that and want to start writing your own Typescript code on your machine, the most basic setup involves the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First, install Node.js on your machine. This will automatically install &lt;code&gt;npm&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, create a folder for your project, then navigate to that folder on the command line and run &lt;code&gt;npm init&lt;/code&gt;. Just hit enter to select all the defaults.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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;--save-dev&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will install Typescript in your project as a "dev dependency". You should be able to see it listed with a version number in the &lt;code&gt;package.json&lt;/code&gt; file that NPM created.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the following command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsc &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note that's &lt;code&gt;npx&lt;/code&gt; not &lt;code&gt;npm&lt;/code&gt;. &lt;code&gt;npx&lt;/code&gt; is a "package runner" which is different from your package manager. It can run packages that are installed in your project as code directly)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will create a &lt;code&gt;tsconfig.json&lt;/code&gt; file which has all the configuration for your Typescript project. &lt;a href="https://www.typescriptlang.org/docs/handbook/tsconfig-json.html" rel="noopener noreferrer"&gt;You can learn more about tsconfig.json here&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;script.ts&lt;/code&gt; file with any Typescript code you like in it. This file should be in the project root in the same directory as your &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can use the example above with the &lt;code&gt;addNumbers&lt;/code&gt; function if you like, code below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt; Now you need to convert that &lt;code&gt;.ts&lt;/code&gt; file into Javascript. Run the following command.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsc script.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will run Typescript on the &lt;code&gt;script.ts&lt;/code&gt; file and output a &lt;code&gt;script.js&lt;/code&gt; file right beside it with all the type information removed.&lt;/p&gt;

&lt;p&gt;That information was only there to help you with development, once you have verified there are no errors none if it is necessary anymore, which is great, because it means it does not add any size/bloat to the actual code that you will be including in your site.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Once the &lt;code&gt;script.js&lt;/code&gt; file has been generated, run it with Node!
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you copied the above example the output will be &lt;code&gt;7&lt;/code&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the best resources for learning Typescript?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.typescriptlang.org/docs/" rel="noopener noreferrer"&gt;Official documentation&lt;/a&gt; As far as I'm concerned there is no better source than the Typescript docs themselves. Lots of great examples starting at the beginner level and up from there.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://youtu.be/LKVHFHJsiO0" rel="noopener noreferrer"&gt;No BS TS&lt;/a&gt; Some great videos on getting up and running with Typescript quickly&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Web Hosting
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Where do I host a website?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How do I put my website on the internet?
&lt;/h2&gt;

&lt;p&gt;Web hosting is, simply put, the act of putting your website or web app files onto a machine or service somewhere that the general public can access them. There are basically a million different ways you can do this and a lot of factors that go into the decision of which one you might choose, so in this tutorial we are going to focus on the simplest ones.&lt;/p&gt;

&lt;p&gt;Things that are important to us right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplicity &amp;amp; cost (ideally free)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Things that are not important to us right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scalability (ability to handle large amounts of traffic, with &lt;em&gt;large&lt;/em&gt; referring to hundreds of thousands of requests and beyond)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So with those in mind I'll start by showing you two great options for hosting a simple website built with HTML, CSS and JS. This type of setup we call a &lt;em&gt;static site&lt;/em&gt; which basically means all the files used are "static" in that they are already written and don't change (as opposed to a dynamic app which generates HTML automatically, something like React for example).&lt;/p&gt;

&lt;p&gt;The two options I would suggest depend on whether or not you have set up a Github account yet, and pushed your site to a repository.&lt;/p&gt;

&lt;p&gt;If your code is already on Github, then I recommend Static Site Hosting Option 1: Github Pages if not, then I suggest Static Site Hosting Option 2: Netlify which is a great service with an excellent free tier for hosting projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static Site Hosting Option 1: Github Pages
&lt;/h3&gt;

&lt;p&gt;This section will follow up with the tutorial that teaches you how to push your site to a remote Github repository. We will be using a repository that is hosting the Basic Website Example but you can host your own custom site if you choose.&lt;/p&gt;

&lt;p&gt;Navigate to your site's repository on Github and choose &lt;code&gt;Settings -&amp;gt; Pages&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657474898%2Fblogs%2Fintro-to-web-development%2Fgithub-pages-1_ucsyjp.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657474898%2Fblogs%2Fintro-to-web-development%2Fgithub-pages-1_ucsyjp.png" alt="Github Pages Example 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use the dropdown to select which branch you want to publish (default is &lt;code&gt;main&lt;/code&gt; if you followed the tutorial, but if you're on an older version of git it could be &lt;code&gt;master&lt;/code&gt; and then click &lt;code&gt;Save&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;...that's it! You're done. You'll be given a custom generated URL based on the name of your Github account and repository that you can share with anyone. Here's mine:&lt;/p&gt;

&lt;p&gt;&lt;a href=""&gt;https://alexeagleson.github.io/example-git-project/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github pages is an absolutely fantastic way to quickly host and share static websites.&lt;/p&gt;

&lt;p&gt;If you've reached a point where you are now wondering where to host more complex web apps (React apps for example) or Node apps/APIs then skip ahead to the How do I host a web app? section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static Site Hosting Option 2: Netlify
&lt;/h3&gt;

&lt;p&gt;If your HTML, CSS and JS files are on your computer and you haven't learned how to use Github yet don't fret, Netlify is a great option.&lt;/p&gt;

&lt;p&gt;Navigate to the &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify website&lt;/a&gt; and create a free account.&lt;/p&gt;

&lt;p&gt;Once you have logged in your will see a dashboard that gives you three options: to host a project from Github, or use a template, or upload files manually. We are going to upload the files ourselves:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657473568%2Fblogs%2Fintro-to-web-development%2Fstatic-site-hosting_pgwbvq.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657473568%2Fblogs%2Fintro-to-web-development%2Fstatic-site-hosting_pgwbvq.png" alt="Static Site Hosting Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm going to click &lt;em&gt;"browse to upload"&lt;/em&gt; and select the directory that has my &lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;script.js&lt;/code&gt; and &lt;code&gt;style.css&lt;/code&gt; files in it from the Basic Website Example. You can take those files for learning purposes, or upload your own site.&lt;/p&gt;

&lt;p&gt;The process will take a few minutes, Netlify will be configuring its web server to load your files as well as creating a custom domain name (URL) for your site that you can share with other people.&lt;/p&gt;

&lt;p&gt;Cool! My upload is done, Once finished yours should be publicly available just like mine. Here's the link I received with the files I uploaded, feel free to check it out:&lt;/p&gt;

&lt;p&gt;&lt;a href=""&gt;https://stellular-brioche-c71cfe.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's pretty much it. If you own your own domain you can direct it to the site you just uploaded with the tools they provide and add an SSL certificate as well if you like. Otherwise the randomized Netlify domain they provide you automatically is enough to be able to share your work with others.&lt;/p&gt;

&lt;p&gt;Working with free services like this the main downsides you will get is that once your site reaches a certain level of traffic Netlify will likely shut it down until you registered for a paid tier.&lt;/p&gt;

&lt;p&gt;This practice is pretty universal, you'll find that it's easy to find free hosting for projects as long as they don't get too much traffic.&lt;/p&gt;

&lt;p&gt;If you're looking for a more scaleable option that you are willing to pay for with hosting, then check out services like &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/en-ca/" rel="noopener noreferrer"&gt;Microsoft Azure&lt;/a&gt;, and &lt;a href="https://www.digitalocean.com/" rel="noopener noreferrer"&gt;Digital Ocean&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(I'll take this opportunity to warn you to avoid _Godaddy&lt;/em&gt; at all costs just in case that comes up as an option in your search, I won't waste time getting into the details, but suffice to say there are far better options. &lt;a href="https://www.yourdigitalresource.com/post/godaddy-website-review-not-use-godaddy" rel="noopener noreferrer"&gt;Here&lt;/a&gt; and &lt;a href="https://stonedigital.com.au/blog/4-reasons-why-you-should-avoid-godaddy/" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://www.reddit.com/r/webdev/comments/t8v6lp/do_yourself_a_favor_and_stay_away_from_godaddy/" rel="noopener noreferrer"&gt;here&lt;/a&gt; can get you started on reasons if you're curious)._&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I host a web app?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How do I host a React app?
&lt;/h2&gt;

&lt;p&gt;This section will discuss options for hosting web apps, we'll focus specifically on &lt;em&gt;React&lt;/em&gt; apps, but the basic premise is the same for other popular frameworks (like Angular, Vue, etc) as well.&lt;/p&gt;

&lt;p&gt;First we will create a basic React app with the popular tool &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt;. For a major production React app for your business, there are probably better options in 2022, but for quickly getting a simple React app up and running with little to no configuration it's still the best option out there.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note that the following command requires Node.js to be installed on your machine. If you haven't done that already, make sure you check out that tutorial first. It also assumes you have already learned how to hos your project on Github)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app example-react-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next I will go to my Github profile and create a project called &lt;code&gt;example-react-app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Back on my terminal I'll change directory into the project directory, add the remote Github repository I just created as the &lt;code&gt;origin&lt;/code&gt; and then &lt;code&gt;push&lt;/code&gt; my code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd example-react-app
git remote add origin YOUR_GITHUB_URL
git push -u origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/alexeagleson/example-react-app" rel="noopener noreferrer"&gt;Here&lt;/a&gt; is my personal repository where I've pushed by React app. Yours will have a different URL.&lt;/p&gt;

&lt;p&gt;Next navigate over to &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;, login to your account (or create one if you don't already have one), select &lt;em&gt;"Start new project"&lt;/em&gt; and then &lt;em&gt;"Import an existing project from a Git repository"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You will need to give Netlify permission to access your Github profile, and then either select the repository to give permission manually, or give permission to all repositories. Once permission is given you can select your React app repository.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657477051%2Fblogs%2Fintro-to-web-development%2Fnetlify-react_mnqaea.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657477051%2Fblogs%2Fintro-to-web-development%2Fnetlify-react_mnqaea.png" alt="Netlify React Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For configuration select the &lt;code&gt;main&lt;/code&gt; branch, and unless you've altered the default configuration, you can leave all the rest of the commands as-is. Netlify will go through the process of deploying your site, and provide you with an automatically generated public URL afterward.&lt;/p&gt;

&lt;p&gt;That's it! It's that simple. If you want to make updates you can simply commit changes to your repository, and then choose to redeploy on Netlify. You can even configure it to watch for changes on your Github repository, and redeploy automatically whenever you push new changes to the main branch.&lt;/p&gt;

&lt;p&gt;Here's the result of my upload and the public URL that is generated, yours should look very similar:&lt;/p&gt;

&lt;p&gt;&lt;a href=""&gt;https://magenta-conkies-c988a1.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I host a Node.js server?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How do I host a Node.js app?
&lt;/h2&gt;

&lt;p&gt;Hosting a Node app is a little bit trickier than a standard website, but not too much so. You'll have more difficulty finding a free tier for a Node app.&lt;/p&gt;

&lt;p&gt;Before getting into other options, I should say I've heard very good things about &lt;a href="https://fly.io/" rel="noopener noreferrer"&gt;fly.io&lt;/a&gt;. I've never used it personally, but it seems like a potentially great free option for Node.js hosting. If you're interested give &lt;a href="https://fly.io/docs/getting-started/node/" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt; a try and let me know how it goes.&lt;/p&gt;

&lt;p&gt;One other common suggestions is to use &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;. One benefit of lambda functions is that although you will still need to provide your credit card, they will only charge you based on actual usage. So if you and your friends are the only ones using the app, you're likely only looking at a few pennies a month.&lt;/p&gt;

&lt;p&gt;I personally haven't used AWS Lambda, so I'll be focusing on a different option for this tutorial, A service provided by Digital Ocean called &lt;a href="https://www.digitalocean.com/products/droplets" rel="noopener noreferrer"&gt;droplets&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Droplets are simply a fancy name given to access to a Linux server that is fully accessible to anyone on the internet. They're great because you can run pretty much anything you want on them. The lowest tier which is more than enough to run basic Node applications is only $5 per month, and will more than serve our purposes.&lt;/p&gt;

&lt;p&gt;It's a pretty small price to pay for something that you can use to host almost any project you work on, including the websites and web apps we've already discussed.&lt;/p&gt;

&lt;p&gt;Once you have signed up for a droplet, log into your account and select it.&lt;/p&gt;

&lt;p&gt;You will want to make sure you can access your droplet from the command line on your machine. To do this you need to set up SSH. If you have not already created SSH keys on your machine then check out the What is SSH? tutorial to create them.&lt;/p&gt;

&lt;p&gt;Once you have created your public key, from your digital ocean droplet dashboard click &lt;code&gt;Settings -&amp;gt; Security -&amp;gt; Add SSH Key&lt;/code&gt;. After it is added, copy the IP address for your droplet and return to your terminal.&lt;/p&gt;

&lt;p&gt;You can now access your remote Linux server (droplet) with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh root@YOUR_DROPLET_IP_ADDRESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When successful, your terminal will show a welcome message (by default) and you are in a different location/directory. This will be the home directory of the root use of your droplet. You can now create additional users if you choose, or whatever you like.&lt;/p&gt;

&lt;p&gt;Once you have access to your droplet via SSH, you are in a good position to begin following the official guide for running a Node.js app on Digital Ocean:&lt;/p&gt;

&lt;p&gt;Here's a quick overview of what it will show you how to do, and why each step is necessary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Step 1 — Installing Node.js&lt;/strong&gt;: Node is not installed on Linux by default so you need to install it on your droplet yourself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Step 2 — Creating a Node.js Application&lt;/strong&gt;: The tutorial assumes you will be writing the application on your droplet, which most often won't be the case. This step is where you may need to deviate a bit. If you have a Node app hosted on a Github repository, then you will want to install &lt;code&gt;git&lt;/code&gt; on your droplet as well and then clone your repository onto your droplet. That way the app you created and pushed will be on your droplet and ready to run.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Step 3 — Installing PM2&lt;/strong&gt;: PM2 is an amazing robust production quality tool for running Node.js apps. Technically you could run the normal command &lt;code&gt;node my-app.js&lt;/code&gt; same as you do on your machine, but what happens if it crashes? PM2 will take care of running the app, as well as automatically rebooting it if it crashes along with a number of other quality of life features like monitoring.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Step 4 — Setting Up Nginx as a Reverse Proxy Server&lt;/strong&gt;: Nginx is one of the most popular web servers in the world and a fantastic tool. The reason you need it in this case is to control access to your app from the outside world. If your app is running on port 300 for example and you want people to access it on a domain name you bought like &lt;code&gt;mycoolapp.com&lt;/code&gt;, Nginx is the one responsible for directing requests to that domain name on your droplet to your app on the correct port.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So with that context provided, here is the tutorial to help get your Node app up and running live:&lt;/p&gt;

&lt;p&gt;&lt;a href=""&gt;https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-20-04&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a CDN?
&lt;/h2&gt;

&lt;p&gt;CDN stands for &lt;em&gt;content delivery network&lt;/em&gt; and it's basically a hosting service designed to maximize speed and uptime for resources on the web (files, images, full sites themselves, etc).&lt;/p&gt;

&lt;p&gt;The main difference between standard hosting and a CDN is that content on a CDN will be hosted in multiple places, potentially all over the world.&lt;/p&gt;

&lt;p&gt;So if one user from your site needs to load &lt;code&gt;Cat-Picture.jpg&lt;/code&gt; and they are in USA, and another requests it in France, the CDN will serve the same cat picture from a physical server located in the USA to the user in the USA, and vice versa (or at least the nearest one).&lt;/p&gt;

&lt;p&gt;Obviously there's much more to it than that, but this definition should be more than enough to get you to know what people are talking about when they use the acronym.&lt;/p&gt;

&lt;p&gt;One of the biggest CDNs out there is called &lt;em&gt;Cloudflare&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you want to learn more about CDNs then &lt;a href="https://en.wikipedia.org/wiki/Content_delivery_network" rel="noopener noreferrer"&gt;Wikipedia is a great place to start&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Web Domains
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What is a URL?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What is a domain name?
&lt;/h2&gt;

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

&lt;p&gt;A domain name is simply some text that gets converted into an &lt;a href="https://en.wikipedia.org/wiki/IP_address" rel="noopener noreferrer"&gt;IP address&lt;/a&gt; through a process called &lt;a href="https://en.wikipedia.org/wiki/Domain_Name_System" rel="noopener noreferrer"&gt;DNS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An example of a domain name is &lt;code&gt;www.google.com&lt;/code&gt;. The &lt;code&gt;https://&lt;/code&gt; is the &lt;em&gt;scheme&lt;/em&gt; and technically not part of the domain name.&lt;/p&gt;

&lt;p&gt;DNS (domain name system) servers exist all over the internet and act as kind of a global dictionary of names and the IP addresses they belong to. They are constantly being updated as names and IP addresses change. There is no one single DNS server that acts as the source of truth, there are countless DNS servers out there and you can even choose which one you want to use to resolve a domain, or host your own.&lt;/p&gt;

&lt;p&gt;If you've ever seen the dreaded &lt;em&gt;"This site cannot be reached, server's DNS address could not be found"&lt;/em&gt; then that's because your request could not find a way to translate the name into the address of an actual server that is hosting the website or app you are looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I get a custom domain name?
&lt;/h2&gt;

&lt;p&gt;In order to get your own custom domain name you must purchase it first from a domain name registrar. Typically these names are purchased as an annual plan that can be renewed. You will always have first choice of renewal, but if you ever opt not to renew there is nothing to stop someone else from buying the name and preventing you from ever getting it back (or having to pay a steep price to buy it from them).&lt;/p&gt;

&lt;p&gt;I will not get into the nitty gritty of the business of domain names, but suffice to say it can be big business and common phrases in the &lt;code&gt;.com&lt;/code&gt; space an easily go for tens or hundreds of thousands of dollars.&lt;/p&gt;

&lt;p&gt;Fortunately there's a near infinite number of possible names out there and as long as you aren't too picky you can probably get something close enough to what you want for as low as a few dollars a year.&lt;/p&gt;

&lt;p&gt;First you must choose where to purchase from. There are plenty of options. I'd recommend either &lt;a href="https://www.gandi.net/en-CA" rel="noopener noreferrer"&gt;Gandi&lt;/a&gt; or &lt;a href="https://www.namecheap.com/" rel="noopener noreferrer"&gt;Namecheap&lt;/a&gt; or &lt;a href="https://www.cloudflare.com/products/registrar/" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt;. Avoid &lt;em&gt;Godaddy&lt;/em&gt; if at all possible (Google their reputation around customer service before making any decisions).&lt;/p&gt;

&lt;p&gt;After you've purchased the name, most of the services that sell you the name will also be willing to sell you site/app hosting services as well. You can use them if you wish, but it's not necessary, they will have options available for you to point your domain name to your existing server, whether it be something like a Digital Ocean droplet or anything similar.&lt;/p&gt;

&lt;p&gt;The final step you need to arrange after buying and configure a domain name is called an &lt;em&gt;SSL certificate&lt;/em&gt; so that you site can be accessed over secure &lt;em&gt;HTTPS&lt;/em&gt; rather than insecure &lt;em&gt;HTTP&lt;/em&gt;.&lt;/p&gt;

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

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

&lt;h2&gt;
  
  
  How do I get an SSL certificate?
&lt;/h2&gt;

&lt;p&gt;The full scope of exactly what HTTPS and SSL are is beyond the scope of this tutorial, but they are interesting topics if you wish to &lt;a href="https://blog.hubspot.com/marketing/what-is-ssl" rel="noopener noreferrer"&gt;read more about them&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I will be focusing on the practical application of setting up an SSL certificate for your domain. The first thing I will stress to you is that &lt;em&gt;generating an SSL certificate is a completely free process&lt;/em&gt;. I stress this because although it requires a bit of effort, there are no shortage of domain name sales services that will gladly charge you a $50+ fee to "secure" you domain for you.&lt;/p&gt;

&lt;p&gt;It's a completely predatory charge that targets non-technical folks who don't know any better. Don't fall for it.&lt;/p&gt;

&lt;p&gt;How you generate it will really depend on the hosting service you are using. For example if you are using Digital Ocean as I have discussed throughout this tutorial, then &lt;a href="https://docs.digitalocean.com/support/how-do-i-install-an-ssl-certificate-on-a-droplet/" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; will get you up and running.&lt;/p&gt;

&lt;p&gt;If you are using another hosting service then simply Google their name along with "ssl" and you will almost certainly find a tutorial to generate one for free among the top results.&lt;/p&gt;

&lt;h1&gt;
  
  
  SSH
&lt;/h1&gt;

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

&lt;p&gt;SSH (secure shell) is a very important concept to be familiar with, though it is often challenging for beginners to understand. I'll try to explain it as simply as possible.&lt;/p&gt;

&lt;p&gt;SSH provides a way for two machines to communicate securely. It is most commonly used over the command line. It provides a way to authenticate a machine without explicitly requiring a password (though a password can optionally be used).&lt;/p&gt;

&lt;p&gt;Though SSH can be used to transmit data for a variety of applications and uses, the most common use of it you will encounter in web developer is authenticating your machine when logging into remote servers (for example ones that may be hosting your web app) and for authenticating for version control services like Github, so that when you want to push your code to your company's repository, your machine is already authenticated and don't need to provide your username and password.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I use SSH?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What are SSH keys?
&lt;/h2&gt;

&lt;p&gt;So that explains what SSH is as a tool, now let's take a look at how to use it. SSH uses the concept of keys, specifically a &lt;em&gt;public&lt;/em&gt; key and a &lt;em&gt;private&lt;/em&gt; key.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(The explanation of how it actually works to provide security is far above the scope of this tutorial, but it's a fascinating topic and I'd recommend you check out &lt;a href="https://en.wikipedia.org/wiki/Public-key_cryptography" rel="noopener noreferrer"&gt;this Wikipedia page&lt;/a&gt; if you want to learn more about it.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We will focus on the most common developer's use case, using SSH to authenticate ourselves so we can push code to Github. If you're not familiar with Github you can check out the What is Github section of the tutorial and return here when you reach the point of setting up your SSH keys.&lt;/p&gt;

&lt;p&gt;The idea behind the public and private keys is that when you generate them, your private key should remain on your machine and you should never &lt;strong&gt;ever&lt;/strong&gt; share it with &lt;strong&gt;anyone&lt;/strong&gt;. As soon as anyone gains access to your private key, they immediately gain the ability to impersonate you, and if you ever suspect that may have occurred (someone got access to your computer for example), you should delete your keys and generate new ones.&lt;/p&gt;

&lt;p&gt;The public key on the other hand can freely be shared with anyone. That is what you will add to Github, and whenever a connection request is made from your machine, Github will use that public key to verify the request being sent from your computer with the private key matches.&lt;/p&gt;

&lt;p&gt;The keys themselves are simply long strings of text characters, usually a few hundred depending on the algorithm used. When the keys are generated two files will be created, and you can differentiate between the public and private keys with the extension.&lt;/p&gt;

&lt;p&gt;The private key will be generated as &lt;code&gt;FILENAME&lt;/code&gt; (the filename again will depend on the algorithm used) and the public key will be generated in &lt;code&gt;FILENAME.pub&lt;/code&gt;. So remember whenever anyone or any service asks you to provide your SSH key, you want to &lt;em&gt;&lt;strong&gt;always make sure you provide the one in the file with the .pub extension&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I generate SSH keys?
&lt;/h2&gt;

&lt;p&gt;Rather than go through the actual step-by-step instructions on how to genertae them, I will direct you to one of many great tutorials out there. Generating the keys is easy on any operating system using a free command line tool called &lt;code&gt;ssh-keygen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Before showing how to generate keys from the command line, I would also take the opportunity to suggest the &lt;a href="https://developer.1password.com/docs/ssh/" rel="noopener noreferrer"&gt;SSH key generation and SSH agent in 1Password&lt;/a&gt;. Full disclosure, this is the company I work for and I don't usually like to pitch products, but this is a rare case while I am genuinely impressed by how useful it is to manage SSH keys in 1Password and be able to share them between different machines I'm working from.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That said, it's absolutely not necessary to use at all, just a nice convenience thing. The below links show you how to generate your own keys on the command line completely free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://confluence.atlassian.com/bitbucketserver/creating-ssh-keys-776639788.html#CreatingSSHkeys-CreatinganSSHkeyonWindows" rel="noopener noreferrer"&gt;How to generate SSH keys on Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://confluence.atlassian.com/bitbucketserver/creating-ssh-keys-776639788.html#CreatingSSHkeys-CreatinganSSHkeyonLinux&amp;amp;macOS" rel="noopener noreferrer"&gt;How to generate SSH keys on macOS/Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Github itself also has a own &lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt; if for any reason you prefer to use that, but both it and the Atlassian one should give you the same result.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(You have the option of adding a password to SSH keys that you need to enter each time you use them. SSH keys themselves are already very secure, I personally find adding a password on top of that not worth the inconvenience, but it's completely up to you.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once your keys are generated, make sure you know where the &lt;code&gt;.pub&lt;/code&gt; file was creating. On macOS/Linus you'll find it in the &lt;code&gt;~/.ssh&lt;/code&gt; directory, and on Windows the &lt;code&gt;%userprofile%/.ssh&lt;/code&gt; directory. You can view its contents by opening it in any text editor.&lt;/p&gt;

&lt;p&gt;To add it to your Github profile, copy the contents of the &lt;code&gt;.pub&lt;/code&gt; file and go to your Github dashboard. Click your profile icon then &lt;code&gt;Settings -&amp;gt; SSH and GPG Keys&lt;/code&gt;. Now click the green &lt;code&gt;New SSH Key&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;Paste the text of the key itself in the &lt;code&gt;Key&lt;/code&gt; text box and give it a title. Typically the title refers to the machine the key is tied to, so if I generated it I might give it a title like "Alex's Personal Laptop" or "Alex's Work Laptop" etc. Probably good to provide even more details if you work with multiple machines.&lt;/p&gt;

&lt;p&gt;Once that is saved you are ready to &lt;code&gt;clone&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;pull&lt;/code&gt; Github projects over SSH. Make sure that from now on you are always copying the &lt;code&gt;SSH&lt;/code&gt; version of the URL and not the &lt;code&gt;HTTPS&lt;/code&gt; one. You can tell which is which based on their structure, examples below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH URL Example: &lt;a href=""&gt;git@github.com:alexeagleson/example-git-project.git&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;HTTPS URL Example: &lt;a href=""&gt;https://github.com/alexeagleson/example-git-project.git&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have already been working with a Github project over HTTPS and want to switch an existing project, you will need to change the &lt;code&gt;remote URL&lt;/code&gt;. To do that, navigate to the project on your machine and run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote set-url origin YOUR_REPOSITORY_SSH_URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will update the default &lt;code&gt;origin&lt;/code&gt; to use the SSH URL and you will no longer need to enter your username and password when pushing to it.&lt;/p&gt;

&lt;h1&gt;
  
  
  DevOps
&lt;/h1&gt;

&lt;p&gt;DevOps is one of those terms that can mean ten different things to ten different people.  I will not make any attempt to assign any kind of formal definition to the term, my only concern is helping you understand the basic concept.&lt;/p&gt;

&lt;p&gt;DevOps is at its simplest the automation of the deployment process.  We've talked at great length about what a website and web app is, but maybe a little bit less about deployment.  &lt;em&gt;Deployment&lt;/em&gt; is simply the act of getting your site or app online and available to access for your consumer.   &lt;/p&gt;

&lt;p&gt;In the distant past there was a very clear divide between software developers and systems administrators (often called &lt;em&gt;SysAdmins&lt;/em&gt; or just more generally &lt;em&gt;IT&lt;/em&gt; personnel).  As the industry matured it became clear that the divide between these two roles was not as large as once thought, and that a lot of benefits could be gained from having developers who were familiar with how their apps were deployed, as well as system administrators who were familiar with code, so that each could communicate their needs better to one another.&lt;/p&gt;

&lt;p&gt;These days very few companies manage their own infrastructure (the servers their code is deployed on) and even fewer have their own physical servers.  The majority of tech companies deploy their products using &lt;a href="https://en.wikipedia.org/wiki/Cloud_computing" rel="noopener noreferrer"&gt;cloud services&lt;/a&gt; like &lt;a href="https://azure.microsoft.com/en-ca/" rel="noopener noreferrer"&gt;Microsoft Azure&lt;/a&gt; or &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;Amazon Web Services (AWS)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using these services rather than purchasing and maintaining physical servers allows tech companies to focused entirely on their product and not maintain a large infrastructure team.  As their application userbase grows and &lt;a href="https://en.wikipedia.org/wiki/Scalability" rel="noopener noreferrer"&gt;scales&lt;/a&gt; tools like AWS are designed to automatically handle that increase in traffic in real time in ways that would be far more difficult if not impossible to do if it were necessary to purchase and install more physical servers.  &lt;/p&gt;

&lt;p&gt;That feature of course comes at a cost, but that cost presumably will be less than trying to manage your infrastructure yourself.  &lt;/p&gt;

&lt;p&gt;Nevertheless, managing the needs of a high traffic application can be very complex.  Tools like AWS are designed to be easily configured by code rather than through direct access to the servers themselves.  DevOps personnel are particularly adept at building and maintaining configurations for cloud services so that developers do not need to think as much about how the code they write is actually deployed and served to the public.  &lt;/p&gt;

&lt;h2&gt;
  
  
  What is CI/CD?
&lt;/h2&gt;

&lt;p&gt;In addition to managing things like cloud configuration, a good DevOps engineer also takes care of building an application's CI/CD pipeline.  CI/CD stands for &lt;a href="https://en.wikipedia.org/wiki/CI/CD" rel="noopener noreferrer"&gt;continuous integration and continuous delivery&lt;/a&gt;.  It essentially means creating the needed processes so that developers can continue to build and implement features for the application with minimal risk of introducing bugs or errors.&lt;/p&gt;

&lt;p&gt;DevOps engineers will use features within tools like &lt;a href="https://about.gitlab.com/" rel="noopener noreferrer"&gt;Gitlab&lt;/a&gt; or &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;Github&lt;/a&gt; to ensure that in order for code to be allowed to merge into the primary &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;master&lt;/code&gt; branch of the project, it must meet certain conditions.&lt;/p&gt;

&lt;p&gt;Those conditions can range in anything from simple &lt;a href="https://en.wikipedia.org/wiki/Lint_(software)" rel="noopener noreferrer"&gt;linter checks&lt;/a&gt; to full blow &lt;a href="https://www.browserstack.com/guide/end-to-end-testing" rel="noopener noreferrer"&gt;end-to-end tests&lt;/a&gt; which run real simulated user actions on your code and check to see if they match conditions you have set.  If they fail, the code a developer submitted will not be allowed to merge.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Continuous integration&lt;/em&gt; refers to the idea of frequently merging new code into the priamry project branch, rather than keeping it in a separate branch.  This has the benefit of keeping every developer up to date with the most recent state of the project, and avoids the risk of large merge conflicts if separate devs have been making changes to similar areas of the codebase over days or even weeks and months.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Continuous delivery&lt;/em&gt; refers to the idea of releasing these changes frequently to the customer.  This provides the significant benefit of being able to quickly turn around customer feedback into real usable features or bug fixes.  If your CI/CD automated pipeline is solid then you can be confident that any code changes which have passed all your tests are potentially ready to be released to your users without the need for extensive QA (though manual QA is always a good idea regardless of how good your pipeline is.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Containers
&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://docs.docker.com/get-started/overview/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; is a tool that allows you package the environment for running your application along with the application itself.  You can accomplish this as simply as including a single file called &lt;code&gt;Dockerfile&lt;/code&gt; with your project.&lt;/p&gt;

&lt;p&gt;A developer might choose to use Docker because it provides guarantees that the versions of each tool installed (like Node, Python, NPM, MySQL, etc) are the same for every developer working on the project, regardless of what they have installed on their own machine.&lt;/p&gt;

&lt;p&gt;If you've ever had trouble getting your &lt;em&gt;environment setup&lt;/em&gt; properly to start your development work, that's exactly what a tool like Docker is designed to solve.&lt;/p&gt;

&lt;p&gt;It uses a concept it calls &lt;em&gt;containers&lt;/em&gt; which are lighter weight (require less resources) than full on &lt;a href="https://en.wikipedia.org/wiki/Virtual_machine" rel="noopener noreferrer"&gt;virtual machines&lt;/a&gt; to create the environment for your application.  These containers are designed to be extremely &lt;em&gt;portable&lt;/em&gt; which means that you can quickly deploy them anywhere, and also scale up your app quickly by simply deploying more copies of your container.  &lt;/p&gt;

&lt;p&gt;All you need to do is define the requirements for your environment in the &lt;code&gt;Dockerfile&lt;/code&gt; (for example Ubuntu 18, Node.js, etc) and every time your container is started on any machine, it will recreate exactly that environment. So you already know in advance that you will not have any issue with missing dependencies or incorrect versions.&lt;/p&gt;

&lt;p&gt;If you would like to learn more about Docker from the perspective of a Javascript developer I have written a brief &lt;a href="https://dev.to/alexeagleson/docker-for-javascript-developers-41me"&gt;introductory Docker tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning DevOps?
&lt;/h2&gt;

&lt;p&gt;DevOps is more challenging to learn on your own than some other programming topics, simply because at its core its about empowering development &lt;em&gt;teams&lt;/em&gt; at scale which is difficult to emulate when trying to learn as a solo developer.  &lt;/p&gt;

&lt;p&gt;Remember that we discussed how being a good DevOps engineer is about understanding the needs of the development team.  Being a good DevOps engineer requires you to have a very solid understanding of a lot of developer and sysadmin fundamentals including but not limited to: Git, Linux, bash scripting, and different cloud services (particularly the one the company you work for uses).  &lt;/p&gt;

&lt;p&gt;Make sure you have a solid understanding of Git and Linux commands before you go any further:&lt;/p&gt;

&lt;p&gt;What are the best free resources for learning the command line terminal?&lt;/p&gt;

&lt;p&gt;What are the best free resources for learning Git?&lt;/p&gt;

&lt;p&gt;After that depending on your code repository and hosting provider you'll want to familiarize yourself using their own tutorials and documentation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/en/actions/learn-github-actions" rel="noopener noreferrer"&gt;Learn Github Actions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.aws.training/" rel="noopener noreferrer"&gt;AWS training&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/training/azure/" rel="noopener noreferrer"&gt;Azure training&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reddit.com/r/devops/comments/rig8tm/devops_course_but_text_based_not_video/hoxa7t8/" rel="noopener noreferrer"&gt;This really good reddit post about DevOps resources&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kelseyhightower/kubernetes-the-hard-way" rel="noopener noreferrer"&gt;Kubernetes the Hard Way&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd like to end this by acknowledging that I am certainly no DevOps expert, the resources and descriptions I have included here are best effort and hopefully do not offend any serious DevOps people.  There are still further many advanced topics I have not covered that will inevitably come up if you take the plunge into the DevOps world.&lt;/p&gt;

&lt;p&gt;If you are interested would encourage your to at least familiarize yourself with additional tools like &lt;em&gt;Kubernetes, Ansible, Jenkins&lt;/em&gt; and &lt;em&gt;Terraform&lt;/em&gt;.  Their use cases are mostly beyond my needs as someone who is focused primarily on the development side, but are undoubtedly critical for anyone looking to dive further into DevOps.&lt;/p&gt;

&lt;h1&gt;
  
  
  Interviewing and Job Hunting
&lt;/h1&gt;

&lt;p&gt;In this section I'll be discussing general topics and frequently asked questions as they relate to the web development career space and software industry in general.&lt;/p&gt;

&lt;p&gt;These responses will inevitably be a bit more opinionated than the other sections, but I do my best not to state any advice as the "only way". There are an infinite number of different paths you can take to success in this industry, it's all a matter of varying degrees of speed and effectiveness.&lt;/p&gt;

&lt;p&gt;The vast majority of it is simply based on my own personal experiences and years spent in online developer communities and forums reading experiences from other developers at similar stages in their career.&lt;/p&gt;

&lt;h2&gt;
  
  
  How long until I will be ready to apply for jobs?
&lt;/h2&gt;

&lt;p&gt;Everyone is different of course and there is not going to be a single answer that applies to everyone. Some people will have more time in a day to invest into their learning.&lt;/p&gt;

&lt;p&gt;Some people will be learning in the evenings / weekends while supporting themselves with another job, others will have the freedom to make learning itself their full time job.&lt;/p&gt;

&lt;p&gt;The important thing to remember is that while the process will be faster for some, everyone has the capability to make it eventually if it's something they are genuinely interested in.&lt;/p&gt;

&lt;p&gt;My &lt;em&gt;extremely ballpark'd&lt;/em&gt; answer for the majority of people would be about one year. For those who can dedicate to learning full time, it could potentially be more like 6 months. Others who are extremely busy and only able to learn a few hours a week might be looking at closer to 2 years.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I know when I am ready to apply to jobs?
&lt;/h2&gt;

&lt;p&gt;This is a very common question, and the honest answer is that there is no specific threshold. Some companies are willing to hire people with very limited skills and experience who are willing to learn on the job, other companies have very high requirements for skill level before they are willing to hire someone.&lt;/p&gt;

&lt;p&gt;Often there is really no way of knowing which company is strict about the requirements they ask for, and job descriptions unfortunately are notorious for not actually defining the real requirements for the job.&lt;/p&gt;

&lt;p&gt;Many jobs that "require 5 years of experience" or "must know Angular" will end up hiring someone with 2 years experience who has never used Angular at all. The reality is that the market is very competitive and companies are often willing to settle for candidates that only tick &lt;em&gt;some&lt;/em&gt; of the boxes who have a good attitude and sound like they will be willing to learn and train in the areas they might be missing.&lt;/p&gt;

&lt;p&gt;The only way to know is to apply. I'm not saying to start applying right away before you can even put together a basic project, but if you have been learning for 6 months straight and get to a point where you are comfortable with the basics of HTML, CSS and Javascript then I would encourage you to think about applying for positions, even if you don't meet all the requirements.&lt;/p&gt;

&lt;p&gt;The "worst case" is you get to practice interviews and get a better understanding of what companies are really looking for. The "best case" is you get hired! Honestly, both cases are a win for you.&lt;/p&gt;

&lt;p&gt;For more information on preparing for your first job check out the What are the most important factors in getting hired? section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where do I find jobs?
&lt;/h2&gt;

&lt;p&gt;Your best resource will probably be &lt;a href="https://ca.linkedin.com/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. Keeping your LinkedIn profile up to date is critical for people looking for work.&lt;/p&gt;

&lt;p&gt;Start building your professional network however you can. Look for meetups, conferences, and talks in your area. Find ways to connect and start chatting with other developers. Many people find that some random network connection was the key they needed to get into their first job.&lt;/p&gt;

&lt;p&gt;Aside from that you should look up companies that you are interested in and view the "careers" page on their website. Often applying to a company directly is an effective tool. Make sure to include the reason the company interests you in your initial point of contact.&lt;/p&gt;

&lt;p&gt;If you are a student, do absolutely anything you get to get into an internship or a co-op program. The reality is that the most effective way to get a job is through existing professional experience, and internships and co-ops provide one of the easiest paths to get that experience. Do not pass up that opportunity under any circumstance.&lt;/p&gt;

&lt;p&gt;Lastly, while you're learning, remember to showcase your skills. Two great methods to do that are by blogging or recording videos.&lt;/p&gt;

&lt;p&gt;You can start to build a respectable network entirely online without actually meeting other developers in person this way.&lt;/p&gt;

&lt;p&gt;Remember you don't need to be an expert to write a blog. Keep your topics small and focused on things you have learned, and let the intention be to share what you have learned with others. You might be surprised at some of the contacts and opportunities you can get if you keep it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What programming language should I learn?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Why are there so many different programming languages?
&lt;/h2&gt;

&lt;p&gt;This is a great question, and there is no right answer for everyone. It really depends on what kind of work you want to do. You might wonder "why are there so many programming languages?" and the reason is that each different language is particularly good at something.&lt;/p&gt;

&lt;p&gt;Python is known for being a great first language to learn, it's good a relatively simple syntax that is easier for beginners to understand, and it has a lot of different practical use cases including task automation, data science (crunching numbers and statistics) and building web servers.&lt;/p&gt;

&lt;p&gt;If you want to get into mobile app development, then you'll want to learn Kotlin (for Android development) or Swift (for iOS development).&lt;/p&gt;

&lt;p&gt;If your goal is simply to get employed, then Javascript is definitely your best bet. Although it is region dependent (you'll want to search in your local area for what kind of jobs are available) in most parts of the world Javascript (and web development in general) remains the most in-demand skill, and all signs point to it remaining that way for the forseeable future.&lt;/p&gt;

&lt;p&gt;Everything these days is web driven, from apps on your phone to home appliances.&lt;/p&gt;

&lt;p&gt;Maybe companies use web frameworks to help speed development, organize their code and build apps more efficiently. Some you may have heard of include &lt;em&gt;React, Angular, Vue and Svelte&lt;/em&gt;. It's well worth it to learn at least one of these frameworks, but don't jump into them too quick, as each one is built on top of the fundamentals of HTML, CSS and Javascript and typically require a solid working knowledge base of those three in order to learn effectively.&lt;/p&gt;

&lt;p&gt;Which framework you choose is up to you, though if you are targeting employment make sure you search the jobs in your area. In the vast majority of the world, React jobs outnumber all other frameworks by a large margin (though there is a sizeable market for &lt;em&gt;Vue&lt;/em&gt; in Asia).&lt;/p&gt;

&lt;p&gt;If web development doesn't sound like your thing, maybe systems programming is more up your alley (embedded controllers, hardware devices, internet of things (IoT) and etc).&lt;/p&gt;

&lt;p&gt;To become a systems programmer there are many paths to take, but most start through the C programming language and build from there. It will be important to have a stronger grasp of computer science fundamentals in this field than in web development since you will be interacting with low level concepts like the operating system and memory directly.&lt;/p&gt;

&lt;p&gt;Check out the section called What are the best free resources for learning computer science? to find some great resources on learning systems programming concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if I fail?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What if I get overwhelmed?
&lt;/h2&gt;

&lt;p&gt;Learning software development is extremely challenging, for everyone. Any dev you see who makes it look easy almost certainly has years of practice and failure behind them, it's no different than any other skill that takes years to develop.&lt;/p&gt;

&lt;p&gt;Along the way you are almost certainly going to find days where nothing goes right, or everything seems way too overwhelming and it's impossible to keep up with.&lt;/p&gt;

&lt;p&gt;The only advice I can give here is to say that this is &lt;em&gt;perfectly normal&lt;/em&gt; and part of the process. Failing at building a project will teach you a lot more about that project then not starting it at all. Sometimes you'll find that you've bitten off more than you can chew, and that's okay.&lt;/p&gt;

&lt;p&gt;There's nothing wrong with taking a step back and slowing down. When you encounter a topic that seems too large to digest, see if you can break it down into small pieces. Take a day to learn more about just one small aspect of it. Then move on to the next thing. And the next thing.&lt;/p&gt;

&lt;p&gt;And remember, there's no set amount of time when you will have "learned something." New devs often say things like "I'll give myself six months to learn Javascript". It doesn't really work like that. I've been writing Javascript for years and I'm still learning. Your goals should reflect concrete tangible targets, focus on learning specific aspects of the languages, rather than the whole language itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the most important factors in getting hired?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How do I get a job when all companies want existing work experience?
&lt;/h2&gt;

&lt;p&gt;This is the real question right here. Honestly when it comes to software development, &lt;em&gt;&lt;strong&gt;finding your first job will the most difficult stage of your career by a significant margin&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Work Experience
&lt;/h3&gt;

&lt;p&gt;Those who are still students should do absolutely everything they can to take internships and co-op placements, having those will give you a massive leg-up over other devs in your peer group who don't when it comes to full-time hiring after graduation.&lt;/p&gt;

&lt;p&gt;If you're looking at bootcamps then make sure you pick one specifically that offers networking support and helps connect you with employers after graduation.&lt;/p&gt;

&lt;p&gt;For the rest of us getting into development later in life, the best thing you can do is allow the reality to sink in that it's going to be very challenging, accept it, and do your best not to allow it to deter you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The vast majority of your applications will be rejected.&lt;/strong&gt; And that's perfectly okay, it's almost certainly due to a lack of experience, not a lacking in skill or ability on your part.&lt;/p&gt;

&lt;p&gt;It's important to train yourself not to take it personally. Rejection does not mean &lt;em&gt;"I'm not good enough"&lt;/em&gt; it simply means that particular companies needs didn't align with your skills at that moment.&lt;/p&gt;

&lt;p&gt;That's it and nothing more.&lt;/p&gt;

&lt;p&gt;The fact is that most companies are risk averse. They see someone new to the field with no proven track record of working for an organization and they don't have the confidence that you have the skills and abilities required to contribute. The reality is that if you think you do, you probably do -- but unfortunately many companies just aren't willing to take that risk.&lt;/p&gt;

&lt;p&gt;So since this seems like a catch-22 scenario where you can't get experience, how exactly &lt;em&gt;do&lt;/em&gt; you break into the field?&lt;/p&gt;

&lt;p&gt;The best advice for new devs is that you have to look at it like a numbers game. If there are 100 companies out there, and 1 of them is willing to take a chance on new devs, then you need to apply to 100 companies to get your job.&lt;/p&gt;

&lt;p&gt;Apply like crazy! Come up with a solid but generic resume, and start sending it out. Target all the web dev jobs in your local region, look for companies online that are hiring remote. Make the expectation that most will reject you and be &lt;em&gt;perfectly okay with that&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Every failed interview is experience at interviewing. The more you do the more comfortable you will get. Get your resume into as many hands as possible and do as many interviews as you can.&lt;/p&gt;

&lt;p&gt;Be completely honest about your skills. When asked a question you don't know the best answer is always "I'm not familiar with that, but I would love to learn more about it."&lt;/p&gt;

&lt;p&gt;All you need to remember is this: you only need &lt;em&gt;one&lt;/em&gt; company to say yes, and you're in. Once you've got that, then you'll have work experience, and everything from that point on just gets easier and easier.&lt;/p&gt;

&lt;p&gt;Now that we've talked about work experience, let's look at some of the other critical factors at play when it comes to getting hired.&lt;/p&gt;

&lt;h3&gt;
  
  
  Networking and Relationships
&lt;/h3&gt;

&lt;p&gt;When I say &lt;em&gt;networking&lt;/em&gt; I'm not talking about &lt;a href="https://en.wikipedia.org/wiki/Social_group" rel="noopener noreferrer"&gt;networking&lt;/a&gt; I'm talking about &lt;a href="https://en.wikipedia.org/wiki/Computer_network" rel="noopener noreferrer"&gt;networking&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Which is unfortunate because if you're like a lot of people (myself included) learning the &lt;a href="https://en.wikipedia.org/wiki/OSI_model" rel="noopener noreferrer"&gt;OSI model&lt;/a&gt; is a lot easier than building a professional network. Like many other things in life, the earlier you start the better off you'll be in the long run.&lt;/p&gt;

&lt;p&gt;One of the most helpful things when I started to internalize this was the realization that your network doesn't necessarily mean "people you've met in person". You can build a network entirely online through contacts you make on social networks, reddit, Github, Stack Overflow, Discord, etc.&lt;/p&gt;

&lt;p&gt;Particularly with the rise of remote work, you never know if the person you were talking to or helping out online two weeks ago could be the person who connects you with your next job. It happens all the time.&lt;/p&gt;

&lt;p&gt;I should clarify that having a network of developers is &lt;em&gt;absolutely not required&lt;/em&gt; for finding a job. The good old fashioned method of sending out 100 copies of your resume to 100 different companies still works great too. In fact if your goal is to get employed realistically you should be pursuing &lt;strong&gt;both&lt;/strong&gt; these methods.&lt;/p&gt;

&lt;p&gt;If you fancy yourself a writer or a speaker, don't sleep on blogs and Youtube tutorials. It's a common misconception that you need to be an expert. Certainly do your homework, but after spending some time getting confident enough with a small topic (even something as simple as loops or if statements) &lt;a href="https://dev.to"&gt;try writing a blog about it!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is something many bootcamps heavily encourage students to do. It can be a great way to build confidence and also expand your personal network.&lt;/p&gt;

&lt;p&gt;Lastly, don't sleep on LinkedIn. Yes, everyone is on there to self promote, and yes the news feed can be really difficult to stomach. The good news is you don't need to use it for that. Don't even look at it. All you need is your own profile up to date, and with some experience under your belt, the recruiters will be reaching out &lt;em&gt;to you&lt;/em&gt; rather then the other way around.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Knowledge and Interview Performance
&lt;/h3&gt;

&lt;h2&gt;
  
  
  What can I expect from an interview?
&lt;/h2&gt;

&lt;p&gt;The standards for developer interviews are all over the map.&lt;/p&gt;

&lt;p&gt;One company might simply want to chat and talk about projects you have worked on. Another might want to run you through technical aptitude tests. Another might give you a take-home project to work on in your spare time.&lt;/p&gt;

&lt;p&gt;You should be prepared for any of these and more. As a junior developer your expectation should be a strong working knowledge of HTML, CSS and Javascript, Git, and the command line.&lt;/p&gt;

&lt;p&gt;You'll want to supplement that with whatever additional technologies and tooling the position is asking for. So if they are hiring for a junior React position, obviously you would want to be familiar with the basics of React as well.&lt;/p&gt;

&lt;p&gt;I think it's really important to taper your expectations and be ready to encounter scenarios where companies are hiring for junior positions, but after getting into the interview it becomes clear they are actually looking for a very experienced developer with the hopes of only paying them as a junior.&lt;/p&gt;

&lt;p&gt;Unfortunately all you can really do in these scenarios is your best, ask lots of questions, be honest about your skills, and don't let it discourage you.&lt;/p&gt;

&lt;p&gt;Companies will often be willing to relax their skill requirements a bit if they find someone with a good attitude who appears they are ready and willing to learn. Allow yourself to be that person.&lt;/p&gt;

&lt;p&gt;Don't forget you are interviewing them as well. Ask questions to try and get an idea of their workload, company culture, what an average day looks like etc.&lt;/p&gt;

&lt;p&gt;And don't hesitate to answer a question with &lt;strong&gt;"I don't know"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's a much better answer than making something up or guessing wrong. You can follow it up with something like "&lt;em&gt;I don't know, but here's something similar I've encountered before"&lt;/em&gt; or &lt;em&gt;"I don't know, but here's how I would start looking for the answer if I encountered this"&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interview Styles
&lt;/h3&gt;

&lt;p&gt;Show the interviewer that you are proactive when it comes to encountering situations where you don't know the answer, because as we've already discussed, these situations will happen &lt;em&gt;almost every day&lt;/em&gt; in a developers career. Embrace that fact and leverage it in your interview.&lt;/p&gt;

&lt;p&gt;Let's take a look at some of the different styles of interviews you might encounter in your job search: Here's a realistic look at three different hypothetical interview approaches at three different companies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Company A&lt;/strong&gt;: Tell me about some projects you've worked on. Tell me about why you chose the tools you did (discussion style).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Company B&lt;/strong&gt;: Open up this online browser tool and use Javascript/Python/whatever to reverse a string (whiteboard style).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Company C&lt;/strong&gt;: Here's an assignment to build a landing page for a website with an interactive menu. Take it home and work on it and then send us the results tomorrow (take home style).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course there are plenty more scenarios, but this captures sort of the three main "styles".&lt;/p&gt;

&lt;p&gt;The first &lt;strong&gt;(discussion style)&lt;/strong&gt; is based on a conversation of you discussion your knowledge and experience.&lt;/p&gt;

&lt;p&gt;Personally I find these the best for junior positions. Most people starting out have a very difficult time programming while under pressure (even for simple stuff) and given an opportunity to discuss they knowledge, the interviewer can ask questions and probe to make sure they actually understand the things they're talking about.&lt;/p&gt;

&lt;p&gt;The second &lt;strong&gt;(whiteboard style)&lt;/strong&gt; may be done with actual code or may be done on a board where you simply use a marker. The interviewer usually isn't necessarily looking for a correct or complete solution, but an approach that shows an understanding of the problem, even if there are minor errors or edge cases.&lt;/p&gt;

&lt;p&gt;Also important with this style of interview is the candidates ability to ask good questions and clarify assumptions. Sometimes there will even be missing information in the question intentionally and the candidate is supposed to get that information by asking questions. Despite being a coding challenge, this style of interview is very much focused on a discussion of the problem. Typically, depending on the complexity, you'll want to discuss it for up to half the allotted time before you even begin to write code.&lt;/p&gt;

&lt;p&gt;When you get up in the higher levels and more competitive companies (often referred to as &lt;a href="https://en.wikipedia.org/wiki/Big_Tech" rel="noopener noreferrer"&gt;FAANG or MANGA&lt;/a&gt; companies), these styles of interviews get more common and much more difficult than reversing strings.&lt;/p&gt;

&lt;p&gt;If you're interested in pushing for those top tier jobs, check out the DSA, Leetcode and Systems Design section for more information.&lt;/p&gt;

&lt;p&gt;The final interview style &lt;strong&gt;(takehome style)&lt;/strong&gt; typically involves giving the candidate a small challenge to do on their own time. This can have the benefit of allowing you to work at your own pace without the pressure of someone watching, but it also has the downside of being time consuming, and the majority of companies will not be paying for your time.&lt;/p&gt;

&lt;p&gt;Early in your career I can understand agreeing to take home interviews when you are simply trying to get any job you can, but as you progress in your career you'll find yourself passing on this style of interview as you simply don't have the time to build multiple small projects for companies in your limited spare time. Fortunately this interview style is the least common of the three, and rarely used by the top tech companies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Soft Skills
&lt;/h3&gt;

&lt;p&gt;Don't sleep on soft skills when it comes to finding a job in the industry. Technical skills will certainly help get you the job, but good soft skills will often fast track you should levels and promotions faster than technical skills alone.&lt;/p&gt;

&lt;p&gt;What do I mean when I say soft skills? I'm talking about things like &lt;em&gt;positive attitude&lt;/em&gt;, the ability to &lt;em&gt;communicate clearly&lt;/em&gt; (both spoken and written) and _willingness to share knowledge and help others.&lt;/p&gt;

&lt;p&gt;Good mentors and teachers are often looked on very highly by companies, because it shows you can contribute to improving the level of knowledge and skill within the company. If this is something you have interest and experience in (even if it's just something like blogging or videos) make sure that it's something you share during the interview.&lt;/p&gt;

&lt;p&gt;Many companies have what's called a &lt;em&gt;cultural interview&lt;/em&gt; as one fo the steps in your interview process. While some companies might state they have metrics to quantify this value, the reality is that many simply evaluate you on their "feeling" about how well you would fit in with the company based on the attitude and disposition you display during the interview.&lt;/p&gt;

&lt;h3&gt;
  
  
  Education
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Do I need to get a degree?
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Do I need to go to college?
&lt;/h2&gt;

&lt;p&gt;One of the great things about a career in software development is that it does not &lt;em&gt;require&lt;/em&gt; you to complete a four year degree or college program to get hired. I can't speak for percentages, but many companies are more concerned with a candidates skill level and ability to produce working software than their educational background.&lt;/p&gt;

&lt;p&gt;I don't want to discount how much of a benefit a university or college degree can bring however. If you are someone who has the time and resources, then in the long term a computer science degree will almost certainly be worth the investment you make into it, for a couple of reasons: First is that there are still many companies out there that do look for a degree before hiring a candidate, and second that the fundamental knowledge you gain in computer science will be incredibly valuable in teaching you &lt;em&gt;problem solving skills&lt;/em&gt; that translate directly to work you do in the field.&lt;/p&gt;

&lt;p&gt;If you do go the college route one of the biggest benefits career-wise are the co-op and internship programs, do not pass up those opportunities if they are available to you, they are one of the most effective ways of breaking through that initial barrier of getting your first job, which most new devs describe as the most difficult hurdle of their career. See How do I get a job when all companies want existing work experience?.&lt;/p&gt;

&lt;p&gt;Still, for those that do not have the means to complete a full degree, if you are motivated and disciplined enough it is absolutely possible to teach yourself everything you need to know through a combination of free online resources and building your own practice projects with the knowledge you gain from those resources.&lt;/p&gt;

&lt;p&gt;Another popular option these days is bootcamps. They can be a great middle ground between self teaching and a college degree. They are good for those people who feel they may not be able to motivate or direct themselves enough and benefit from having a very strict curriculum to follow.&lt;/p&gt;

&lt;p&gt;Bootcamps have a reputation of being very challenging and being one of those things that really gives back the effort you put into it, so make sure you are ready to invest the huge amount of time (and often money) it takes to get the full benefits. Also make sure you do your research on the quality of the bootcamps, you'll find the full array of well regarded ones and poor quality bootcamps. If possible try to find one that also includes help with job placement as part of the package.&lt;/p&gt;

&lt;h3&gt;
  
  
  Luck
&lt;/h3&gt;

&lt;p&gt;Let's be honest, when you ask many people how they got their first job they'll say &lt;em&gt;"well, I was lucky..."&lt;/em&gt; and proceed to tell some anecdote about their good fortunate.&lt;/p&gt;

&lt;p&gt;As they say, &lt;em&gt;luck is the intersection of preparation and opportunity&lt;/em&gt;. Many of these people who describe themselves as lucky had done preparation in advance that allowed them to take these opportunities when they presented themselves.&lt;/p&gt;

&lt;p&gt;Allow yourself to accept that there's always going to be some luck involved, but you can dramatically improve your chances of that luck finding you if you're well prepared.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which factors most influence potential income?
&lt;/h2&gt;

&lt;p&gt;I've grouped these two questions together as they often go hand in hand. How much you as a candidate appeal to a company has a direct impact on your potential value.&lt;/p&gt;

&lt;p&gt;As you can imagine, this is a very popular question, and like many other complex questions, the most accurate answer is going to be &lt;em&gt;"it depends"&lt;/em&gt;... but let's take some time to break down as best we can into exactly "what" it depends on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Location
&lt;/h3&gt;

&lt;p&gt;Not necessarily a huge factor when it comes to &lt;em&gt;getting&lt;/em&gt; a job -- but quite possibly the &lt;strong&gt;most&lt;/strong&gt; important factor when it comes to income. Without a doubt, both average and top end software development salaries the U.S. dwarf pretty much every other country.&lt;/p&gt;

&lt;p&gt;That's not to say they aren't still &lt;em&gt;well above average&lt;/em&gt; in pretty much every country, it's simply pointing out just how much "above" that already high baseline they are in the U.S. You can still live extremely comfortably as a software developer in pretty much any country in the world.&lt;/p&gt;

&lt;p&gt;Here's an &lt;a href="https://codesubmit.io/blog/software-engineer-salary-by-country/" rel="noopener noreferrer"&gt;aggregate by country from Codesubmit&lt;/a&gt; showing the different average values between countries. The actual values themselves are less important than the variance between countries.&lt;/p&gt;

&lt;p&gt;For developers in the U.S., here is the data directly from the &lt;a href="https://www.bls.gov/oes/current/oes151252.htm#nat" rel="noopener noreferrer"&gt;U.S. Bureau of Labor Statistics&lt;/a&gt; directly. Similar &lt;a href="https://www.jobbank.gc.ca/marketreport/wages-occupation/22548/ca" rel="noopener noreferrer"&gt;metrics from the Government of Canada&lt;/a&gt; here.&lt;/p&gt;

&lt;p&gt;If you're outside North America you should be able to find data from your government's statistics reporting with a quick Google search.&lt;/p&gt;

&lt;p&gt;Of course there are tons of factors that go into total income. Cities with significantly higher salaries also have higher costs of living, and there are many other quality of life considerations to take into account as well.&lt;/p&gt;

&lt;p&gt;Nevertheless, even when you account for regional cost of living, there's still pretty much no question that developers whose only goal is to maximize income should be aiming to relocate to the U.S.&lt;/p&gt;

&lt;p&gt;That said, this particular advice really only applies to the small subset of folks who aren't already in the U.S. and are also young enough and motivated enough to uplift their entire lives.&lt;/p&gt;

&lt;p&gt;For the rest of us (myself included in Canada) there are plenty of other factors listed ahead to consider to help maximize potential earnings without the need to relocate. The rise of remote work is (slowly) shifting the balance and bringing salaries up in non-U.S. countries, and there are more opportunities than ever to work remotely for a U.S. company while living in another country.&lt;/p&gt;

&lt;h3&gt;
  
  
  Product
&lt;/h3&gt;

&lt;p&gt;What kind of product does the company you're applying to develop? Oftentimes in the tech world, depending on the company's market, they either view software developers as "revenue generating" or an "operating cost".&lt;/p&gt;

&lt;p&gt;Not surprisingly, companies that view developers as a source of increased revenue tend to pay more than companies that look at devs as a cost.&lt;/p&gt;

&lt;p&gt;Take tech companies like Facebook for example. The more developers hey hire, potentially the more features they can release and the more revenue they can generate. Hiring good devs gives them a direct line to more money, and as such they tend to pay more.&lt;/p&gt;

&lt;p&gt;Alternatively consider a major restaurant chain. They need developers of course to manage their websites, maybe the software in their restaurants, and any number of internal tools they build to help manage their company, but ultimately a business like that is going to treat devs more as a "cost of doing business" rather than a source of revenue.&lt;/p&gt;

&lt;p&gt;So when seeking higher paying jobs, make sure you are considering the company's product. Is the main product or service they offer software based? If so chances are they're going to value their developers higher than a brick-and-mortar business, and you're likely to get a better offer from them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Size and Funding
&lt;/h3&gt;

&lt;p&gt;Smaller companies for reasons that should be obviously simply cannot afford to pay the big software salaries that larger companies can.&lt;/p&gt;

&lt;p&gt;Working for a small company can be a great experience though, you'll often be able to have a much bigger impact on the product and be involved in more major decisions, but in doing so there is often a price to pay income as compared to the larger companies out there.&lt;/p&gt;

&lt;p&gt;That said, an exception to this rule can be small startups that are well funded. When a software focused startup company receives a large round of &lt;a href="https://www.investopedia.com/terms/v/venturecapital.asp" rel="noopener noreferrer"&gt;VC funding&lt;/a&gt;, often the biggest chunk of that funding is intended to go directly into hiring more staff to scale their product to a wider market -- so get in there and get your piece!&lt;/p&gt;

&lt;h3&gt;
  
  
  Base Salary vs Equity
&lt;/h3&gt;

&lt;p&gt;This topic is way bigger than I can possibly go into (and I'm no expert either) so I'll simply link this &lt;a href="https://blog.pragmaticengineer.com/equity-for-software-engineers/" rel="noopener noreferrer"&gt;great blog post on the topic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Suffice it to say that you short of &lt;em&gt;guaranteed stock&lt;/em&gt; for an already &lt;em&gt;publicly traded company&lt;/em&gt;, you are often best to consider any private equity or options as &lt;strong&gt;zero value&lt;/strong&gt; when it comes to negotiating your salary.&lt;/p&gt;

&lt;p&gt;Because in the case of startups (early stage ones in particular) most often that's exactly what it ends up being worth.&lt;/p&gt;

&lt;p&gt;Having some ownership in the product you work on is great, but please don't let a company take advantage of you with promises of great value "someday" when they do public. Too many great devs have been burned by this. &lt;strong&gt;Make sure you get the base annual salary that you need first&lt;/strong&gt;, no matter how small the company, if their product is solid they should be able to pay their talent. Full stop.&lt;/p&gt;

&lt;p&gt;Once you've got that nailed down, then you can comfortably discuss options on top of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What other factors should I consider when applying to a company?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Remote Friendliness
&lt;/h3&gt;

&lt;p&gt;Is the company you're applying to remote friendly? Do they allow permanent work from home? Hybrid model?&lt;/p&gt;

&lt;p&gt;Remote work has become more and more common. Even for juniors starting out it's not unrealistic to aim for a remote job.&lt;/p&gt;

&lt;p&gt;If it's something that's important to you, make sure you are upfront about it with the company before the interview process begins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Company Culture
&lt;/h3&gt;

&lt;p&gt;Before beginning the interview or even applying to a company, try and gather as much information you can about what it's like to work at the company.&lt;/p&gt;

&lt;p&gt;Ask on developer communities like Reddit, Discord, etc if anyone has experience or anecdotes about what it's like to work for those companies.&lt;/p&gt;

&lt;p&gt;Check sites like &lt;a href="https://www.glassdoor.com" rel="noopener noreferrer"&gt;Glassdoor&lt;/a&gt;, &lt;a href="https://www.teamblind.com/" rel="noopener noreferrer"&gt;Blind&lt;/a&gt; and &lt;a href="https://layoffs.fyi/" rel="noopener noreferrer"&gt;Layoffs.fyi&lt;/a&gt; to get accounts from people who have worked at these companies.&lt;/p&gt;

&lt;p&gt;try to filter out the most extreme positives and negatives from these sites if you can. Companies can and will find ways to get paid positive reviews. Focus on the ones that sound the most like a "slice of life" honest account if you can. Obviously the bigger the company there more you'll find the easier it will be to get an impression.&lt;/p&gt;

&lt;p&gt;Finally make sure you ask in your interview as well. Don't just say &lt;em&gt;"what is your company culture like?"&lt;/em&gt; because you'll just get a canned answer.&lt;/p&gt;

&lt;p&gt;Ask specific questions like &lt;em&gt;"what time do most developers start and finish work each day?"&lt;/em&gt; to try get an idea how much team pressure there might be to "work extra" even if it's not officially "required".&lt;/p&gt;

&lt;p&gt;Another great question is &lt;em&gt;"what is your training/onboarding process like?"&lt;/em&gt;. A question like that can give a good idea whether they've really got their act together when it comes to training new hires, or whether it sounds like you'll just be thrown into a project with nothing more than a "good luck!".&lt;/p&gt;

&lt;p&gt;There's tons more of course. Really the questions you want to ask are the ones that reflect things that are &lt;em&gt;important to you&lt;/em&gt;. They may not be the same things that are important to someone else. Here's a &lt;a href="https://arc.dev/developer-blog/questions-to-ask-at-an-interview/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt; with some more examples. Consider picking 2-3 that best reflect the kind of work experience you are looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if I find a job, but it's not what I was expecting?
&lt;/h2&gt;

&lt;p&gt;This section of the post is primarily aimed at those developers who have been been able to find work, but unfortunately find themselves struggling with unrealistic expectations, or pressure to work unpaid overtime, lack of support, or at worst -- straight up verbal harassment including insults, mocking or derision.&lt;/p&gt;

&lt;p&gt;Let me tell you straight up so there can be absolutely no misinterpretation: &lt;strong&gt;GOOD JOBS, AND GOOD COMPANIES, DO NOT TREAT PEOPLE THIS WAY. EVER. PERIOD. FULL STOP.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are no exceptions to that statement.&lt;/p&gt;

&lt;p&gt;Is it possible that maybe you aren't keeping up, or you are struggling? Absolutely! Maybe it could be that you weren't quite ready for thr job you were hired for. That's an unfortunate reality, but it's not a death sentence.&lt;/p&gt;

&lt;p&gt;There are ways of approaching this situation that good managers and good companies will be have plenty of experience with.&lt;/p&gt;

&lt;p&gt;One thing I read recently that I think is really critical for developers to remember is this: &lt;em&gt;&lt;strong&gt;nothing said in a performance review should ever come as a surprise&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you wake up tomorrow and have a performance review (whether it's an official one, or simply your manager talking about your performance 1-on-1) and you're told that you've failed to meet expectations, what it really means is that your manager has failed at properly addressing it earlier on when they should have (unless they follow that statement with a plan to support you).&lt;/p&gt;

&lt;p&gt;A good manager will approach the topic in a positive way, willing to work with you to come up with a solution. Do you need more training time? More time to shadow other developers? Are the tickets you are being assigned currently too far above your level and you need to spend more time tackling smaller ones to build experience?&lt;/p&gt;

&lt;p&gt;These are the kind of questions good companies will encourage managers to ask in performance reviews. You are part of the team and that's how you should expect to be treated.&lt;/p&gt;

&lt;p&gt;Following a discussion like this, after whatever the agreed upon period is (whether weeks or months) if you still are unable to work out an approach that helped you work at the level expected of you -- &lt;strong&gt;then&lt;/strong&gt; maybe the tough discussions might start about your fit for the role.&lt;/p&gt;

&lt;p&gt;But the key point being made here is that it &lt;em&gt;should never, ever, come as a surprise.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If what I am describing here sounds totally unrealistic or like some kind of "dream company," and you find yourself in a position where you think that mistreatment and unrealistic expectations are the norm -- then I'm happy to tell you that you simply have &lt;a href="https://en.wikipedia.org/wiki/Stockholm_syndrome" rel="noopener noreferrer"&gt;Stockholm syndrome&lt;/a&gt; (I mean that in the nicest way possible).&lt;/p&gt;

&lt;p&gt;There are no shortage of companies out there that don't treat people this way.&lt;/p&gt;

&lt;p&gt;There has &lt;em&gt;never been a better time to be a developer&lt;/em&gt;. I would encourage you to polish off the resume and start your search for that career you deserve.&lt;/p&gt;

&lt;p&gt;There's not too many incredibly strong opinions I hold about the industry, but the belief that no matter your skill level that &lt;strong&gt;&lt;em&gt;everybody deserves to be treated and spoken to with respect&lt;/em&gt;&lt;/strong&gt; is one of the few complete dealbreakers for me. I'll put up with a lot of stuff, but that's where I draw the line. I think everybody should.&lt;/p&gt;

&lt;p&gt;The more we put our foot down for behaviour like that, the more companies will be forced to address it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Negotiating an Offer
&lt;/h3&gt;

&lt;p&gt;A lot of people will tell you there is no harm in negotiating an offer. That's not &lt;em&gt;exactly&lt;/em&gt; true, but it's still good advice.&lt;/p&gt;

&lt;p&gt;There's really two most likely scenarios that will occur when you try to negotiate an offer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The company will accept or counter (good)&lt;/li&gt;
&lt;li&gt;The company will stay firm at current offer (fine)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are the most likely scenarios and since both are options in your favour, that's the reason most people will encourage you to negotiate.&lt;/p&gt;

&lt;p&gt;There is a rare third scenario where the company &lt;em&gt;rescinds the initial offer entirely&lt;/em&gt; which can happen -- but the most oft repeated advice to that is that &lt;em&gt;"a company that does that probably isn't a company you want to work for anyway."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Whether you should negotiate or not really is a personal choice. I think there are good reasons and scenarios where you might choose not too (the offer is in the range you were expecting and the company is one you are interested to work for.) I personally would never fault someone for accepting an off as-is in that scenario.&lt;/p&gt;

&lt;p&gt;Other factors to consider is the &lt;em&gt;amount&lt;/em&gt; and your &lt;em&gt;leverage&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A good rule of thumb is 10%. Most companies won't be too surprised if a candidate counters at 10% above the offer that was made to them. If they company is genuinely interested in you, 10% if probably a small price to pay to close the deal.&lt;/p&gt;

&lt;p&gt;More than that and you should probably make sure you are confident in yourself and have leverage.&lt;/p&gt;

&lt;p&gt;Leverage is basically &lt;em&gt;evidence to show value&lt;/em&gt;. The further you are in your career the more track record of proven value you will have and the more leverage you will have. Negotiating up as a new graduate with no experience is possible, but much riskier.&lt;/p&gt;

&lt;p&gt;Another way to get leverage is having multiple offers. If you are fortunate enough to have more than one offer from more than one company, and the one you would prefer to work for has offered less, you can use the other offer as leverage in a (very friendly and professional) communication that you have another offer, but would &lt;em&gt;prefer&lt;/em&gt; to work for the other company if they would be able to match $X amount.&lt;/p&gt;

&lt;p&gt;The final point to note is that when you negotiate or try and leverage multiple offers against each other you have to be willing to lose the offer. That's part of the risk. If you aren't willing to walk away, don't take the risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pay Bands
&lt;/h3&gt;

&lt;p&gt;Make sure you are as familiar as possible with the pay bands (salary range) of the role you are applying to at the company your are interviewing with.&lt;/p&gt;

&lt;p&gt;Remember that it's in your best interest not to provide this range yourself as you are much more likely to undersell yourself.  Any respectable company or recruiter should be able to provide you with the potential pay range for the role you are applying for, though it may take some pressure on your end to get it out of them, it's well worth it.&lt;/p&gt;

&lt;p&gt;If they will not provide you with a range in advance it may be in your best interest to walk away unless you are desperate for the job.  Interview processes can be very lengthy and time consuming and there is nothing worth than getting to the offer stage and finding out you had a completely different expectation than the company did.  &lt;/p&gt;

&lt;p&gt;Be sure to educate yourself in advance using tools like levels.fyi.  Remember that software developer pay range is &lt;em&gt;extremely&lt;/em&gt; location dependent so you need to ensure you are filtering not only by the company you are applying to, but also your location.&lt;/p&gt;

&lt;p&gt;Although levels is the best indicator, particularly for tech companies, you should also make sure to check &lt;a href="https://www.glassdoor.ca/index.htm" rel="noopener noreferrer"&gt;Glassdoor&lt;/a&gt; and &lt;a href="https://www.teamblind.com/" rel="noopener noreferrer"&gt;Blind&lt;/a&gt; as well just to get the most well rounded number you can.  &lt;/p&gt;

&lt;h3&gt;
  
  
  DSA, Leetcode and Systems Design
&lt;/h3&gt;

&lt;p&gt;If your goal is to maximize your income, then you've arrived at your destination.&lt;/p&gt;

&lt;p&gt;I mean, full disclosure -- I don't work for a &lt;a href="https://en.wikipedia.org/wiki/Big_Tech" rel="noopener noreferrer"&gt;FAANG&lt;/a&gt; company. I haven't done the grind myself and don't intend to. I work for a great company and could hardly ask for a better career, but I am familiar with the requirements and can certainly point folks in the right direction for all the resources they need to study to take that leap.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DSA&lt;/em&gt; stands for &lt;a href="https://en.wikipedia.org/wiki/Data_structure" rel="noopener noreferrer"&gt;data structures&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Algorithm" rel="noopener noreferrer"&gt;algorithms&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you studied computer science in college/university then this is probably old news to you, but if you're someone who has been just learning web development on their own in their spare time it might seem a bit overwhelming. And that's okay! Let's break it down.&lt;/p&gt;

&lt;p&gt;In order to understand why DSAs are important you need to kind of take a step back and look at the big picture of software engineering as a whole rather than web development in particular.&lt;/p&gt;

&lt;p&gt;Regardless of whether you've learned Javascript, or Python, or C++, or Java, or Rust, or Ruby, or C# or whatever -- each programming language when you boil them down to their core elements is really just a different flavour of approaching the same topic: representing and manipulating data.&lt;/p&gt;

&lt;p&gt;How that data is stored covers the &lt;em&gt;data structures&lt;/em&gt; part and how it is manipulated falls into the &lt;em&gt;algorithms&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Big tech companies like the &lt;em&gt;FAANG/MANGA&lt;/em&gt; crew and similar monoliths are in a very unique position. The small mom and pop shops in your local area have to do a lot of work to seek out developers that can both do all the odds and ends dev work that needs to be done for average to below average pay -- but the big bois can sit back while every new grad and they dog climb over themselves to try to work for them.&lt;/p&gt;

&lt;p&gt;This endless supply of potential dev talent means they have the luxury of being a lot pickier about who they hire than most companies.&lt;/p&gt;

&lt;p&gt;But how do they decide how to filter out the best of the best?&lt;/p&gt;

&lt;p&gt;Well as it happens, they've all done their research, and it seems like the most consistent way of identifying top talent in the software industry isn't necessarily based on work experience or knowledge of any one particular programming language -- it's a candidate's base understanding of fundamental computer science topics like data structures and algorithms.&lt;/p&gt;

&lt;p&gt;The idea behind it is that if you can understand the &lt;em&gt;thought processes&lt;/em&gt; behind the underlying concepts, the actual language you write the code in is pretty irrelevant.&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;much&lt;/strong&gt; easier to teach a strong logical thinker how to &lt;strong&gt;write Python&lt;/strong&gt; than it is to teach a Python developer &lt;strong&gt;how to think&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So with that background established we've paved the way for the birth of platforms like &lt;a href="https://leetcode.com/" rel="noopener noreferrer"&gt;Leetcode&lt;/a&gt; to exist, which despite the stupid name, is unquestionably the most important resource available to you as a developer if your long term goal is to maximize your income.&lt;/p&gt;

&lt;p&gt;All the top paying tech companies right now like Amazon, Apple, Facebook, etc draw most of their engineering interview questions directly from the pool of questions listed on this site. Whether similar and adjusted slightly, or in many occasions almost identically word for word.&lt;/p&gt;

&lt;p&gt;There's no tricks or cheating involved in having access to them in advance. The whole idea is that they are challenging enough to require weeks or months of practice to internalize the concepts. If you are able to do so successfully then it demonstrates to these companies that you are capable of a level of logical thinking that they expect, and so having the solutions practices and even memorized is enough to identify you as a valuable candidate.&lt;/p&gt;

&lt;p&gt;This is what's called the &lt;em&gt;Leetcode grind&lt;/em&gt;, and as painful as it can be, it's widely considered to be the most valuable way you can spend your time if your goal is maximizing your income. Grind out a few problems per day, work your way up into the mediums and hards, and you'll be ready for your &lt;em&gt;FAANG&lt;/em&gt; interview in no time.&lt;/p&gt;

&lt;p&gt;For a new grad or someone with no experience, this is often enough to get your foot in the door. For those developers targeting the higher level positions at the big tech companies you'll also need to spend time studying &lt;em&gt;system design&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Systems design in a nutshell is simply an outline of &lt;em&gt;all the factors you need to consider when building a large scale software system&lt;/em&gt;. Consider a trivial example of a website. I make a website with HTML, CSS and Javascript and host it online with Github pages, or purchase some web hosting with Godaddy and upload my files. People love it! Every day I get more and more visitors.&lt;/p&gt;

&lt;p&gt;Tomorrow I log on and my site is down. It got too popular! Turns out I only had 1GB of bandwidth with my hosting provider and I blew through it overnight when my site went viral. Damn. How big were the images I was hosting? What was my &lt;a href="https://en.wikipedia.org/wiki/Web_cache" rel="noopener noreferrer"&gt;caching&lt;/a&gt; setup? What were my plans for &lt;a href="https://en.wikipedia.org/wiki/Scalability" rel="noopener noreferrer"&gt;scalability&lt;/a&gt;? I didn't have any?&lt;/p&gt;

&lt;p&gt;Well no wonder everything fell apart.&lt;/p&gt;

&lt;p&gt;In a &lt;em&gt;systems design interview&lt;/em&gt; you'll get an example of some kind of business idea or product that might need to be built. You'll be expected to be able to discuss as many factors or considerations that need to be accounted for in building that system.&lt;/p&gt;

&lt;p&gt;You'll need to discuss both functional requirements (what features does this product need to support?) as well as infrastructure (how can we handle potentially large amounts of traffic and data storage requirements?).&lt;/p&gt;

&lt;p&gt;What solutions are available? What are the pros and cons of each one?&lt;/p&gt;

&lt;p&gt;If you're still not sure exactly what we're talking about, here's a couple classic examples based on real interview questions you might encounter on this subject:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/DSGsa0pu8-k" rel="noopener noreferrer"&gt;How would you design a parking lot?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/fMZMm_0ZhK4" rel="noopener noreferrer"&gt;How would you design a URL shortener service?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These videos will give you a great idea of how you will be expected to answer questions like this in a big tech interview.&lt;/p&gt;

&lt;p&gt;Lastly, before moving on I should like you with a couple of the foremost standard resources in this space. The book &lt;a href="https://www.crackingthecodinginterview.com/" rel="noopener noreferrer"&gt;Cracking the Coding Interview&lt;/a&gt; is considered the gold standard. It's not free unlike most other resources I've linked, but since you're presumably only here because you're looking to maximize your earning potential, $40 is probably a pretty small price to pay to get you there.&lt;/p&gt;

&lt;p&gt;For systems design there are great books too, but honestly YouTube is pretty much your best friend for this one. It's really great to just listen to people walk through their thought process for different problems. Just watch to avoid the crypto shills like &lt;em&gt;TechLead&lt;/em&gt; which I will not link out of principle.&lt;/p&gt;

&lt;p&gt;A simple rule of thumb to follow is that if the person is only speaking about the topic and answering exactly the subject you searched for, you're probably in good hands. If they're starting or ending their video encouraging you to "check out" something totally unrelated you should proceed with extreme caution.&lt;/p&gt;

&lt;p&gt;Good luck! Let me know in a comment if you manage to land a sweet gig :D&lt;/p&gt;

&lt;h1&gt;
  
  
  More Learning Resources
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What resources should I use to learn web development?
&lt;/h2&gt;

&lt;p&gt;My personal #1 recommendation to anyone trying to get into web development as a career would be to go through &lt;a href="https://www.theodinproject.com/" rel="noopener noreferrer"&gt;The Odin Project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is an absolutely incredible resource that teaches all of the fundamentals of web development (including HTML, CSS, Javascript and Git) and more in a completely free digital environment.&lt;/p&gt;

&lt;p&gt;They even have a Discord server for users to help each other out while going through the curriculum.&lt;/p&gt;

&lt;p&gt;If you go through the entire Odin Project from start to finish and complete every step and every project I genuinely believe you will be in a position to start applying for jobs. It uses all the same technologies that real companies use and mirrors the kinds of tasks and challenges you would find in a real professional web development position.&lt;/p&gt;

&lt;p&gt;In addition to the Odin Project, &lt;a href="https://www.freecodecamp.org/" rel="noopener noreferrer"&gt;Free Code Camp&lt;/a&gt; is also very highly recommended as a free resource to learn web development.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are the best free resources for learning HTML&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning CSS&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning Javascript&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning Git&lt;/li&gt;
&lt;li&gt;What are the best free resources for learning Databases&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are the best free resources for learning computer science?
&lt;/h2&gt;

&lt;p&gt;If you are interested in learning about the more generalized field of "software development" then there are some absolutely incredible free resources for that as well.&lt;/p&gt;

&lt;p&gt;Anything that you learn about the development in general will almost certainly help propel your understanding of web development as well. The great thing about software is that ultimately most of the concepts are the same regardless of which specialty you choose.&lt;/p&gt;

&lt;p&gt;Learning how to sort an array in C++ or Python will use all the same general concepts as sorting an array in Javascript. Learning how to do it in one language one will make learning it in the other significantly faster. Often you'll even learn tips and tricks that you might not have been exposed to working exclusively in one language.&lt;/p&gt;

&lt;p&gt;The gold standard free resource for getting introduced to programming and software development is &lt;a href="https://cs50.harvard.edu" rel="noopener noreferrer"&gt;Harvard's free CS50 course&lt;/a&gt;. Seriously, watch the preview video to get an idea, it's absolutely fascinating subject material and extremely well presented. I would recommend this course to anyone who was thinking about getting into development.&lt;/p&gt;

&lt;p&gt;After that we have the incredible &lt;a href="https://github.com/ossu/computer-science" rel="noopener noreferrer"&gt;OSSU&lt;/a&gt; which is an entire university level computer science available free online. Once again, this is one of the most amazing resources you will ever encounter, and entirely free.&lt;/p&gt;

&lt;p&gt;We also have &lt;a href="https://teachyourselfcs.com/" rel="noopener noreferrer"&gt;teach yourself CS&lt;/a&gt; which is very similar to OSSU in that it aims to be a complete computer science education.&lt;/p&gt;

&lt;p&gt;Lastly, I'd like to also share two other great resources for people interested in the field of software development, depending on where you interest lies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you are interesting in using software and programming to solve practical everyday problems, check out &lt;a href="https://automatetheboringstuff.com/" rel="noopener noreferrer"&gt;Automate the Boring Stuff&lt;/a&gt; with Python. After completing this if you're working a white collar job using Excel in an office, there's a good chance you'll find you can automate away half the stuff you do on a daily basis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The other is for people who are more interested in the "how does software work at the lowest level". It's a project called &lt;a href="https://www.nand2tetris.org/" rel="noopener noreferrer"&gt;Nand to Tetris&lt;/a&gt; and it basically goes through the process of going from electronic hardware logic gates to a working game of Tetris. Very involved and complex, but incredibly rewarding.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you are interested to go even lower, down to the bare metal, then you'll definitely want to check out this incredible video series from Ben Eater on &lt;a href="https://www.youtube.com/playlist?list=PLowKtXNTBypGqImE405J2565dvjafglHU" rel="noopener noreferrer"&gt;building an 8-bit computer from scratch&lt;/a&gt;. If you complete a big project like this you'll learn more about computers than any single college course or video lecture will be able to teach you.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Simple Website Template
&lt;/h1&gt;

&lt;p&gt;The following is a simple example of a complete website that uses HTML, CSS and Javascript. These files are used as the basis of a lot of examples in this tutorial such as using Github, website hosting, and learning HTML/CSS/JS.&lt;/p&gt;

&lt;p&gt;The purpose of this section is to link to in those other parts of the tutorials to copy these files, but it may also serve as an example of a simple website setup that shows some of the fundamental concepts of HTML, CSS and Javascript.&lt;/p&gt;

&lt;p&gt;Feel free to use it for any part of your learning or projects in any way that you like.&lt;/p&gt;

&lt;p&gt;It consists of three files called &lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;script.js&lt;/code&gt; and &lt;code&gt;style.css&lt;/code&gt; which are all intended to go into the same folder/directory. The contents of each of those three files is as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My Animal Blog&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;My Favourite Animals&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Enjoy these furry friends&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
          &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://res.cloudinary.com/dqse2txyi/image/upload/v1657421273/blogs/intro-to-web-development/cat_k4fcww.png"&lt;/span&gt;
          &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Cat Playing Chess"&lt;/span&gt;
        &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card__container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Chess Cat&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;He's planning his next move.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"likeButton()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Like&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;footer&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;copy;&lt;/span&gt; 2022&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;style.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;footer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;italic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;lighter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;350px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Adds 1 to the number of likes, and updates the text of the button&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;likeButton&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&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;var&lt;/span&gt; &lt;span class="nx"&gt;myButton&lt;/span&gt; &lt;span class="o"&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;myButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&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="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;likes&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;When placed together and hosted with a web server, this will be the output when you visit the URL:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657469604%2Fblogs%2Fintro-to-web-development%2Fwebsite-example_jqew3t.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1657469604%2Fblogs%2Fintro-to-web-development%2Fwebsite-example_jqew3t.png" alt="Website Example"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I hope you found this guide useful and informative.  It's been extremely challenging to try and decide the right format to present it so that it can be helpful to as many people as possible.&lt;/p&gt;

&lt;p&gt;If you have any suggestions or feedback please leave a comment behind.  Despite the length and scope of this guide I still consider it to be a work in progress and am very open to any ideas for improvement.&lt;/p&gt;

&lt;p&gt;Lastly, to everyone, I wish you good luck on your learning journey.  Learning a new skill, especially one as complex as software development, takes a lot of time.  Go easy on yourself, and remember that the goal is not overnight success, but rather a little bit of progress each day.&lt;/p&gt;

&lt;p&gt;All the best,&lt;/p&gt;

&lt;p&gt;~ Alex&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Build a Fullstack Next.js App (with Storybook &amp; TailwindCSS)</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Thu, 21 Apr 2022 23:22:33 +0000</pubDate>
      <link>https://dev.to/alexeagleson/how-to-build-a-fullstack-nextjs-application-with-storybook-tailwindcss-2gfa</link>
      <guid>https://dev.to/alexeagleson/how-to-build-a-fullstack-nextjs-application-with-storybook-tailwindcss-2gfa</guid>
      <description>&lt;p&gt;All code from this tutorial as a complete package is available in &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you find this tutorial helpful, please share it with your friends and colleagues! For more like it you can subscribe on &lt;a href="https://www.youtube.com/channel/UCV5YqK3AaInd3lYFQqlp7Lw" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/eagleson_alex" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This tutorial is available as a video lesson if you prefer that format:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/46V478kPL3A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Adding Tailwind&lt;/li&gt;
&lt;li&gt;Storybook Support for Tailwind&lt;/li&gt;
&lt;li&gt;Scoping and Requirements&lt;/li&gt;
&lt;li&gt;Front End Planning&lt;/li&gt;
&lt;li&gt;Front End: Search Component&lt;/li&gt;
&lt;li&gt;Front End: Header and Footer&lt;/li&gt;
&lt;li&gt;Front End: Layout&lt;/li&gt;
&lt;li&gt;Front End: Results&lt;/li&gt;
&lt;li&gt;Back End Planning&lt;/li&gt;
&lt;li&gt;Back End: Search Data&lt;/li&gt;
&lt;li&gt;Back End: API Routes&lt;/li&gt;
&lt;li&gt;Static and Dynamic Pages in Next.js&lt;/li&gt;
&lt;li&gt;Front End Finishing Touches&lt;/li&gt;
&lt;li&gt;Themes and Design Systems&lt;/li&gt;
&lt;li&gt;Next Steps&lt;/li&gt;
&lt;li&gt;Wrapping Up&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT: This tutorial is a continuation of a &lt;a href="https://dev.to/alexeagleson/how-to-build-scalable-architecture-for-your-nextjs-project-2pb7#adding-storybook"&gt;previous tutorial&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you wish to align the &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;repository&lt;/a&gt; with the start of this tutorial, clone the repository and &lt;code&gt;git checkout 6630ca95c25e66d7b6c7b1aad92151b481c1b9c5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After you check out that commit, create a new branch to follow along with this tutorial. An example would be something like &lt;code&gt;git branch fullstack-tutorial&lt;/code&gt; and then &lt;code&gt;git checkout fullstack-tutorial&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It should be possible to follow this tutorial with a new blank project if you choose without all the configuration from the previous setup, but I would recommend you at least read through the article to understand the project architecture before we get started.&lt;/p&gt;

&lt;p&gt;If you wish to try starting from a fresh Next.js project, run the following commands to set up the core project:&lt;/p&gt;

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

npx create-next-app --ts


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

&lt;/div&gt;

&lt;p&gt;Then you will also want to install Storybook. &lt;a href="https://dev.to/alexeagleson/how-to-build-scalable-architecture-for-your-nextjs-project-2pb7#adding-storybook"&gt;Follow these instructions&lt;/a&gt; in a new project to get aligned with the beginning of this tutorial.&lt;/p&gt;

&lt;p&gt;We also create all of our components off a base template that includes styles, stories and mock data. You can get that template from &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template/tree/main/components/templates/base" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Good luck, and I hope you enjoy this tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This tutorial is the second in a series about building scaleable Next.js architecture.&lt;/p&gt;

&lt;p&gt;In the first installment, we focused entirely on the base project setup, we didn't actually begin building an application, just a simple component template to show the process.&lt;/p&gt;

&lt;p&gt;In this next stage we will be looking at actually building out an application. We'll be looking at how Next.js handles some fundamental things like routing, image optimization, static vs dynamic pages, building an API, and of course: styling solutions.&lt;/p&gt;

&lt;p&gt;We'll be using the current "hot commodity" &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt; as the tool we use to organize our design system, and get styles implemented quickly while maintaining a consistent look and feel to the product.&lt;/p&gt;

&lt;p&gt;Finally and maybe most importantly, this tutorial is also focused on trying to replicate the real software development process. So we won't just be jumping into building, we'll be looking at what the requirements are based on our goals, what the scope of the project should be, and planning out in advance how we are going to build both the front end and back end.&lt;/p&gt;

&lt;p&gt;By the end of the tutorial our goal will be to have a functional full-stack Next.js app that we can push to a production site and continue to iterate on in the future with a team of developers following a consistent system.&lt;/p&gt;

&lt;p&gt;If that all sounds good to you, let's jump right in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Tailwind
&lt;/h2&gt;

&lt;p&gt;Tailwind CSS describes itself as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A utility-first CSS framework packed with classes like flex, pt-4, text-center and rotate-90 that can be composed to build any design, directly in your markup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So basically it's a way to enforce a bit of consistency and convenience, while also placing most of your styles closer to the components you're developing.&lt;/p&gt;

&lt;p&gt;Tailwind's compiler will analyze all your code and only bundle raw CSS based on the classes you actually use, so it requires some dependencies to get up and running.&lt;/p&gt;

&lt;p&gt;Before we get started I would very highly recommend the &lt;a href="https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss" rel="noopener noreferrer"&gt;Tailwind CSS IntelliSense&lt;/a&gt; extension for VS Code. It gives you autocomplete for Tailwind styles, shows you the actual CSS values being applied, integrates with your custom theme, and generally and makes working with Tailwind so much smoother.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649774048%2Fblogs%2Fnextjs-app-tailwind%2Ftailwind-vscode-extension_lbp2kp.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649774048%2Fblogs%2Fnextjs-app-tailwind%2Ftailwind-vscode-extension_lbp2kp.png" alt="Tailwind CSS Intellisense"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's begin by running the following commands in the root directory of our project:&lt;/p&gt;

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

yarn add -D tailwindcss postcss autoprefixer


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

&lt;/div&gt;

&lt;p&gt;Tailwind will compile into regular CSS for your final build so there is no need for it to exist as a runtime dependency in your project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/postcss" rel="noopener noreferrer"&gt;postcss&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/autoprefixer" rel="noopener noreferrer"&gt;autoprefixer&lt;/a&gt; are tools for transforming CSS that Tailwind uses to do its job.&lt;/p&gt;

&lt;p&gt;After Tailwind has been installed, we need to initialize it.&lt;/p&gt;

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

npx tailwindcss init -p


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

&lt;/div&gt;

&lt;p&gt;This will automatically create a &lt;code&gt;postcss.config.js&lt;/code&gt; file for you. In addition to that you also need to create a &lt;code&gt;tailwind.config.js&lt;/code&gt;file in the root of the project. One might get created by default as well. Its contents should include:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tailwind.config.js&lt;/code&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/**/*.{js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/**/*.{js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// Ensure these match with .storybook/preview.js&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;screens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;375px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;600px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;md&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;900px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1200px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1536px&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="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Notice the pattern I used above is aligned with our &lt;code&gt;/components&lt;/code&gt; and &lt;code&gt;/pages&lt;/code&gt; directories. These are the only places I am planning to place React components (and therefore Tailwind styles since they are written on the components).&lt;/p&gt;

&lt;p&gt;If you plan on adding more top level component directories in the future make sure you update this config.&lt;/p&gt;

&lt;p&gt;We're almost ready to test it. We just need to add a few default baseline values to our &lt;code&gt;global.css&lt;/code&gt; file. At this point I'm going to move it to the &lt;code&gt;/pages&lt;/code&gt; directory because we will be building this app entirely with Tailwind and will not have any need for a global styles directory. (Note you may also need to update the import in &lt;code&gt;.storybook/main.js&lt;/code&gt; if you do this).&lt;/p&gt;

&lt;p&gt;If you choose not to use Tailwind, you can either keep the &lt;code&gt;styles&lt;/code&gt; directory, or even still choose to remove it and keep your &lt;code&gt;.modules.css&lt;/code&gt; (or SCSS, or styled-components) next to the components themselves.&lt;/p&gt;

&lt;p&gt;Take special note of the &lt;code&gt;@tailwind&lt;/code&gt; values at the top.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/global.css&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&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 remove any other browser normalizing CSS you had in global, Tailwind will take care of that for you.&lt;/p&gt;

&lt;p&gt;I have also updated our &lt;code&gt;index.tsx&lt;/code&gt; to get rid of &lt;code&gt;Home.module.css&lt;/code&gt; and deleted that file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CatCard&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/cards/cat/CatCard&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;mockCatCardProps&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;../components/cards/cat/CatCard.mocks&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;PrimaryLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/layouts/primary/PrimaryLayout&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;SidebarLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/layouts/sidebar/SidebarLayout&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;NextPageWithLayout&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;./page&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;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPageWithLayout&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-gradient-to-r from-cyan-500 to-blue-500"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Welcome to &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://nextjs.org"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Next.js!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&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;CatCard&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mockCatCardProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PrimaryLayout&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;SidebarLayout&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;page&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;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now let's test to make sure Tailwind is installed and configured properly.&lt;/p&gt;

&lt;p&gt;Notice that &lt;code&gt;className&lt;/code&gt; on the section component in the above home page? That's tailwind right there, essentially just quick shorthands for the CSS properties you're already familiar with.&lt;/p&gt;

&lt;p&gt;Without Tailwind installed and configured they won't do anything, but with Tailwind we should see a blue/cyan linear gradient background.&lt;/p&gt;

&lt;p&gt;The nice thing is that Next.js will handle all the build process for you, you don't even have to think about it. Just start up your dev server (you may need to reboot to pick it up if it was already running):&lt;/p&gt;

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

yarn dev


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

&lt;/div&gt;

&lt;p&gt;And go to &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649454449%2Fblogs%2Fnextjs-app-tailwind%2Finstall-tailwind_ukdptn.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649454449%2Fblogs%2Fnextjs-app-tailwind%2Finstall-tailwind_ukdptn.png" alt="Nextjs Tailwind"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks like everything is setup. We only have one problem, if you try and run Storybook you're not going to see your styles. Your Next.js is setup to process your Tailwind classes, but by default Storybook is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storybook Support for Tailwind
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you don't have Storybook installed and configured already, remember to read the prerequisites section of this guide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Start by adding the PostCSS addon for Storybook:&lt;/p&gt;

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

yarn add -D @storybook/addon-postcss


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

&lt;/div&gt;

&lt;p&gt;OPTIONAL: If you want to keep using CSS modules as well:&lt;/p&gt;

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

yarn add -D storybook-css-modules-preset


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

&lt;/div&gt;

&lt;p&gt;Then update your &lt;code&gt;.storybook/main.js&lt;/code&gt; file to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.storybook/main.js&lt;/code&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;stories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../**/*.stories.mdx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../**/*.stories.@(js|jsx|ts|tsx)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="cm"&gt;/** Expose public folder to storybook as static */&lt;/span&gt;
  &lt;span class="na"&gt;staticDirs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;addons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/addon-links&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/addon-essentials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/addon-interactions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storybook-css-modules-preset&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="cm"&gt;/**
       * Fix Storybook issue with PostCSS@8
       * @see https://github.com/storybookjs/storybook/issues/12668#issuecomment-773958085
       */&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/addon-postcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;postcssLoaderOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;framework&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;core&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/builder-webpack5&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I've just added our blue/cyan gradient to the &lt;code&gt;BaseTemplate.tsx&lt;/code&gt; component to test in Storybook to ensure it's properly compiling Tailwind styles (I removed the class again immediately after the test).&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649455929%2Fblogs%2Fnextjs-app-tailwind%2Fstorybook-tailwind_liznmv.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649455929%2Fblogs%2Fnextjs-app-tailwind%2Fstorybook-tailwind_liznmv.png" alt="Storybook Tailwind"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time to commit our progress with &lt;code&gt;git commit -m 'feat: implement tailwind css'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to align with this step of the tutorial, clone the &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and use &lt;code&gt;git checkout 6630ca95c25e66d7b6c7b1aad92151b481c1b9c5&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scoping and Requirements
&lt;/h2&gt;

&lt;p&gt;One thing I would like to do with this tutorial is cover, at least at a very high level, the general software development lifecycle. Obviously this topic can span full posts and entire books, but I think it's important to touch on the concepts especially for those devs following along with the tutorial who may not have the existing experience working with real projects in the industry. That is one of the goals of this tutorial series.&lt;/p&gt;

&lt;p&gt;So with that in mind I am going to treat it like a real project.&lt;/p&gt;

&lt;p&gt;First I need to ask the client (in this case the client is myself): &lt;em&gt;What are your goals? What are you trying to achieve?"&lt;/em&gt; It's possible (though very unlikely) that once discussed in detail, this challenge can actually addressed without building new software at all. Perhaps there is an existing tool out there already built that fits their needs that they are not aware of?&lt;/p&gt;

&lt;p&gt;In our scenario my goal is to "teach people about building applications in Next.js". Alright. I think it's fair to presume I'm going to need to build a Next.js application to deliver on that goal.&lt;/p&gt;

&lt;p&gt;It turns out that I (the client) has a list of particular topics that I would like to teach readers about as part of this tutorial. They are concepts that nearly everyone building a professional Next.js app will encounter in the process of development&lt;/p&gt;

&lt;h3&gt;
  
  
  Must haves:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Styling&lt;/li&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;li&gt;API routes&lt;/li&gt;
&lt;li&gt;Static and dynamic pages&lt;/li&gt;
&lt;li&gt;Image optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Nice-to-haves:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sharing state between routes&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Internationalization&lt;/li&gt;
&lt;li&gt;Unit and end-to-end testing&lt;/li&gt;
&lt;li&gt;Data persistence (database)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notes: The two separate footers are not required. Just one (showing location) is enough.&lt;/p&gt;

&lt;p&gt;Great. That really helps me decide how I am going to scope the project.&lt;/p&gt;

&lt;p&gt;Immediately out of the gate, since I am writing multiple blog posts I am going to assign all the "nice-to-have's" into the &lt;em&gt;Phase 2&lt;/em&gt; of the project (in our case, future blog posts). The scope of &lt;em&gt;Phase 1&lt;/em&gt; will include all the "must have's".&lt;/p&gt;

&lt;p&gt;But what kind of project will I build to meet those requirements? I'm looking for the minimum viable example I can choose which will allow me to demonstrate each of those and meet the client needs without going over time and budget.&lt;/p&gt;

&lt;p&gt;After spending some time reviewing popular sites out there to get ideas, I have decided that for this tutorial we are going to make a very simple &lt;em&gt;&lt;strong&gt;Google clone&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649473228%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-example-screenshot_qmy9np.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649473228%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-example-screenshot_qmy9np.png" alt="Google Home"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649475380%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-example-screenshot-results_aad5hv.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649475380%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-example-screenshot-results_aad5hv.png" alt="Google Results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why? Well let's review the requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Styling &lt;em&gt;(Google has a simple design, we'll use Tailwind CSS to recreate it)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Routing &lt;em&gt;(we'll demonstrate two routes, the main "home" page and a "results" page)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;API routes &lt;em&gt;(we'll use the &lt;code&gt;fetch&lt;/code&gt; API to query for some mock search data with an API route)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Static and dynamic pages &lt;em&gt;(main page can be static, search page dynamic based on search query)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Image optimization &lt;em&gt;(the Google logo)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Excellent! We have our requirements and scope, and now we are ready to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Front End Planning
&lt;/h2&gt;

&lt;p&gt;Before we dive in and start making components, let's take a bit of time to look at the whole project holistically and get an idea what components we are going to need. Normally this is likely where you would involve your designer in your process and use an industry grade tool like &lt;a href="https://www.figma.com" rel="noopener noreferrer"&gt;Figma&lt;/a&gt; to plan out and design the components you are going to need before you even begin thinking about code.&lt;/p&gt;

&lt;p&gt;Lucky for us we already have the best design we could possibly ask for: a fully interactive one accessible at &lt;a href="https://www.google.com" rel="noopener noreferrer"&gt;https://www.google.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So we'll give the designer a break on this project and tackle it ourselves! I still want to get an idea what components I'm going to need so let's take a look at the two main pages we want to create and get an idea what the components are, and build a mental model of which pieces of it are re-used in multiple places.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note when I say "components" here in this context, I'm talking about the general concept of components, like the individual parts that something is composed of. I haven't gotten to the React-specific code "components" yet)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649473228%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-example-screenshot-planning_zqdprl.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649473228%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-example-screenshot-planning_zqdprl.png" alt="Google Home Planning"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649475380%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-example-screenshot-results-planning_p6unpb.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649475380%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-example-screenshot-results-planning_p6unpb.png" alt="Google Results Planning"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So you can see in the above I've isolated at least a few components at minimum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layout (likely need home and results variants)&lt;/li&gt;
&lt;li&gt;Search (the functional part including the input, will be a form)&lt;/li&gt;
&lt;li&gt;Nav (both header and footer variants, only difference being the background colour and top/bottom position. The elements can be child components)&lt;/li&gt;
&lt;li&gt;Search Result (the structure of and typography of everything that does into rendering one result of a search, including title, text, url, etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above is just one possible approach of a near infinite number even for something as simple as this. This is the project design stage and there honestly is no one right answer on exactly how to do it. Most people find in there career after a few years of getting the coding down, this is the stuff that ends up being the real challenge.&lt;/p&gt;

&lt;p&gt;A good app will have the team spending much more time getting the design and plan in place, so that the absolutely minimum amount of coding needs to be done to achieve that goal. The coding and development stage is usually not only the most expensive, but it's also the most costly and complex to "undo" if requirements were not correct the first time.&lt;/p&gt;

&lt;p&gt;I'll stop short of getting into the bureaucracy of it, because of course the reality is never this cut and dry, but hopefully you can see what I'm getting at. If at all possible, do it once, do it right, and be consistent. Other developers (and your future self) will thank you.&lt;/p&gt;

&lt;p&gt;With that out of the way, I think we're finally ready to begin development on the front end components!&lt;/p&gt;

&lt;h2&gt;
  
  
  Front End: Search Component
&lt;/h2&gt;

&lt;p&gt;We will be doing ALL of our component designing and testing in Storybook.&lt;/p&gt;

&lt;p&gt;You'll find that will be a recurring theme in our development process. It's a great way to make sure that the components we build look correct in isolation, so we can validate that without interference from other parts of the app, and then place them into our app afterward once they have been verified.&lt;/p&gt;

&lt;p&gt;For this reason I actually have the flexibility to start working on whichever component I like. I'm going to begin with the &lt;code&gt;Search&lt;/code&gt; component first.&lt;/p&gt;

&lt;p&gt;Create a new directory called &lt;code&gt;/utility&lt;/code&gt; inside &lt;code&gt;/components&lt;/code&gt;. As before, we'll start by copying our &lt;code&gt;templates/base&lt;/code&gt; into the &lt;code&gt;components/utility&lt;/code&gt; directory to start our component.&lt;/p&gt;

&lt;p&gt;If you are unsure what I am describing, you can refer back to the &lt;a href="https://dev.to/alexeagleson/how-to-build-scalable-architecture-for-your-nextjs-project-2pb7#creating-a-component-template"&gt;original tutorial&lt;/a&gt; where we created the &lt;a href="https://dev.to/alexeagleson/how-to-build-scalable-architecture-for-your-nextjs-project-2pb7#creating-a-component-template"&gt;BaseTemplate&lt;/a&gt; component, or simply take it from the project &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run a find and replace for each instance of &lt;code&gt;BaseTemplate&lt;/code&gt; and replace with &lt;code&gt;Search&lt;/code&gt; in the copied folder, including both the content of the files and the filenames themselves. Lastly change the &lt;code&gt;title&lt;/code&gt; in &lt;code&gt;Search.stories.tsx&lt;/code&gt; to &lt;code&gt;utility/Search&lt;/code&gt;. When you are done it should look 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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649532739%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-component_bhd3wc.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649532739%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-component_bhd3wc.png" alt="Search Component File Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And in Storybook with:&lt;/p&gt;

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

yarn storybook


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649472567%2Fblogs%2Fnextjs-app-tailwind%2Fstorybook-search-template_g0xxfk.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649472567%2Fblogs%2Fnextjs-app-tailwind%2Fstorybook-search-template_g0xxfk.png" alt="Storybook Search Template"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(You may still have some lingering Tailwind test styles on the template which can be removed. Note also that I am leaving the &lt;code&gt;.module.css&lt;/code&gt; template on here for those who choose not to use Tailwind, but we will not be using it in this tutorial)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Alright time to begin building the component! This is the one I've outlined in green in the original planning design above and titled as &lt;code&gt;Search&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search Step 01: HTML Structure
&lt;/h3&gt;

&lt;p&gt;I'm going to begin with just the HTML structure, no styles or function logic. The "Search" button and input implies I'm going to want a form.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/utility/base/Search.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISearch&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;Search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ISearch&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Google Search&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;I&lt;span class="ni"&gt;&amp;amp;apos;&lt;/span&gt;m Feeling Lucky&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649476578%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-component-step-01_llnjz1.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649476578%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-component-step-01_llnjz1.png" alt="Search Component Step 01"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Look at that &lt;code&gt;Search&lt;/code&gt; component, pretty incredible eh? Hit the submit button in storybook and get an error since you don't have a backend to handle it. I'd say it's basically done... well maybe not.&lt;/p&gt;

&lt;p&gt;I'm happy with the structure though, function-wise it's got everything we need. Let's do the styling next to get the look and feel up to speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search Step 02: CSS Structure
&lt;/h3&gt;

&lt;p&gt;If you're not familiar with Tailwind CSS I recommend you take a &lt;a href="https://tailwindcss.com/docs/installation" rel="noopener noreferrer"&gt;read through their documentation&lt;/a&gt; first to get a good feel for the syntax. If you're experienced with CSS you should find it very easy, for the most part it's just convenient shorthands. Just use the search bar of &lt;code&gt;ctrl + F&lt;/code&gt; to quickly find the Tailwind version of what you need.&lt;/p&gt;

&lt;p&gt;Full disclosure: I've been using Tailwind now for a grand total of about... 48 hours. It's brand new to me too! But I'm acknowledging that, not as a negative, but as a positive to show how straightforward it is to learn when you already have the fundamentals down.&lt;/p&gt;

&lt;p&gt;I chose Tailwind for two reasons: ease of development (get styles in place quickly) and consistency (the base theme and pre-set values help ensure that the different parts in our app will look and feel the same).&lt;/p&gt;

&lt;p&gt;Now with all that said, let's start adding those classes! Here's the same component as above, just with some Tailwind styles added (and a wrapper element for the buttons).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/utility/base/Search.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISearch&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;Search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ISearch&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center gap-y-5"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"rounded-full border-2 w-5/6 sm:w-96 h-12 px-3"&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-x-3"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border-0 p-2 px-6 bg-slate-100 rounded-md"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Google Search
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border-0 p-2 px-6 bg-slate-100 rounded-md"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          I&lt;span class="ni"&gt;&amp;amp;apos;&lt;/span&gt;m Feeling Lucky
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Search&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 abstract those repeat classes on buttons out to a separate &lt;code&gt;@apply&lt;/code&gt; directive to avoid repeating yourself.&lt;/p&gt;

&lt;p&gt;Note: please read through Tailwind's extremely good &lt;a href="https://tailwindcss.com/docs/reusing-styles" rel="noopener noreferrer"&gt;documentation on this concept&lt;/a&gt; because it discusses how in a lot of cases the &lt;code&gt;@apply&lt;/code&gt; solution can actually reduce future maintainability, so you just want to make sure it's the right decision first.&lt;/p&gt;

&lt;p&gt;I'm using it here because I just want you to be aware of it and how to do it, and secondly they use an example of a global button style as one of the times that it should be used, so I feel confident using it in this example.&lt;/p&gt;

&lt;p&gt;We just need to remove those repeat button styles and put them into &lt;code&gt;pages/global.css&lt;/code&gt; and replace with an actual class name like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/global.css&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.btn-primary&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;border-0&lt;/span&gt; &lt;span class="err"&gt;p-2&lt;/span&gt; &lt;span class="err"&gt;px-6&lt;/span&gt; &lt;span class="err"&gt;bg-slate-100&lt;/span&gt; &lt;span class="err"&gt;rounded-md;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;components/utility/base/Search.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISearch&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;Search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ISearch&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center gap-y-5"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"rounded-full border-2 w-5/6 sm:w-96 h-12 px-3"&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-x-3"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"btn-primary"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Google Search
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"btn-primary"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          I&lt;span class="ni"&gt;&amp;amp;apos;&lt;/span&gt;m Feeling Lucky
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Excellent. Our &lt;code&gt;Search&lt;/code&gt; component is finally ready visually (I've opted not to use the magnifying icon as it is embedded within the input element which makes the CSS a bit more complex than the intended scope of this tutorial.)&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649481216%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-component-step-02_o2sjfo.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649481216%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-component-step-02_o2sjfo.png" alt="Search Component Step 01"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try using the screen size button within Storybook (you can see it set to &lt;code&gt;sm&lt;/code&gt; in the screenshot) to test at different mobile breakpoints. Notice we used the default 5/6 width on the input but set to &lt;code&gt;sm:w-96&lt;/code&gt; once the screen begins to stretch to keep it from getting too large.&lt;/p&gt;

&lt;p&gt;Simplifying responsive design is one of the things Tailwind really excels at.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search Step 03: Logic and State
&lt;/h3&gt;

&lt;p&gt;The last piece is to implement the management of the search state (basically keeping track of what the user has written so far).&lt;/p&gt;

&lt;p&gt;The easiest way to do that is with the &lt;a href="https://beta.reactjs.org/apis/usestate" rel="noopener noreferrer"&gt;useState&lt;/a&gt; hook.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Reminder once again that this is not a React tutorial, if you are not familiar with &lt;code&gt;useState&lt;/code&gt; then you have potentially jumped the gun into Next.js a little too quickly. Not to worry! Shouldn't take you long to pick up, the new &lt;a href="https://beta.reactjs.org/" rel="noopener noreferrer"&gt;React documentation&lt;/a&gt; focused on hooks is probably the best way to learn straight from the source)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/utility/base/Search.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;useState&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="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISearch&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;Search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ISearch&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchTerm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center gap-y-5"&lt;/span&gt;
      &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="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="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Action requested. Search for term: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"rounded-full border-2 w-5/6 sm:w-96 h-12 px-3"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nf"&gt;setSearchTerm&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="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-x-3"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"btn-primary"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Google Search
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"btn-primary"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          I&lt;span class="ni"&gt;&amp;amp;apos;&lt;/span&gt;m Feeling Lucky
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The above will allow you to track and react to changes in the search form on the &lt;code&gt;searchTerm&lt;/code&gt; variable. I've also added a Javascript-based form handler (as opposed to the default HTML behavior) so we can use it later if we need it. The &lt;code&gt;preventDefault&lt;/code&gt; steps the normal form submission behavior of making a POST to the server from occurring.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649481924%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-component-step-03_rftvoi.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649481924%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-component-step-03_rftvoi.png" alt="Search Component Step 03"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point we are not sure if the search term might need to be managed elsewhere in the app (other components might need to be able to read it) or how we are going to submit the form. Normally that would be part of the planning process and I would know before writing code, but I am including this default behavior here to show as an example how we will refactor later if needed.&lt;/p&gt;

&lt;p&gt;This completes our &lt;code&gt;Search&lt;/code&gt; component for now until we know more about what we want to do with it. Aside form the &lt;code&gt;alert()&lt;/code&gt; it appears to do everything we need it to do, and renders without visual issues on all breakpoints, so we can consider that done for now (normally you'd update your ticket and submit to QA for approval that the execution matches the design).&lt;/p&gt;

&lt;p&gt;Time to commit our progress with &lt;code&gt;git commit -m 'feat: create Search component'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to align with this step of the tutorial, clone the &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and use &lt;code&gt;git checkout 676a71b50755d859f46a12e54f8ea3484bf1f208&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Front End: Header and Footer
&lt;/h3&gt;

&lt;p&gt;We're gonna kick up the speed a bit here to get the basic remaining components in place.&lt;/p&gt;

&lt;p&gt;I've decided to build the &lt;code&gt;Header&lt;/code&gt; and &lt;code&gt;Footer&lt;/code&gt; as separate components for the time being. There is definitely behavior that is shared between them that could be abstracted into is own component (links/buttons in a row separated on each side of the screen horizontally with flex's &lt;code&gt;space-between&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;However there is still a lot that's unique, the content for sure, the position and the background colour. Enough that I have decided to separate them for the sake of simplicity in this demo.&lt;/p&gt;

&lt;p&gt;Let's get to building.&lt;/p&gt;

&lt;p&gt;Remember in each case we are using the &lt;a href="https://dev.to/alexeagleson/how-to-build-scalable-architecture-for-your-nextjs-project-2pb7#creating-a-component-template"&gt;BaseTemplate&lt;/a&gt;. For &lt;code&gt;Header&lt;/code&gt; the Story title is &lt;code&gt;navigation/Header&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/navigation/header/Header.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IHeader&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IHeader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;headerProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;headerProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`w-full flex flex-row justify-between &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-x-5 m-5"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hover:underline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hover:underline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Store&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-x-5 m-5"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hover:underline hidden sm:inline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Gmail&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hover:underline hidden sm:inline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Images&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border-1 p-2 px-4 sm:px-6 bg-blue-500 rounded text-white"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Sign In
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;A cool feature of the above is that the Gmail &amp;amp; Images links disappear on the smallest screen size. In the real app we would have a menu that includes those items so they are not inaccessible on mobile, but on larger screens we get handy shortcuts to them.&lt;/p&gt;

&lt;p&gt;Another thing you'll notice is the special &lt;code&gt;&amp;lt;Link /&amp;gt;&lt;/code&gt; component provided by Next.js as an alternative to the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; anchor tag. These links are required in order to maintain stage between routes in Next which we'll get to in a little while. Learn more about it &lt;a href="https://nextjs.org/docs/routing/introduction#linking-between-pages" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we move onto the Footer.&lt;/p&gt;

&lt;p&gt;components/navigation/header/Footer.tsx&lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IFooter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;footer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IFooter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;footerProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;footer&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;footerProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`w-full p-5 bg-slate-100 text-slate-500 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Canada&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Footer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We were told in our requirements that only one footer is required. Right now we have the value hard coded as &lt;code&gt;Canada&lt;/code&gt;, but we can return to that later. Just focusing on style for now.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649483860%2Fblogs%2Fnextjs-app-tailwind%2Fheader-and-footer-initial_iymsxk.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649483860%2Fblogs%2Fnextjs-app-tailwind%2Fheader-and-footer-initial_iymsxk.png" alt="Header and Footer Initial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Front End: Layout
&lt;/h3&gt;

&lt;p&gt;Presuming you've been following up with the previous blog / tutorial you will already have a layout component in place in &lt;code&gt;components/layouts/primary/PrimaryLayout.tsx&lt;/code&gt;. This is important because we already set that layout up to persist between page routing so it doesn't reload the same layout and nav bar when you transition from one page to another.&lt;/p&gt;

&lt;p&gt;One that note you can delete &lt;code&gt;components/layouts/sidebar&lt;/code&gt; entirely, our new &lt;code&gt;Header&lt;/code&gt; and &lt;code&gt;Footer&lt;/code&gt; will replace that. Remember to delete it elsewhere in the code where &lt;code&gt;SidebarLayout&lt;/code&gt; is imported. You can also delete &lt;code&gt;pages/about.tsx&lt;/code&gt; for the same reason. It was just an example to show routing and no longer required in our app.&lt;/p&gt;

&lt;p&gt;As for &lt;code&gt;PrimaryLayout.tsx&lt;/code&gt; we will update it as follows (first remove or just blank out &lt;code&gt;PrimaryLayout.module.css&lt;/code&gt;) then:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/layouts/primary/PrimaryLayout.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Footer&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;../../navigation/footer/Footer&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;Header&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../navigation/header/Header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IPrimaryLayout&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;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IPrimaryLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;NextJs Fullstack App Template&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"min-h-screen flex flex-col items-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&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;children&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;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"m-auto"&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;Footer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&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="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649484746%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-primary-layout_x4ge1l.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649484746%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-primary-layout_x4ge1l.png" alt="Google Primary Layout"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With our layout in place, we are ready to build the actual home page.&lt;/p&gt;

&lt;p&gt;The way &lt;a href="https://nextjs.org/docs/routing/introduction" rel="noopener noreferrer"&gt;that Next.js handles routing&lt;/a&gt; is super simple and straightforward out of the box. Similar to a traditional webserver all you need to do is create directories.&lt;/p&gt;

&lt;p&gt;The directory structure you create will match the path structure of your site and the page it loads is simply the &lt;code&gt;index.tsx&lt;/code&gt; inside that directory, same as a webserver would look for an &lt;code&gt;index.html&lt;/code&gt; by default.&lt;/p&gt;

&lt;p&gt;For our home page accessible at the base &lt;code&gt;/&lt;/code&gt; route of our site, we simply use &lt;code&gt;pages.index.tsx&lt;/code&gt;. We already have the Header, Footer, Search components, and layout created, so all the home page needs to do is put those together and add the logo &amp;amp; language toggle link.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/image&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;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="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;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PrimaryLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/layouts/primary/PrimaryLayout&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;Search&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/utility/search/Search&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;NextPageWithLayout&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;./page&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;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPageWithLayout&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center gap-y-5 mt-12 sm:mt-36"&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;Image&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/Google.png"&lt;/span&gt;
        &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Google Logo"&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;272&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;priority&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;Search&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Google offered in:&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&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="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"underline text-blue-600"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Français&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PrimaryLayout&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;page&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;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(Note that I have downloaded this version of the Google logo from &lt;a href="https://en.wikipedia.org/wiki/Google_logo" rel="noopener noreferrer"&gt;its Wikipedia page&lt;/a&gt;, named it &lt;code&gt;Google.png&lt;/code&gt; and place it in the root &lt;code&gt;public&lt;/code&gt; directory of the project)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There's two new Next.js specific components showcased here that I'd like to cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/docs/api-reference/next/link" rel="noopener noreferrer"&gt;Link&lt;/a&gt; - Next provides a special kind of link that is used as a superpowered version of the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; anchor tag. You still use the anchor tag, but by wrapping it in a &lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt; with the &lt;code&gt;href&lt;/code&gt;, Next will handle a click to that link in a special way that preserves state in your application without a full page load and refresh (among other benefits described in the docs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have also taken advantage of the &lt;code&gt;locale&lt;/code&gt; value in the &lt;a href="https://nextjs.org/docs/api-reference/next/router#userouter" rel="noopener noreferrer"&gt;useRouter&lt;/a&gt; hook to handling efficiently toggling back and forth between locales. Try it yourself (you'll need to run the &lt;code&gt;yarn dev&lt;/code&gt; server to test it since you won't have access to routing in Storybook), but it works great for toggling back and forth between languages.&lt;/p&gt;

&lt;p&gt;Remember that our app's available locales can be customized in &lt;code&gt;next.config.js&lt;/code&gt; on the &lt;code&gt;i18n&lt;/code&gt; field. Right now we don't have any translation in place, so only the URL will switch (updating the text copy for &lt;code&gt;i18n&lt;/code&gt; support will be a topic of a future tutorial.)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/docs/api-reference/next/image" rel="noopener noreferrer"&gt;Image&lt;/a&gt; - Image handling in web development is surprisingly complicated, and as such, Next has created a special &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt; tag to replace the standard &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; which helps optimize your images on the server at build time and decide exactly the right one to serve to your users. The biggest immediate benefits here are load times (quality optimizations, PNG -&amp;gt; WEBP conversions as example) and also addressing &lt;a href="https://web.dev/cls/" rel="noopener noreferrer"&gt;Cumulative Layout Shift&lt;/a&gt; issues. I highly recommend you click the link to the docs to read more about it. In this example we are only using a small subset of the features available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to the Image component API docs, Next also includes a &lt;a href="https://nextjs.org/docs/basic-features/image-optimization" rel="noopener noreferrer"&gt;special section talking about how they manage image optimization&lt;/a&gt; which is well worth a read.&lt;/p&gt;

&lt;p&gt;Thanks to a few handy Tailwind classes, with the above version of &lt;code&gt;pages/index.tsx&lt;/code&gt; we now have a fully desktop and mobile friendly (simplified) clone of Google's homepage you can view on your dev server.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649529002%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-homepage-desktop_ec6w2x.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649529002%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-homepage-desktop_ec6w2x.png" alt="Google Custom Home Desktop"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649530936%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-homepage-mobile_n8cgpj.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649530936%2Fblogs%2Fnextjs-app-tailwind%2Fgoogle-homepage-mobile_n8cgpj.png" alt="Google Custom Home Mobile"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  (Optional) Storybook for Pages
&lt;/h3&gt;

&lt;p&gt;One could make the argument that Storybook isn't quite the right place to test full pages. It's more focused on the individual components than the complete integration of all of that.&lt;/p&gt;

&lt;p&gt;That said however, Storybook does have &lt;a href="https://storybook.js.org/docs/react/writing-stories/build-pages-with-storybook" rel="noopener noreferrer"&gt;full support for pages&lt;/a&gt; and recommendations for how to handle it, so with that in mind if you'd like to test your pages in Storybook then I'll show you the tools you'll need (at this stage) to get it working.&lt;/p&gt;

&lt;p&gt;The main challenge is always mocking functional dependencies. So for example Next's router does not exist in Storybook. Other future challenges will be authentication and internationalization.&lt;/p&gt;

&lt;p&gt;Each of these can be individually managed though with mock functions that provide sensible defaults, and most of the popular ones (including Next router) have addons to handle most of the config for you.&lt;/p&gt;

&lt;p&gt;Here's how to support Next Router in Storybook. Start by installing the addon and &lt;a href="https://storybook.js.org/addons/storybook-addon-next-router" rel="noopener noreferrer"&gt;reading its documentation&lt;/a&gt;.&lt;/p&gt;

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

yarn add -D storybook-addon-next-router


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

&lt;/div&gt;

&lt;p&gt;Then update your config files:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.storybook/main.js&lt;/code&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;addons&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storybook-addon-next-router&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;.storybook/preview.js&lt;/code&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;RouterContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/dist/shared/lib/router-context&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;..&lt;/span&gt;
  &lt;span class="na"&gt;nextRouter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouterContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then create a story for your page. Since you don't want to interfere with NExt's router by placing stories in your pages directory and potentially causing errors, I have created the &lt;code&gt;__stories__&lt;/code&gt; directory specifically for holding any page stories.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;__stories__/pages/index.stories.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;ComponentMeta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ComponentStory&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;@storybook/react&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;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&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="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="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;argTypes&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;as&lt;/span&gt; &lt;span class="nx"&gt;ComponentMeta&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ComponentStory&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Home&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649531711%2Fblogs%2Fnextjs-app-tailwind%2Fstorybook-next-router-pages_oz1zzn.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649531711%2Fblogs%2Fnextjs-app-tailwind%2Fstorybook-next-router-pages_oz1zzn.png" alt="Storybook Next Router"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there it is. Remember that the layout (Header and Footer) are applied by Next via a separate function call, so we only have the actual page content here for testing. If you want to test the layout use the &lt;code&gt;layouts/PrimaryLayout&lt;/code&gt; story.&lt;/p&gt;

&lt;p&gt;Things are in a good state so time to commit our progress with &lt;code&gt;git commit -m 'feat: build home page'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to align with this step of the tutorial, clone the &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and use &lt;code&gt;git checkout 9ff325aceb0e2096fa618d78489beec2c00dea12&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Front End: Results
&lt;/h2&gt;

&lt;p&gt;We still have the "Results" page to do, but the nice thing is there's a LOT of overlap so we really only have one more custom component to build (Search Result) as well as setting a variant of the layout (home is centered on the page while the results are left-aligned).&lt;/p&gt;

&lt;p&gt;Start by copying the &lt;code&gt;BaseTemplate&lt;/code&gt;, rename &lt;code&gt;base&lt;/code&gt; to &lt;code&gt;search-result&lt;/code&gt; and replace each instance of &lt;code&gt;BaseTemplate&lt;/code&gt; with &lt;code&gt;SearchResult&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/utility/search-result/SearchResult&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISearchResult&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SearchResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ISearchResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;divProps&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;divProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`flex flex-col w-5/6 max-w-screen-md space-y-1 &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; `&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"cursor:pointer hover:underline"&lt;/span&gt;
          &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;
          &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&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;url&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-blue-600 text-xl "&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;title&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&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;text&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;SearchResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then the mock data:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/utility/search-result/SearchResult.mocks.ts&lt;/code&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;ISearchResult&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;./SearchResult&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;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ISearchResult&lt;/span&gt; &lt;span class="o"&gt;=&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="s1"&gt;https://www.google.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is a link to a search result about product or service&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The topic of this link is product or service.  Description of the search result. The description might be a bit long and it will tell you everything you need to know about the search result.&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockSearchResultProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;base&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;Finally rename the story to &lt;code&gt;utility/SearchResult&lt;/code&gt; and load Storybook, our component will look like a real Google search result (or close enough for our purposes):&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649533888%2Fblogs%2Fnextjs-app-tailwind%2Fstorybook-search-result_t9dtyh.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649533888%2Fblogs%2Fnextjs-app-tailwind%2Fstorybook-search-result_t9dtyh.png" alt="Storybook Search Result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With our result in place, we are ready to create the results page. Create a &lt;code&gt;/results&lt;/code&gt; directory in the &lt;code&gt;/pages&lt;/code&gt; directory and that's all you need to do, Next will handle the routing for you.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/results/index.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PrimaryLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/layouts/primary/PrimaryLayout&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;SearchResult&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/utility/search-result/SearchResult&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;mockSearchResultProps&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;../../components/utility/search-result/SearchResult.mocks&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;NextPageWithLayout&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;../page&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;Results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPageWithLayout&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center gap-y-5"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`flex flex-col space-y-8`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SearchResult&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mockSearchResultProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PrimaryLayout&lt;/span&gt; &lt;span class="na"&gt;justify&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"items-start"&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;page&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;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Since the &lt;code&gt;/results&lt;/code&gt; page has its layout left aligned, we need to update out &lt;code&gt;PrimaryLayout.tsx&lt;/code&gt; to support a conditional prop. I've created the optional &lt;code&gt;justify&lt;/code&gt; prop below and used Typescript to allow the user two options: &lt;code&gt;items-center&lt;/code&gt; (default) and &lt;code&gt;items-start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/layouts/primary/PrimaryLayout.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Footer&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;../../navigation/footer/Footer&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;Header&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../navigation/header/Header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IPrimaryLayout&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;justify&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;items-center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;items-start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IPrimaryLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;justify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;items-center&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;divProps&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;NextJs Fullstack App Template&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;divProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`min-h-screen flex flex-col &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;justify&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"px-5"&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;children&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;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"m-auto"&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;Footer&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&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="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now start your dev server with &lt;code&gt;yarn dev&lt;/code&gt; and go to &lt;a href="http://localhost:3000/results" rel="noopener noreferrer"&gt;http://localhost:3000/results&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649535428%2Fblogs%2Fnextjs-app-tailwind%2Fresults-page_sqoln5.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649535428%2Fblogs%2Fnextjs-app-tailwind%2Fresults-page_sqoln5.png" alt="Results Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a good time to commit our progress with &lt;code&gt;git commit -m 'feat: create results page and SearchResult component'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There's a couple of things I'm going to be excluding from the clone for simplicity. Technically Google's results page still includes the search bar and even places it in the header on scroll.&lt;/p&gt;

&lt;p&gt;You could easily create a modified version of that component and place it as a child element into this page and the header, but in terms of this tutorial we wouldn't really touch on any new Next.js-specific topics by doing that (and that's what this tutorial is focused on), so to keep things moving forward I'll leave that as an optional challenge for you if you choose.&lt;/p&gt;

&lt;p&gt;If you want to align with this step of the tutorial, clone the &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and use &lt;code&gt;git checkout 3c4cf387cfd9112fe26c5dd268c293d7c1c00f5f&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back End Planning
&lt;/h2&gt;

&lt;p&gt;Now that we have the visual aspect of the application essentially feature complete (that we know of at this stage) it's time to move onto the back end.&lt;/p&gt;

&lt;p&gt;The great thing about Next.js is that it really is a complete full stack solution. Because pages are rendered on the server, obviously that means you have access to a server environment, and that means you can securely do things like access your database directly without needing to expose credentials to the client browser.&lt;/p&gt;

&lt;p&gt;The primary vehicles that Next.js uses to do this depends on whether your back end functions are designed to provide data directly to pages being rendered, or if they are standard APIs that simply return data to any source in any shape (usually JSON, but not necessarily).&lt;/p&gt;

&lt;p&gt;For the former, pages, we would use &lt;a href="https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props" rel="noopener noreferrer"&gt;getServerSideProps&lt;/a&gt; and for the latter we use &lt;a href="https://nextjs.org/docs/api-routes/introduction" rel="noopener noreferrer"&gt;API routes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to teach how they work, we'll be using both in this example.&lt;/p&gt;

&lt;p&gt;Let's begin by thinking about how our app would work if we were actually querying real data. A really simplistic ELI5 version of what Google does is that it crawls through all public data on the web and &lt;a href="https://www.google.com/search/howsearchworks/crawling-indexing/" rel="noopener noreferrer"&gt;index&lt;/a&gt; it so that it's organized in a way that is fast to search through (a simple example would be in alphabetical order).&lt;/p&gt;

&lt;p&gt;That index would be stored by Google in some kind of &lt;a href="https://en.wikipedia.org/wiki/Database" rel="noopener noreferrer"&gt;database&lt;/a&gt;. Let's ignore the obvious differences between our little imaginary database and the worldwide distributed datacentres they use, and just simplify it to "searching through existing text in some database."&lt;/p&gt;

&lt;p&gt;Adding a real database is beyond the scope of this tutorial (though it will be covered in a future one soon, likely using &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt; and &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;) so we're just going to create our own little pretend one that is close enough so that we can at least teach the fundamentals.&lt;/p&gt;

&lt;p&gt;Like many other aspects of web development, once you have the fundamentals, you can very quickly learn to work with any specific tool or implementation of those ideas.&lt;/p&gt;

&lt;p&gt;There are many ways to plan your back end, but personally I believe the most important first step is to begin with your data model. From there you build out any relationships between those data models, and modify as needed based on requirements.&lt;/p&gt;

&lt;p&gt;If you are fortunate enough to have a rock solid data model to begin with that all parties are aligned with, and a schema to enforce correctness, you will be in an extremely good position to build your application.&lt;/p&gt;

&lt;p&gt;In our case we have control of the data (since we are creating it) and as such I will simply design it to align with the information provided with the standard Google search results:&lt;/p&gt;

&lt;p&gt;We already began this work when we built the &lt;code&gt;SearchResult&lt;/code&gt; component so I am going to stick with those values for simplicity. You could definitely make the argument that &lt;code&gt;description&lt;/code&gt; is a more apt term than &lt;code&gt;text&lt;/code&gt;. Once again feel free to design your schema however you like, you don't need to follow what I've used to the letter.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649560767%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-result-data-model_x5hiyv.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649560767%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-result-data-model_x5hiyv.png" alt="Search Result Data Model"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have decided how the model for our search data will be shaped, we only need to decide how the app will get that data to our results page.&lt;/p&gt;

&lt;p&gt;My plan for the journey is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search value term is entered by user on &lt;code&gt;home&lt;/code&gt; page input form&lt;/li&gt;
&lt;li&gt;Form submission redirects to &lt;code&gt;results&lt;/code&gt; page with user's search value as a query parameter in the URL&lt;/li&gt;
&lt;li&gt;When rendering on server side, the &lt;code&gt;results&lt;/code&gt; page will query an API route (we will call it &lt;code&gt;/api/search&lt;/code&gt;) inside a &lt;code&gt;getServerSideProps&lt;/code&gt; function, which extracts the search value from the URL query param and passes it to the API route.&lt;/li&gt;
&lt;li&gt;The API route will query our mock database with the search value and provide the results filtered by the search value back to the &lt;code&gt;getServerSideProps&lt;/code&gt; function on the &lt;code&gt;results&lt;/code&gt; page.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;getServerSideProps&lt;/code&gt; function on the&lt;code&gt;results&lt;/code&gt; page will receive its search results then pass those results as props to the &lt;code&gt;results&lt;/code&gt; page component to render the data for the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll note that in this flow technically the &lt;code&gt;results&lt;/code&gt; page could just query the database directly in &lt;code&gt;getServerSideProps&lt;/code&gt;. There are two main reasons I've chosen not to do that however:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In a real app, other pages or even external services might have reason to query search results with a search value, so I don't want to tie that search logic specifically to the &lt;code&gt;results&lt;/code&gt; page&lt;/li&gt;
&lt;li&gt;More personally, I want to demonstrate how to use both API routes and &lt;code&gt;getServerSideProps&lt;/code&gt; in this tutorial.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now with all that planning in place, I think we are ready to build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back End: Search Data
&lt;/h2&gt;

&lt;p&gt;We'll begin with the mock database. When working with Node/Javascript/Typescript etc most real database that you query will be done using Node drivers for those DBs which will returns the results in JSON format. JSON is one of (if not THE) most popular formats for transmitting data on the web, so if your app can handle JSON payloads you'll be in very good shape to handle data from many different sources.&lt;/p&gt;

&lt;p&gt;That's the reason I've chosen to put our mock data inside a JSON file.&lt;/p&gt;

&lt;p&gt;We're going to begin using the &lt;code&gt;/lib&lt;/code&gt; directory in the root. If you recall from the initial tutorial that is the folder I created which will store all the domain &amp;amp; business logic and data that our application deals with.&lt;/p&gt;

&lt;p&gt;If "components" and "pages" are the &lt;em&gt;front end&lt;/em&gt; directories, then "lib" is our &lt;em&gt;back end&lt;/em&gt; directory (though we will leverage it from both sides to get all the benefits that come with that, hence the &lt;em&gt;full-stack&lt;/em&gt; app we are building).&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;/search&lt;/code&gt; directory inside of &lt;code&gt;/lib&lt;/code&gt;. This is where we will be placing all the logic related to the concept of search data and results. Within that we'll create a file called &lt;code&gt;database.json&lt;/code&gt; and populate it with the dummy data below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lib/search/database.json&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/Cat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is a link to a search result about cats"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Did you know their whiskers can sense vibrations in the air?  Description of the search result. The description might be a bit long and it will tell you everything you need to know about the search result."&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/Dog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is a link to a search result about dogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"They sure do love to bark.  Description of the search result. The description might be a bit long and it will tell you everything you need to know about the search result."&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/Cats_%26_Dogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is a link to a search result about both cats and dogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Both of them have tails.  Description of the search result. The description might be a bit long and it will tell you everything you need to know about the search result."&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/Broccoli"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is a link to a search result about broccoli"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Broccoli was invented by crossing cauliflower with pea seeds.  Description of the search result. The description might be a bit long and it will tell you everything you need to know about the search result."&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/Cauliflower"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is a link to a search result about cauliflower"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Who invented cauliflower?  Description of the search result. The description might be a bit long and it will tell you everything you need to know about the search result."&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've slightly modified the titles and text values so that we'll be able to perform real searches on the data and see the filtered results.&lt;/p&gt;

&lt;p&gt;I'm also going to create a Typescript interface that aligns with this data model. We'll be using that everywhere in our app to minimize errors when working with this data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;lib/search/types.ts&lt;/code&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;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISearchData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This interface is now the &lt;strong&gt;source of truth&lt;/strong&gt; for everything related to search data in the app. If we every change or add new fields, we add them here and then I want to see every API and every component in the app that uses that data to immediately break and throw a warning that I have to update those as well to handle the schema change.&lt;/p&gt;

&lt;p&gt;For that reason there is one place I need to update already. Our &lt;code&gt;SearchResult.tsx&lt;/code&gt; component has its own explicit type for url / title / text. Instead of that I'm going to refactor it to extend this type so they always remain aligned:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/utility/search-result/SearchResult.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="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;ISearchData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../../lib/search/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ISearchResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ISearchData&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Everything else below the ellipsis for the component is the same, only the type and imports have been updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back End: API Routes
&lt;/h2&gt;

&lt;p&gt;I'm going to begin with the data and work my way out. I've already created the data in the mock database. The next connection point to that data is our &lt;a href="https://nextjs.org/docs/api-routes/introduction" rel="noopener noreferrer"&gt;API route&lt;/a&gt; that will be loading it and returning a filtered version of it to whoever is querying.&lt;/p&gt;

&lt;p&gt;All API routes in Next by default begin with the &lt;code&gt;/api&lt;/code&gt; prefix to differentiate them from routes that you would expect to visit and receive an HTML page. Our search query API will be &lt;code&gt;/api/search&lt;/code&gt;, so create that structure now along with an &lt;code&gt;index.ts&lt;/code&gt; file. Since this is an API dealing with data and not a React component, we can just use the &lt;code&gt;.ts&lt;/code&gt; extension:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/pages/api/search/index.ts&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="c1"&gt;// Next.js API route support: https://nextjs.org/docs/api-routes/introduction&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextApiResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&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;database&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../../lib/search/database.json&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;ISearchData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../../lib/search/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IApiSearchRequest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;NextApiRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;IApiSearchResponseData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ISearchData&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&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;IApiSearchRequest&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="nx"&gt;NextApiResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IApiSearchResponseData&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Creates a regex search pattern for a case insensitive match from the user's search term&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchPattern&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;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i&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;filteredResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// Check the user's search term again either the title or the text of the database entry&lt;/span&gt;
        &lt;span class="nx"&gt;searchPattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;searchPattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredResults&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&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="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;Let's unpack the above.&lt;/p&gt;

&lt;p&gt;We'll start with the &lt;code&gt;database&lt;/code&gt;. We're very spoiled to have such amazing tooling in this day and age. By default Typescript will be able to handle the import of raw JSON files and even provide types for us based on the schema that it detects on the fields in the file. We don't even need to explicitly cast it.&lt;/p&gt;

&lt;p&gt;This behavior is enabled with the &lt;code&gt;esModuleInterop&lt;/code&gt; and &lt;code&gt;resolveJsonModule&lt;/code&gt; values in your &lt;code&gt;tsconfig.json&lt;/code&gt; file in the root of your project, both of which are enabled by default in the Next.js Typescript template we are using.&lt;/p&gt;

&lt;p&gt;The second is that we have decided that we will be expecting the user's &lt;code&gt;searchTerm&lt;/code&gt; on the body of a &lt;code&gt;POST&lt;/code&gt; request to get search results. If it's not a &lt;code&gt;POST&lt;/code&gt; request or the searchTerm is missing or empty, we are going to return a &lt;code&gt;400 Bad Request&lt;/code&gt; along with an empty JSON array to indicate there are no results due to a poorly formatted or invalid request. The benefit of this is that regardless of term we will be able to handle an expectation of an array in the response, either empty or not.&lt;/p&gt;

&lt;p&gt;The last key part here is the logic of the actual search. We convert the user's search term into a Javascript &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions" rel="noopener noreferrer"&gt;regular expression (aka regex)&lt;/a&gt; object with the &lt;code&gt;"i"&lt;/code&gt; flag which means &lt;em&gt;case insensitive&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you are unfamiliar or just not comfortable with regexes, an alternative option that accomplishes the same result would be to check if:&lt;/p&gt;

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

&lt;span class="nx"&gt;result&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="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The result of the string compare is used to filter out the complete list of all search results. Obviously if we were using real web indexes there's no possible way we would load ALL possible search results before processing, but this is an example and we know exactly the current size of our data, so our implementation is safe in that scope.&lt;/p&gt;

&lt;p&gt;Now let's test our endpoint before we go any further. If you're not familiar with API testing I would suggest you look into some of the great tools out there. &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; used to be the best, but they've started really locking things down behind sign-up walls. It does still have a workable free version though. &lt;a href="https://insomnia.rest/" rel="noopener noreferrer"&gt;Insomnia&lt;/a&gt; is a great alternative.&lt;/p&gt;

&lt;p&gt;If you're comfortable with the command line and you're on a Linux or Mac machine (or Windows with a command line version) the fastest way is to just use &lt;a href="https://en.wikipedia.org/wiki/CURL" rel="noopener noreferrer"&gt;cURL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below is the command that will make a search request to your API for the term &lt;code&gt;dog&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I've added a couple of &lt;code&gt;echo;&lt;/code&gt; in the screenshot just to add newlines to make it more readable -- there are tools to display formatted JSON on the command line too if you want to look them up and get really fancy, but all we care about now is if the payload is returned and is correct.&lt;/p&gt;

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

curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{"searchTerm":"dog"}' "http://localhost:3000/api/search"


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649570420%2Fblogs%2Fnextjs-app-tailwind%2Fcurl-api-search_hollju.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649570420%2Fblogs%2Fnextjs-app-tailwind%2Fcurl-api-search_hollju.png" alt="cURL API Test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's our result! If you look closely it's returned 2/5 entires from our mock database, the one about "dogs" and the one about "cats &amp;amp; dogs".&lt;/p&gt;

&lt;p&gt;Since our search term was &lt;code&gt;dog&lt;/code&gt; I'd say that's a good sign things are working well.&lt;/p&gt;

&lt;p&gt;Let's switch gears and set up your &lt;code&gt;results&lt;/code&gt; page to use this endpoint and get the search results to display.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static and Dynamic Pages in Next.js
&lt;/h2&gt;

&lt;p&gt;Now we are ready to introduce our first &lt;a href="https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props" rel="noopener noreferrer"&gt;getServerSideProps&lt;/a&gt; function. We'll be adding it to our results page so that we can take the search term from the URL of the initial request and use it to fetch search data that we render the page with.&lt;/p&gt;

&lt;p&gt;As soon as you introduce this function the page is no longer a candidate for &lt;a href="https://nextjs.org/docs/basic-features/pages#static-generation-recommended" rel="noopener noreferrer"&gt;static generation&lt;/a&gt;, which is the default behavior for pages in Next. If possible pages will always be generated when you build your app presuming they always look the same for every user. Our &lt;code&gt;home&lt;/code&gt; page is an example of that.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;results&lt;/code&gt; page however is going to look different all the time depending on the search term, so consequently Next will have to render that page dynamically every time a user requests it. The benefit obviously being the dynamic data and the downside being an increase in page load time.&lt;/p&gt;

&lt;p&gt;We'll begin by doing a simple test of the &lt;code&gt;getServerSideProps&lt;/code&gt; function by setting it up with a simple dummy prop.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/utility/search-result/SearchResult.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;GetServerSideProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&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;PrimaryLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/layouts/primary/PrimaryLayout&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;SearchResult&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../components/utility/search-result/SearchResult&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;ISearchData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../lib/search/types&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;IApiSearchResponseData&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;../api/search&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;NextPageWithLayout&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;../page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IResults&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ISearchData&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getServerSideProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GetServerSideProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IResults&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&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;query&lt;/span&gt;&lt;span class="p"&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="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IApiSearchResponseData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&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;searchTerm&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&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="s2"&gt;`http://localhost:3000/api/search`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&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="s1"&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="s1"&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="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="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;searchResults&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;response&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 3&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Will be passed to the page component as props&lt;/span&gt;
      &lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPageWithLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IResults&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;searchResults&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center gap-y-5"&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;hasResults&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`flex flex-col space-y-8`&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;searchResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&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="c1"&gt;// 4&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SearchResult&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;No results found.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&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="nt"&gt;section&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="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PrimaryLayout&lt;/span&gt; &lt;span class="na"&gt;justify&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"items-start"&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;page&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;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Hopefully you are able to get an idea how data is being passed in the example above. I would encourage you to read the &lt;a href="https://nextjs.org/docs/basic-features/data-fetching/overview" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; if you haven't already.&lt;/p&gt;

&lt;p&gt;There's a few critical things to understand and unpack here before we talk about what the actual page is doing.&lt;/p&gt;

&lt;p&gt;First of all, it's important to be aware that &lt;code&gt;getServerSideProps&lt;/code&gt; is a special function that must be named exactly that which is run automatically by Next as part of the page build process. Because of this you should not expect to be able to create a Story for this page in Storybook.&lt;/p&gt;

&lt;p&gt;Think of that as a good thing, we are talking about data fetching from our API, at this point we have moved away from the real purpose of Storybook. Ideally it should not be making API calls for data. Of course we could create a mock version of our &lt;code&gt;getServerSideProps&lt;/code&gt; function and configure Storybook to use it, but that's beyond the scope of this tutorial.&lt;/p&gt;

&lt;p&gt;For now, while we are working on the back end we will be doing all our testing on the development build by running &lt;code&gt;yarn dev&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Just before you run the dev server, let's talk about what's happening. There's a lot going on here so I've add four numbered 1-2-3-4 comments in the code above to talk about.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;query&lt;/code&gt; field on the context object that &lt;code&gt;getServerSideProps&lt;/code&gt; receives will have the query parameter from the URL. So this page is expecting to receive a URL like &lt;code&gt;/results?search=something&lt;/code&gt; and that "something" will be available as available on &lt;code&gt;query.search&lt;/code&gt; that we extract into the &lt;code&gt;searchTerm&lt;/code&gt; variable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Here we are querying our own APi we created! Same values and headers we did with cURL test. The search term will be what we extract from the URL, and we'll save the result in &lt;code&gt;searchResults&lt;/code&gt; which defaults to an empty array.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We must return an object with values on the &lt;code&gt;props&lt;/code&gt; field, that is what our page component will receive. All this is typesafe along the way including the return value, pay close attention to the three places the &lt;code&gt;IResults&lt;/code&gt; interface is used along the way.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We take whatever search data is returned and map it to our &lt;code&gt;SearchResult&lt;/code&gt; component. We already know the return data matches the expected props, so we can use the spread operator to very easily pass each prop at once.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now we are ready to run&lt;/p&gt;

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

yarn dev


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

&lt;/div&gt;

&lt;p&gt;And open the URL to &lt;a href="http://localhost:3000/results?search=dog" rel="noopener noreferrer"&gt;http://localhost:3000/results?search=dog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice the query param I added to the URL? It works! Try changing it yourself to other terms and see if you get different results. Some examples from the mock database would be &lt;code&gt;broccoli&lt;/code&gt; and &lt;code&gt;bark&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649652680%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-param-results_gyg9e0.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649652680%2Fblogs%2Fnextjs-app-tailwind%2Fsearch-param-results_gyg9e0.png" alt="Search Param Results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Time to commit our progress with &lt;code&gt;git commit -m 'feat: implement search API and results page query'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to align with this step of the tutorial, clone the &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and use &lt;code&gt;git checkout f7321a266c51528d2369bf5d5862bc4ace4fdfcb&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Front End Finishing Touches
&lt;/h2&gt;

&lt;p&gt;I'm going to have to backtrack a little bit, turns out there was one more front end task that I forgot before moving to the back end.&lt;/p&gt;

&lt;p&gt;We need to configure our &lt;code&gt;Search&lt;/code&gt; component to redirect to the results page and put the search term into the URL when it does so that our search bar actually works.&lt;/p&gt;

&lt;p&gt;This is quite easy to do, the necessary update to the &lt;code&gt;Search.tsx&lt;/code&gt; component looks like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/utility/search/Search.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="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;useState&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="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISearch&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;Search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ISearch&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1&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="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchTerm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-center gap-y-5"&lt;/span&gt;
      &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="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="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// 2&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;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/results?search=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"rounded-full border-2 w-5/6 sm:w-96 h-12 px-3"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nf"&gt;setSearchTerm&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="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-x-3"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"btn-primary"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Google Search
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
          &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FEATURE COMING SOON!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"btn-primary"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          I&lt;span class="ni"&gt;&amp;amp;apos;&lt;/span&gt;m Feeling Lucky
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;I've added some numbered comments on the code for reference.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We import Next's router which allows us to navigate to different pages while preserving all state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the &lt;code&gt;onSubmit&lt;/code&gt; function we use the router's &lt;code&gt;push&lt;/code&gt; function to navigate to the results page and set the search query param to the current value of the &lt;code&gt;searchTerm&lt;/code&gt; which is set by the input field.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've also added a silly &lt;em&gt;FEATURE COMING SOON!&lt;/em&gt; alert to the &lt;em&gt;I'm Feeling Lucky&lt;/em&gt; button, but don't hold your breath on that one.&lt;/p&gt;

&lt;p&gt;I think we're finally ready to take the entire app for a test drive. Start the dev server with &lt;code&gt;yarn dev&lt;/code&gt; and visit &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649653441%2Fblogs%2Fnextjs-app-tailwind%2Fapp-final-1_e5v1xk.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649653441%2Fblogs%2Fnextjs-app-tailwind%2Fapp-final-1_e5v1xk.png" alt="App Final 01"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649653441%2Fblogs%2Fnextjs-app-tailwind%2Fapp-final-2_dx6pei.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649653441%2Fblogs%2Fnextjs-app-tailwind%2Fapp-final-2_dx6pei.png" alt="App Final 02"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How cool is that? We just built our own functioning search engine. Ready to work at Google or NASA now right?&lt;/p&gt;

&lt;p&gt;Couple small features to keep in mind, you can return to home and search again by clicking the "Home" link. You can also search by typing your value and just pressing "enter" since it's a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element and the browser handles that behavior automatically by triggering &lt;code&gt;onSubmit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Time to commit our progress with &lt;code&gt;git commit -m 'feat: connect search input to results page'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you want to align with this step of the tutorial, clone the &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and use &lt;code&gt;git checkout&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Themes and Design Systems
&lt;/h2&gt;

&lt;p&gt;Although the app is "feature complete" as per the scope of this article, there is one final related topic that I want to touch on that I think is absolutely critical: &lt;a href="https://material.io/design/introduction#theming" rel="noopener noreferrer"&gt;theming&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The link I made above is not specific to Tailwind or any one particular implementation of a theme, because I wanted to first talk about the importance of theming as a concept before we apply it to our app.&lt;/p&gt;

&lt;p&gt;As you get more experienced and build more apps you'll realize your CSS naturally starts to look something like:&lt;/p&gt;

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

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.nav-bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.content-section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&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;This is a really contrived example, but you can probably see where I'm going. As your app grows and your CSS grows you end up using the same values over and over.&lt;/p&gt;

&lt;p&gt;Of course with modern CSS you can do something like &lt;code&gt;--primary-color: red;&lt;/code&gt; and then &lt;code&gt;background-color: var(--primary-color)&lt;/code&gt;, which in itself is already a great improvement, but often what you're looking for is to create a &lt;em&gt;consistent&lt;/em&gt; design system that automatically gets used as a default by the pieces of your app without even having to explicitly say it.&lt;/p&gt;

&lt;p&gt;Every core component that needs a color should just have &lt;code&gt;--primary-color&lt;/code&gt; on it by default rather than you having to be explicit about it. You should only need to do so if overriding it. Similarly with spacing, your app will feel a lot more consistent if all spacing between elements is a multiple of some value like &lt;code&gt;4px&lt;/code&gt; or &lt;code&gt;8px&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's what creating a design system (like Material Design for example) aims to do. Build a consistent look for your digital product and place a meaningful framework around it. A good design system will lead to a more consistent and predictable user experience, and also provide the path of least resistance for developers implementing it.&lt;/p&gt;

&lt;p&gt;This is just a very basic introduction, I am absolutely not a designer myself but I love working with good ones, because they make my job easier and our product better.&lt;/p&gt;

&lt;p&gt;The final part of this tutorial is going to look at Tailwind CSS's specific implementation of a design system and how you can use it to make your app better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design System with Tailwind
&lt;/h3&gt;

&lt;p&gt;Like everything, before we begin I always recommend you first read &lt;a href="https://tailwindcss.com/docs/theme" rel="noopener noreferrer"&gt;the documentation&lt;/a&gt;. Tailwind's docs are fantastic and will help you get up and running quickly.&lt;/p&gt;

&lt;p&gt;We actually already created a basic theme in the Tailwind installation section where we established the value of the different &lt;code&gt;xs&lt;/code&gt; &lt;code&gt;sm&lt;/code&gt; &lt;code&gt;md&lt;/code&gt; etc screen breakpoints for our app. The theme lives in &lt;code&gt;tailwind.config.js&lt;/code&gt; and we are going to expand on it.&lt;/p&gt;

&lt;p&gt;I revisited &lt;a href="https://www.google.com" rel="noopener noreferrer"&gt;Google&lt;/a&gt; again to see if there's any little changes we can make to closer align the styles, a couple easy ones are: Google uses the &lt;code&gt;Arial&lt;/code&gt; font, and the search bar is a bit wider than the max Tailwind static with we have available by default (&lt;code&gt;w-96&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;So rather than explicitly override our components, let's update our theme so that the rest of the app can benefit from those conventions!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tailwind.config.js&lt;/code&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/**/*.{js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/**/*.{js,ts,jsx,tsx}&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;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Ensure these match with .storybook/preview.js&lt;/span&gt;
    &lt;span class="na"&gt;screens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;375px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;600px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;md&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;900px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1200px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1536px&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;fontFamily&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;sans&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Arial&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sans-serif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;serif&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Garamond&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serif&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;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#1a73e8&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="na"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;32rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;I've updated the &lt;code&gt;fontFamily&lt;/code&gt; globally by setting the value there on the &lt;code&gt;theme&lt;/code&gt; object. Within that theme object I also have a nested object called &lt;code&gt;extends&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Any values I place on the theme will completely replace Tailwind's defaults, but setting values on the same values inside &lt;code&gt;extends&lt;/code&gt; will add those values in addition to the existing ones.&lt;/p&gt;

&lt;p&gt;I've overridden the &lt;code&gt;blue-500&lt;/code&gt; colour with the actual colour Google uses on their button based on using the handy eyedropper in Firefox &lt;em&gt;(More Tools -&amp;gt; Eyedropper)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649715221%2Fblogs%2Fnextjs-app-tailwind%2Fsign-in-button_aqp8jm.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649715221%2Fblogs%2Fnextjs-app-tailwind%2Fsign-in-button_aqp8jm.png" alt="Sign In Button Colour"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's what I've done with the new width 128 which will translate into a &lt;code&gt;w-128&lt;/code&gt; Tailwind class. Let's swap out the &lt;code&gt;w-96&lt;/code&gt; value for &lt;code&gt;w-128&lt;/code&gt; on our &lt;code&gt;Search&lt;/code&gt; component:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/utility/search/Search.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rounded-full border-2 w-5/6 sm:w-128 h-12 px-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&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="nf"&gt;setSearchTerm&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="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649714215%2Fblogs%2Fnextjs-app-tailwind%2FGoogle_Final_Product_t16fon.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649714215%2Fblogs%2Fnextjs-app-tailwind%2FGoogle_Final_Product_t16fon.png" alt="Final Product"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;There's more cool stuff you can do with the theme we didn't mention here. The &lt;a href="https://tailwindcss.com/docs/customizing-colors" rel="noopener noreferrer"&gt;colour specific documentation&lt;/a&gt; is worth a look, as is the concept of using a self-referencing function to get access to the theme value.&lt;/p&gt;

&lt;p&gt;For example if you wanted to set a &lt;code&gt;blue&lt;/code&gt; colour and then later reference that exact colour on a background while still on the theme itself with &lt;code&gt;theme('color.blue')&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing State Between Pages
&lt;/h2&gt;

&lt;p&gt;One topic that is critically important for large Next.js apps that we haven't yet addressed is the ability to share state between pages.&lt;/p&gt;

&lt;p&gt;In traditional single page React apps it's quite simple to pass your props or wrap the app in context, but how is that handled in Next when transitioning to a completely separate page?&lt;/p&gt;

&lt;p&gt;The answer is that we leverage the top level &lt;code&gt;_app.tsx&lt;/code&gt; component to manage our state. As long as we are using Next's built in router or the special Next &lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt; component, Next will be able to handle the persistance of state in our app between pages.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The same general rules for React state still apply, if the user refreshes the page or manually enters a URL it will be lost. In those cases if you want persistance you would want to look at &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage" rel="noopener noreferrer"&gt;localStorage&lt;/a&gt; or a state management packaged solution that includes support for local storage like &lt;a href="https://recoiljs.org/docs/guides/atom-effects/" rel="noopener noreferrer"&gt;Recoil&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Just for a quick demonstration of how to use it, we will be implementing a mock "auth" state that is controlled with our "Sign In" button. Our goal will be that your authenticated state will still persist even when hitting the search button and navigation to the &lt;code&gt;/results&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;We will be using &lt;a href="https://beta.reactjs.org/apis/usecontext" rel="noopener noreferrer"&gt;React context&lt;/a&gt; for this. Down the road when you implement a real auth service, you could potentially even connect it to this component we are going to create and replace the mock data with real data, while still using our context solution to control the UI state.&lt;/p&gt;

&lt;p&gt;First things first I think it's time to create an additional root directory. We need a place to store React specific logic (like context and custom hooks) that is not the same as pure UI (components) or domain logic and services (lib).&lt;/p&gt;

&lt;p&gt;Proper project structure is critically important and there are some great &lt;a href="https://www.robinwieruch.de/react-folder-structure/" rel="noopener noreferrer"&gt;resources about it&lt;/a&gt; out there. I want to find the right balance between too compact (too much unrelated in one directory) and too abstract (directories for every different concept no matter how small).&lt;/p&gt;

&lt;p&gt;For our use case I am going to create a root directory called &lt;code&gt;/state&lt;/code&gt; which will be intended to hold both custom hooks and React context. The two are usually tightly related so I am comfortable keeping them together for the time being.&lt;/p&gt;

&lt;p&gt;Within &lt;code&gt;/state&lt;/code&gt; I will create a directory called &lt;code&gt;/auth&lt;/code&gt; which will manage everything related to the state of authentication in our app.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;state/auth/AuthContext.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IAuthContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;login&lt;/span&gt;&lt;span class="p"&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="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;logOut&lt;/span&gt;&lt;span class="p"&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="k"&gt;void&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;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IAuthContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;login&lt;/span&gt;&lt;span class="p"&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="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;logOut&lt;/span&gt;&lt;span class="p"&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="kc"&gt;undefined&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;AuthContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IAuthContext&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;defaultValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAuthenticated&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticated&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;login&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="nf"&gt;setAuthenticated&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logOut&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="nf"&gt;setAuthenticated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AuthContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logOut&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&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;AuthContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;AuthContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The above component will provide context to our entire application that any component can use to check if the user is authenticated to see certain content. When that authentication state changes (using one of the two handy login/logOut functions we have provided) then all children of the context provider will re-render and update their state.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note when I say all children I mean &lt;strong&gt;ALL&lt;/strong&gt; children, even ones that don't use the authenticated context value. This is an important concept to understand, I would recommend you read more about it if you aren't familiar with that concept. &lt;a href="https://beta.reactjs.org/apis/usecontext#optimizing-re-renders-when-passing-objects-and-functions" rel="noopener noreferrer"&gt;This&lt;/a&gt; is a place to start. It's one of the reasons why global state management libraries like Redux and Recoil are so widely used is that they have ways of working around this behavior if you need to)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We will create a new button component called &lt;code&gt;AuthButton&lt;/code&gt;. This component is going to be dependent on the context provided by &lt;code&gt;AuthContext&lt;/code&gt;, so we need to remember that when we use this button somewhere up the component tree we will need an &lt;code&gt;AuthContext.Provider&lt;/code&gt; component for it to work -- the trick is to remember that's not just for our app, that applies to Storybook as well! For now though, let's just build the component.&lt;/p&gt;

&lt;p&gt;Copy our &lt;code&gt;BaseComponent&lt;/code&gt; over again into the &lt;code&gt;/components/button&lt;/code&gt; directory and rename it to &lt;code&gt;auth&lt;/code&gt;. We're going to replace all instances of &lt;code&gt;BaseComponent&lt;/code&gt; with &lt;code&gt;AuthButton&lt;/code&gt; including the filename. Make sure you also change the story title to &lt;code&gt;buttons/AuthButton&lt;/code&gt; and remove any most data from the template.&lt;/p&gt;

&lt;p&gt;The structure of the &lt;code&gt;AuthButton&lt;/code&gt; already exists, we are going to extract it out of our &lt;code&gt;Header&lt;/code&gt; component into its own component like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/buttons/auth/AuthButton.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;useContext&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AuthContext&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;../../../state/auth/AuthContext&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;styles&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;./AuthButton.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IAuthButton&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AuthButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IAuthButton&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;buttonProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logOut&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;logOut&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&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;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; border-1 p-2 px-4 sm:px-6 bg-blue-500 rounded text-white w-28`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;buttonProps&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;authenticated&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sign Out&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sign In&lt;/span&gt;&lt;span class="dl"&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;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;AuthButton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Pay attention to the &lt;code&gt;useContext&lt;/code&gt; invocation, that is how twe consume the &lt;code&gt;&amp;lt;AuthProvider&amp;gt;&lt;/code&gt; context that will be wrapping our entire application. We'll get to that part last. The next step is to take this new auth button use it in our &lt;code&gt;Header&lt;/code&gt;:&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AuthButton&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;../../buttons/auth/AuthButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IHeader&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ComponentPropsWithoutRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IHeader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;headerProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;headerProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`w-full flex flex-row justify-between &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-x-5 m-5"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hover:underline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hover:underline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Store&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"space-x-5 m-5"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hover:underline hidden sm:inline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Gmail&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hover:underline hidden sm:inline"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Images&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AuthButton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Finally we need to update &lt;code&gt;_app.tsx&lt;/code&gt; which is the component that wraps our whole app. We want every piece of our app to have access to the Auth context, so right now that serves as the best place for it.&lt;/p&gt;

&lt;p&gt;Technically every time the auth updates the app will re-render, but that is okay since presumably a real user would only be signing in once per session.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/_app.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/app&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;AuthProvider&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;../state/auth/AuthContext&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./globals.css&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;NextPageWithLayout&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;./page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AppPropsWithLayout&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPageWithLayout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;AppPropsWithLayout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Use the layout defined at the page level, if available&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;||&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;getLayout&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And finally, if we want to be able to access these context values for the components when we run them in Storybook, we need to create a default story template that includes that context.&lt;/p&gt;

&lt;p&gt;For that we use Storybook decorators. Just export a const called &lt;code&gt;decorators&lt;/code&gt; which React component(s) you want as a wrapper around all your stories.&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;AuthProvider&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;../state/auth/AuthContext&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decorators&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Story&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuthProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Story&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/AuthProvider&lt;/span&gt;&lt;span class="err"&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;Thats it! Now run &lt;code&gt;yarn dev&lt;/code&gt; and load &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you click on the "Sign In" button if all has gone correct it will toggle to a "Sign Out" which mimics the function of having logged into the site. Doing this is basic React behavior to toggle a button state.&lt;/p&gt;

&lt;p&gt;What is special about what we have done is when you enter a term into your search bar and hit search. It will navigate to a completely different page, the results page, but because of the React auth context wrapper your button should still show "Sign Out" if you had signed in on the home page.&lt;/p&gt;

&lt;p&gt;And that is persistent state between routes in Next.js&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Remember that all code from this tutorial as a complete package is available in &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please check some of my other learning tutorials. Feel free to leave a comment or question and share with others if you find any of them helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-build-scalable-architecture-for-your-nextjs-project-2pb7"&gt;How to Build Scalable Architecture for your Next.js Project&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-connect-a-react-app-to-a-notion-database-51mc"&gt;How to Connect a React App to a Notion Database&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-nodejs-to-backup-your-personal-files-and-learn-some-webdev-skills-along-the-way-541a"&gt;How to use Node.js to backup your personal files&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/docker-for-javascript-developers-41me"&gt;Introduction to Docker for Javascript Developers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg"&gt;Learnings from React Conf 2021&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg"&gt;How to Create a Dark Mode Component in React&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34"&gt;How to Analyze and Improve your 'Create React App' Production Build &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe"&gt;How to Create and Publish a React Component Library&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-indexeddb-to-store-data-for-your-web-application-in-the-browser-1o90"&gt;How to use IndexedDB to Store Local Data for your Web App &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g"&gt;Running a Local Web Server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-linters-eslint-59pm"&gt;ESLint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-prettier-214j"&gt;Prettier&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp"&gt;Babel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7"&gt;React &amp;amp; JSX&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-1-2mn1"&gt;Webpack: The Basics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>How to Build Scalable Architecture for your Next.js Project</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Wed, 06 Apr 2022 23:45:38 +0000</pubDate>
      <link>https://dev.to/alexeagleson/how-to-build-scalable-architecture-for-your-nextjs-project-2pb7</link>
      <guid>https://dev.to/alexeagleson/how-to-build-scalable-architecture-for-your-nextjs-project-2pb7</guid>
      <description>&lt;p&gt;All code from this tutorial as a complete package is available in &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you find this tutorial helpful, please share it with your friends and colleagues! For more like it you can subscribe on &lt;a href="https://www.youtube.com/channel/UCV5YqK3AaInd3lYFQqlp7Lw" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/eagleson_alex" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This tutorial is available as a video lesson if you prefer that format:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Iu5aZDqZt8E"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What is Next.js?&lt;/li&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Project Setup&lt;/li&gt;
&lt;li&gt;Engine Locking&lt;/li&gt;
&lt;li&gt;Git Setup&lt;/li&gt;
&lt;li&gt;Code Formatting and Quality Tools&lt;/li&gt;
&lt;li&gt;Git Hooks&lt;/li&gt;
&lt;li&gt;VS Code Configuration&lt;/li&gt;
&lt;li&gt;Debugging&lt;/li&gt;
&lt;li&gt;Directory Structure&lt;/li&gt;
&lt;li&gt;Adding Storybook&lt;/li&gt;
&lt;li&gt;Creating a Component Template&lt;/li&gt;
&lt;li&gt;Using the Component Template&lt;/li&gt;
&lt;li&gt;Adding a Custom Document&lt;/li&gt;
&lt;li&gt;Adding Layouts&lt;/li&gt;
&lt;li&gt;Deployment&lt;/li&gt;
&lt;li&gt;Next Steps&lt;/li&gt;
&lt;li&gt;Wrapping Up&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is Next.js?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;"Next.js gives you the best developer experience with all the features you need for production: hybrid static &amp;amp; server rendering, TypeScript support, smart bundling, route pre-fetching, and more. No config needed."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As described in their words above, Next.js is very much an all-in-one fullstack modern application building solution. It includes first class support for Typescript and React, while offering easy solutions for some of the most common requirements in a modern application like routing, API, postCSS tools, and code-splitting.&lt;/p&gt;

&lt;p&gt;It also supports both static site generation (for lightning fast static HTML pages that can be hosted anywhere) or with managed hosting services like Vercel/AWS/etc that run a Node server and support full on-demand data loading and server-side rendered pages.&lt;/p&gt;

&lt;p&gt;Next.js has quickly become one of the most in demand skills in the web development space. This tutorial aims to act as kind of a "practical" extension to the &lt;a href="https://nextjs.org/docs/getting-started" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; and help you set up a project using a lot of best practices that will improve your chances of keeping everything management as you scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This tutorial is not meant to replace the official documentation, which is absolutely fantastic. I highly recommend you take a read through at least the &lt;a href="https://nextjs.org/docs/basic-features/pages" rel="noopener noreferrer"&gt;basic features&lt;/a&gt; section before you begin this tutorial, so you'll be familiar with the terminology and tools and some of the components they provide that are similar, but usually "more powerful" versions of their vanilla HTML counterparts.&lt;/p&gt;

&lt;p&gt;Please review the table of contents to get an idea of each of the topics we will be touching in this extensive tutorial. I will freely acknowledge many of them are strict and opinionated configurations, if any of tem don't appeal to you then in most cases you can simply skip over those sections and should still be able to complete the tutorial without too much trouble.&lt;/p&gt;

&lt;p&gt;Now, with all that said, if you are ready, let's dive right in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;We'll begin by creating a default Next.js application with a Typescript template.&lt;/p&gt;

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

npx create-next-app &lt;span class="nt"&gt;--ts&lt;/span&gt; nextjs-fullstack-app-template

&lt;span class="nb"&gt;cd &lt;/span&gt;nextjs-fullstack-app-template


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

&lt;/div&gt;

&lt;p&gt;First we will test to make sure the app is working. We're going to be using &lt;code&gt;yarn&lt;/code&gt; for this example, but you could just as easily use NPM if you choose.&lt;/p&gt;

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

yarn install

yarn dev


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

&lt;/div&gt;

&lt;p&gt;You should see the demo app available on &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649125549%2Fblogs%2Fnextjs-fullstack-app-template%2Ffirst-load_sm29jf.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649125549%2Fblogs%2Fnextjs-fullstack-app-template%2Ffirst-load_sm29jf.png" alt="First Page Load"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also recommended to run&lt;/p&gt;

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

yarn build


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

&lt;/div&gt;

&lt;p&gt;To ensure you can successfully do a production build of the project. It's recommended (but not required) to close your dev server when running a Next.js build. Most of the time there is no issue but occasionally the build can put your dev server in a weird state that requires a restart.&lt;/p&gt;

&lt;p&gt;You should get a nice little report on the command line of all the pages built with green coloured text implying they are small and efficient. We'll try to keep them that way as we develop the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Engine Locking
&lt;/h2&gt;

&lt;p&gt;We would like for all developers working on this project to use the same Node engine and package manager we are using. To do that we create two new files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.nvmrc&lt;/code&gt; - Will tell other uses of the project which version of Node is used&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.npmrc&lt;/code&gt; - Will tell other users of the project which package manager is used&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are using &lt;code&gt;Node v14 Fermium&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; for this project so we set those values like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.nvmrc&lt;/code&gt;&lt;/p&gt;

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

lts/fermium


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;.npmrc&lt;/code&gt;&lt;/p&gt;

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

engine-strict=true


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

&lt;/div&gt;

&lt;p&gt;The reason we are using v14 instead of v16 for Node is that later in the tutorial we will be deploying on Vercel which unfortunately still does not support Node 16. Perhaps by the time you read this tutorial it might. You can follow the progress &lt;a href="https://github.com/vercel/community/discussions/37" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can check your version of Node with &lt;code&gt;node --version&lt;/code&gt; and make sure you are setting the correct one. A list of Node version codenames can be found &lt;a href="https://github.com/nodejs/Release/blob/main/CODENAMES.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that the use of &lt;code&gt;engine-strict&lt;/code&gt; didn't specifically say anything about &lt;code&gt;yarn&lt;/code&gt;, we do that in &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"nextjs-fullstack-app-template"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_NAME"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A tutorial and template for creating a production-ready fullstack Next.js application"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"private"&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="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&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="s2"&gt;"MIT"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"homepage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_GIT_REPO_URL"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"engines"&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;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=14.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"yarn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=1.22.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"npm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"please-use-yarn"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;engines&lt;/code&gt; field is where you specify the specific versions of the tools you are using. You can also fill in your personal details if you choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Setup
&lt;/h2&gt;

&lt;p&gt;This would be a good time to make our first commit to our remote repo, to make sure our changes are backed up, and to follow best practices for keeping related changes grouped within a single commit before moving to something new.&lt;/p&gt;

&lt;p&gt;By default your Next.js project will already have a repo initialized. You can check what branch you are on with &lt;code&gt;git status&lt;/code&gt;. It should say something like:&lt;/p&gt;

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

On branch main
Changes not staged for commit:
  (use "git add &amp;lt;file&amp;gt;..." to update what will be committed)
  (use "git restore &amp;lt;file&amp;gt;..." to discard changes in working directory)
        modified:   README.md

Untracked files:
  (use "git add &amp;lt;file&amp;gt;..." to include in what will be committed)
        .npmrc
        .nvmrc


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

&lt;/div&gt;

&lt;p&gt;This tells us we are on the &lt;code&gt;main&lt;/code&gt; branch and we have not staged or made any commits yet.&lt;/p&gt;

&lt;p&gt;Let's commit our changes so far.&lt;/p&gt;

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

git add .

git commit -m 'project initialization'


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

&lt;/div&gt;

&lt;p&gt;The first command will add and stage all files in your project directory that aren't ignored in &lt;code&gt;.gitignore&lt;/code&gt;. The second will make a commit of the state of your current project with the message we wrote after the &lt;code&gt;-m&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;Hop over to your preferred git hosting provider (&lt;a href="https://github.com" rel="noopener noreferrer"&gt;Github&lt;/a&gt; for example) and create a new repository to host this project. Make sure the default branch is se tto the same name as the branch on your local machine to avoid any confusion.&lt;/p&gt;

&lt;p&gt;On Github you can change your global default branch name to whatever you like by going to:&lt;/p&gt;

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

Settings -&amp;gt; Repositories -&amp;gt; Repository default branch


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

&lt;/div&gt;

&lt;p&gt;Now you are ready to add the remote origin of your repository and push. Github will give you the exact instructions when you create it. Your syntax may be a little different than mine depending on if you are using HTTPS rather than SSH.&lt;/p&gt;

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

git remote add origin git@github.com:{YOUR_GITHUB_USERNAME}/{YOUR_REPOSITORY_NAME}.git

git push -u origin {YOUR_BRANCH_NAME}


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

&lt;/div&gt;

&lt;p&gt;Note that from this point on we will be using the &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/#summary" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt; standard and specifically the Angular convention &lt;a href="https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type" rel="noopener noreferrer"&gt;described here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason being like many other features in this project to simply set a &lt;strong&gt;consistent&lt;/strong&gt; standard for all developers to use to minimize train-up time when contributing to the project. I personally have very little concern as to what standard is chosen, as long as everyone agrees to follow it that is the most important thing.&lt;/p&gt;

&lt;p&gt;Consistency is everything!&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Formatting and Quality Tools
&lt;/h2&gt;

&lt;p&gt;In order to set a standard that will be used by all contributors to the project to keep the code style consistent and basic best practices followed we will be implementing two tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://eslint.org/" rel="noopener noreferrer"&gt;eslint&lt;/a&gt; - For best practices on coding standards&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;prettier&lt;/a&gt; - For automatic formatting of code files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ESLint
&lt;/h3&gt;

&lt;p&gt;We'll begin with ESLint, which is easy because it automatically comes installed and pre-configured with Next.js projects.&lt;/p&gt;

&lt;p&gt;We are just going to add a little bit of extra configuration and make it a bit stricter than it is by default. If you disagree with any of the rules it sets, no need to worry, it's very easy to disable any of them manually. We configure everything in &lt;code&gt;.eslintrc.json&lt;/code&gt; which should already exist in your root directory:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.eslintrc.json&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"extends"&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="s2"&gt;"next"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next/core-web-vitals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint:recommended"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"globals"&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;"React"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"readonly"&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;"rules"&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;"no-unused-vars"&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="mi"&gt;1&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;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"after-used"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"argsIgnorePattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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="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;In the above small code example we have added a few additional defaults, we have said that &lt;code&gt;React&lt;/code&gt; will always be defined even if we don't specifically import it, and I have added a personal custom rule that I like which allows you to prefix variables with an underscore _ if you have declared them but not used them in the code.&lt;/p&gt;

&lt;p&gt;I find that scenario comes up often when you are working on a feature and want to prepare variables for use later, but have not yet reached the point of implementing them.&lt;/p&gt;

&lt;p&gt;You can test out your config by running:&lt;/p&gt;

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

yarn lint


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

&lt;/div&gt;

&lt;p&gt;You should get a message like:&lt;/p&gt;

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

✔ No ESLint warnings or errors
Done in 1.47s.


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

&lt;/div&gt;

&lt;p&gt;If you get any errors then ESLint is quite good at explaining clearly what they are. If you encounter a rule you don't like you can disable it in "rules" by simply setting it to 1 (warning) or 0 (ignore) like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&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;"no-unused-vars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;As&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;example:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;never&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;about&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;unused&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;variables&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;again&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;Let's make a commit at this point with the message &lt;code&gt;build: configure eslint&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prettier
&lt;/h3&gt;

&lt;p&gt;Prettier will take care of automatically formatting our files for us. Let's add it to the project now.&lt;/p&gt;

&lt;p&gt;It's only needed during development, so I'll add it as a &lt;code&gt;devDependency&lt;/code&gt; with &lt;code&gt;-D&lt;/code&gt;&lt;/p&gt;

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

yarn add -D prettier


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

&lt;/div&gt;

&lt;p&gt;I also recommend you get the &lt;a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode" rel="noopener noreferrer"&gt;Prettier VS Code extension&lt;/a&gt; so that VS Code can handle the formatting of the files for you and you don't need to rely on the command line tool. Having it installed and configured in your project means that VSCode will use your project's settings, so it's still necessary to add it here.&lt;/p&gt;

&lt;p&gt;We'll create two files in the root:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.prettierrc&lt;/code&gt;&lt;/p&gt;

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

{
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true
}


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

&lt;/div&gt;

&lt;p&gt;Those values are entirely at your discretion as to what is best for your team and project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.prettierignore&lt;/code&gt;&lt;/p&gt;

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

.yarn
.next
dist
node_modules


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

&lt;/div&gt;

&lt;p&gt;In that file I've placed a list of directories that I don't want Prettier to waste any resources working on. You can also use patterns like *.html to ignore groups of types of files if you choose.&lt;/p&gt;

&lt;p&gt;Now we add a new script to &lt;code&gt;package.json&lt;/code&gt; so we can run Prettier:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;

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

  ...
  "scripts: {
    ...
    "prettier": "prettier --write ."
  }


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

&lt;/div&gt;

&lt;p&gt;You can now run&lt;/p&gt;

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

yarn prettier


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

&lt;/div&gt;

&lt;p&gt;to automatically format, fix and save all files in your project you haven't ignored. By default my formatter updated about 5 files. You can see them in your list of changed files in the source control tab on the left of VS Code.&lt;/p&gt;

&lt;p&gt;Let's make another commit with &lt;code&gt;build: implement prettier&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Hooks
&lt;/h2&gt;

&lt;p&gt;One more section on configuration before we start getting into component development. Remember you're going to want this project to be as rock solid as possible if you're going to be building on it in the long term, particularly with a team of other developers. It's worth the time to get it right at the start.&lt;/p&gt;

&lt;p&gt;We are going to implement a tool called &lt;a href="https://typicode.github.io/husky/#/" rel="noopener noreferrer"&gt;Husky&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Husky is a tool for running scripts at different stages of the git process, for example add, commit, push, etc. We would like to be able to set certain conditions, and only allow things like commit and push to succeed if our code meets those conditions, presuming that it indicates our project is of acceptable quality.&lt;/p&gt;

&lt;p&gt;To install Husky run&lt;/p&gt;

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

yarn add -D husky

npx husky install


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

&lt;/div&gt;

&lt;p&gt;The second command will create a &lt;code&gt;.husky&lt;/code&gt; directory in your project. This is where your hooks will live. Make sure this directory is included in your code repo as it's intended for other developers as well, not just yourself.&lt;/p&gt;

&lt;p&gt;Add the following script to your &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;

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

  ...
  "scripts: {
    ...
    "prepare": "husky install"
  }


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

&lt;/div&gt;

&lt;p&gt;This will ensure Husky gets installed automatically when other developers run the project.&lt;/p&gt;

&lt;p&gt;To create a hook run&lt;/p&gt;

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

npx husky add .husky/pre-commit "yarn lint"


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

&lt;/div&gt;

&lt;p&gt;The above says that in order for our commit to succeed, the &lt;code&gt;yarn lint&lt;/code&gt; script must first run and succeed. "Succeed" in this context means no errors. It will allow you to have warnings (remember in the ESLint config a setting of 1 is a warning and 2 is an error in case you want to adjust settings).&lt;/p&gt;

&lt;p&gt;Let's create a new commit with the message &lt;code&gt;ci: implement husky&lt;/code&gt;. If all has been setup properly your lint script should run before the commit is allowed to occur.&lt;/p&gt;

&lt;p&gt;We're going to add another one:&lt;/p&gt;

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

npx husky add .husky/pre-push "yarn build"


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

&lt;/div&gt;

&lt;p&gt;The above ensures that we are not allowed to push to the remote repository unless our code can successfully build. That seems like a pretty reasonable condition doesn't it? Feel free to test it by committing this change and trying to push.&lt;/p&gt;




&lt;p&gt;Lastly we are going to add one more tool. We have been following a standard convention for all our commit messages so far, let's ensure that everyone on the team is following them as well (including ourselves!). We can add a linter for our commit messages:&lt;/p&gt;

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

yarn add -D @commitlint/config-conventional @commitlint/cli


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

&lt;/div&gt;

&lt;p&gt;To configure it we will be using a set of standard defaults, but I like to include that list explicitly in a &lt;code&gt;commitlint.config.js&lt;/code&gt; file since I sometimes forget what prefixes are available:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;commitlint.config.js&lt;/code&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;// build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)&lt;/span&gt;
&lt;span class="c1"&gt;// ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)&lt;/span&gt;
&lt;span class="c1"&gt;// docs: Documentation only changes&lt;/span&gt;
&lt;span class="c1"&gt;// feat: A new feature&lt;/span&gt;
&lt;span class="c1"&gt;// fix: A bug fix&lt;/span&gt;
&lt;span class="c1"&gt;// perf: A code change that improves performance&lt;/span&gt;
&lt;span class="c1"&gt;// refactor: A code change that neither fixes a bug nor adds a feature&lt;/span&gt;
&lt;span class="c1"&gt;// style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)&lt;/span&gt;
&lt;span class="c1"&gt;// test: Adding missing tests or correcting existing tests&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@commitlint/config-conventional&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-leading-blank&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-max-line-length&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;footer-leading-blank&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;footer-max-line-length&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;header-max-length&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scope-case&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lower-case&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subject-case&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;never&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sentence-case&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start-case&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pascal-case&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;upper-case&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subject-empty&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;never&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subject-full-stop&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;never&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type-case&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lower-case&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type-empty&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;never&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;type-enum&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;always&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ci&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;perf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;refactor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;revert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;style&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;translation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;security&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;changeset&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then enable commitlint with Husky by using:&lt;/p&gt;

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

npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
# Sometimes above command doesn't work in some command interpreters
# You can try other commands below to write npx --no -- commitlint --edit $1
# in the commit-msg file.
npx husky add .husky/commit-msg \"npx --no -- commitlint --edit '$1'\"
# or
npx husky add .husky/commit-msg "npx --no -- commitlint --edit $1"


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

&lt;/div&gt;

&lt;p&gt;Feel free to try some commits that &lt;em&gt;don't&lt;/em&gt; follow the rules and see how they are not accepted, and you receive feedback that is designed to help you correct them.&lt;/p&gt;

&lt;p&gt;I'm going to create a new commit now with the message &lt;code&gt;ci: implement commitlint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can see the result of the complete culmination of this setup in the screenshot below, hopefully yours looks similar:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649129725%2Fblogs%2Fnextjs-fullstack-app-template%2Fdev-experience_wznie9.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649129725%2Fblogs%2Fnextjs-fullstack-app-template%2Fdev-experience_wznie9.png" alt="Dev Experience"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  VS Code Configuration
&lt;/h2&gt;

&lt;p&gt;Now that we have implemented ESLint and Prettier we can take advantage of some convenient VS Code functionality to have them be run automatically.&lt;/p&gt;

&lt;p&gt;Create a directory in the root of your project called &lt;code&gt;.vscode&lt;/code&gt; and inside a file called &lt;code&gt;settings.json&lt;/code&gt;. This will be a list of values that override the default settings of your installed VS Code.&lt;/p&gt;

&lt;p&gt;The reason we want to place them in a folder for the project is that we can set specific settings that only apply to this project, and we can share them with the rest of our team by including them in the code repository.&lt;/p&gt;

&lt;p&gt;Within &lt;code&gt;settings.json&lt;/code&gt; we will add the following values:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.vscode/settings.json&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbenp.prettier-vscode"&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.formatOnSave"&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;"editor.codeActionsOnSave"&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;"source.fixAll"&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;"source.organizeImports"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;

&lt;p&gt;The above will tell VS Code to use your Prettier extension as the default formatter (you can override manually if you wish with another one) and to automatically format your files and organize your import statements every time you save.&lt;/p&gt;

&lt;p&gt;Very handy stuff and just another thing you no longer need to think about so you can focus on the important things like solving business problems.&lt;/p&gt;

&lt;p&gt;I'll now make a commit with message &lt;code&gt;build: implement vscode project settings&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging
&lt;/h2&gt;

&lt;p&gt;Let's set up a convenient environment for debugging our application in case we run into any issues during development.&lt;/p&gt;

&lt;p&gt;Inside of your &lt;code&gt;.vscode&lt;/code&gt; directory create a &lt;code&gt;launch.json&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;launch.json&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&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;"Next.js: debug server-side"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node-terminal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&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;"npm run dev"&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;"Next.js: debug client-side"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pwa-chrome"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000"&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;"Next.js: debug full stack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node-terminal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&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;"npm run dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"console"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integratedTerminal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"serverReadyAction"&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;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"started server on .+, url: (https?://.+)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"uriFormat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"debugWithChrome"&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;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;With that script in place you have three choices for debugging. CLick the little "bug &amp;amp; play icon" on the left of VS Code or press &lt;code&gt;Ctrl + Shift + D&lt;/code&gt; to access the debugging menu. You can select which script you want to run and start/stop it with the start/stop buttons.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649168143%2Fblogs%2Fnextjs-fullstack-app-template%2Fvscode-debugger_x1puqk.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649168143%2Fblogs%2Fnextjs-fullstack-app-template%2Fvscode-debugger_x1puqk.png" alt="VS Code Debugger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to this, or if you are not using VS Code, we can also set up some helpful debugging scripts in your project.&lt;/p&gt;

&lt;p&gt;First we will install the &lt;a href="https://www.npmjs.com/package/cross-env" rel="noopener noreferrer"&gt;cross-env&lt;/a&gt; which will; be necessary to set environment variables if you have teammates working on different environments (Windows, Linux, Mac, etc).&lt;/p&gt;

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

yarn add -D cross-env


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

&lt;/div&gt;

&lt;p&gt;With that package installed we can update our &lt;code&gt;package.json&lt;/code&gt; &lt;code&gt;dev&lt;/code&gt; script to look like the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="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="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env NODE_OPTIONS='--inspect' next dev"&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;This will allow you to log server data in the browser while working in dev mode, making it easier to debug issues.&lt;/p&gt;

&lt;p&gt;At this stage I'll be making a new commit with message &lt;code&gt;build: add debugging configuration&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Directory Structure
&lt;/h2&gt;

&lt;p&gt;This section is now going to cover setting up the folder structure in our project. This is one of those topics that many people will have &lt;em&gt;extremely strong opinions about&lt;/em&gt;, and for good reason! Directory structure can really make or break a project in the long term when it gets out of control, especially when fellow team members have to spend unnecessary time trying to guess where to put things (or find things).&lt;/p&gt;

&lt;p&gt;I personally like to take a fairly simplistic approach, keep things separated basically in a class model/view style. We will be using three primary folders:&lt;/p&gt;

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

/components
/lib
/pages


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;component&lt;/code&gt; - The individual UI components that make up the app will live in here&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lib&lt;/code&gt; - Business/app/domain logic will live in here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pages&lt;/code&gt; - Will be the actual routes/pages as per the required Next.js structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will have other folders in addition to this to support the project, but the core of almost everything that makes up the unique app that we are building will be housed in these three directories.&lt;/p&gt;

&lt;p&gt;Within &lt;code&gt;components&lt;/code&gt; we will have subdirectories that kind of group similar types of components together. You can use any method you prefer to do this. I have used the MUI library quite a bit in my time, so I tend to follow the same organization they use for components in &lt;a href="https://mui.com/getting-started/installation/" rel="noopener noreferrer"&gt;their documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example inputs, surfaces, navigation, utils, layout etc.&lt;/p&gt;

&lt;p&gt;You don't need to create these directories in advance and leave them empty. I would just create them as you go while building your components.&lt;/p&gt;

&lt;p&gt;This section is simply designed to explain how I will be setting up this project, there are many other ways you might choose to organize yours and I would encourage you to choose whatever works best for you and your team.&lt;/p&gt;

&lt;p&gt;At this point I will be making a commit with message &lt;code&gt;rfc: create directory structure&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Storybook
&lt;/h2&gt;

&lt;p&gt;One of the great modern tools available to us if you aren't already familiar with it is called &lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Storybook gives us an environment to show off and test the React components we are building outside of the application we are using them in. It's great tool to connect developers with designers and be able to verify components we have developed look and function as per design requirements in an isolated environment without the overhead of the rest of the app.&lt;/p&gt;

&lt;p&gt;Note that Storybook is meant as a visual testing tool, we will be implementing other tools later for functional unit testing and end-to-end testing.&lt;/p&gt;

&lt;p&gt;The best way to learn how to use Storybook is installing it and trying it out!&lt;/p&gt;

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

npx sb init --builder webpack5


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

&lt;/div&gt;

&lt;p&gt;We'll be using the webpack5 version to stay up to date with the latest version of webpack (I'm unsure why it is still not yet the default. Maybe it will be by the time you are using this tutorial).&lt;/p&gt;

&lt;p&gt;When Storybook installs it automatically detects a lot of things about your project, like how it is a React app, and other tools you are using. It should take care fo all that configuration itself.&lt;/p&gt;

&lt;p&gt;If you get a prompt about the eslintPlugin, you can say "yes". We are going to configure it manually though, so no worries if you get a message saying it didn't auto-configure.&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;.eslintrc.json&lt;/code&gt; and update it to the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.eslintrc.json&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;"extends"&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="s2"&gt;"plugin:storybook/recommended"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;New&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"next"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"next/core-web-vitals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"eslint:recommended"&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;"globals"&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;"React"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"readonly"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;New&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overrides"&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;"files"&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="s2"&gt;"*.stories.@(ts|tsx|js|jsx|mjs|cjs)"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rules"&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;example&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;overriding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;rule&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"storybook/hierarchy-separator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&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;span class="nl"&gt;"rules"&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;"no-unused-vars"&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="mi"&gt;1&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;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"after-used"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"argsIgnorePattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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="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 have added &lt;code&gt;// New&lt;/code&gt; to mark the two new sections and lines that are Storybook specific.&lt;/p&gt;

&lt;p&gt;You'll notice that Storybook has also added as &lt;code&gt;/stories&lt;/code&gt; directory to the root of your project with a number of examples in. If you are new to Storybook I highly recommend you look through them and leave them there until you are comfortable creating your own without the templates.&lt;/p&gt;

&lt;p&gt;Before we run it we need to make sure we are using webpack5. Add the following to your &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resolutions"&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;"webpack"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^5"&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;Then run&lt;/p&gt;

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

yarn install


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

&lt;/div&gt;

&lt;p&gt;To ensure webpack5 is installed.&lt;/p&gt;

&lt;p&gt;Next we have to update the &lt;code&gt;.storybook/main.js&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;storybook/main.js&lt;/code&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;stories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../**/*.stories.mdx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../**/*.stories.@(js|jsx|ts|tsx)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="cm"&gt;/** Expose public folder to storybook as static */&lt;/span&gt;
  &lt;span class="na"&gt;staticDirs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;addons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/addon-links&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/addon-essentials&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/addon-interactions&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;framework&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;core&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@storybook/builder-webpack5&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here we have changed the pattern for stories files so that it will pick up any &lt;code&gt;.stories&lt;/code&gt; files inside our components (or other) directories.&lt;/p&gt;

&lt;p&gt;We have also exposed Next.js's "public" folder as a static directory so we can test things like images, media, etc in Storybook.&lt;/p&gt;

&lt;p&gt;Lastly, before we run Storybook itself, let's add some helpful values in &lt;code&gt;storybook/preview.js&lt;/code&gt;. This is the file where we can control the defaults for how our stories render.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;storybook/preview.js&lt;/code&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../styles/globals.css&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;NextImage&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/image&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;BREAKPOINTS_INT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;md&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;lg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1536&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;customViewports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BREAKPOINTS_INT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;idx&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;width&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;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;height&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;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;vh`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Allow Storybook to handle Next's &amp;lt;Image&amp;gt; component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OriginalNextImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NextImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;NextImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&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;configurable&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="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;OriginalNextImage&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;unoptimized&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;argTypesRegex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;^on[A-Z].*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;controls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;matchers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;background|color&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;$/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&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;viewport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;viewports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customViewports&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;There are a few personal preferences in the above, but you can configure it how you want. Be sure to set the default breakpoints to match whatever is important to you in your app. We are also adding a handler so that Storybook can handle Next's &lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt; component without crashing.&lt;/p&gt;

&lt;p&gt;Now we are ready to test it. Run:&lt;/p&gt;

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

yarn storybook


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

&lt;/div&gt;

&lt;p&gt;If all goes well you'll see a message in your console that looks like:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649131564%2Fblogs%2Fnextjs-fullstack-app-template%2Fstorybook-started_ydsrdg.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649131564%2Fblogs%2Fnextjs-fullstack-app-template%2Fstorybook-started_ydsrdg.png" alt="Storybook Started"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you'll be able to access it on &lt;a href="http://localhost:6006" rel="noopener noreferrer"&gt;http://localhost:6006&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649131644%2Fblogs%2Fnextjs-fullstack-app-template%2Fstorybook-main_yktgqh.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649131644%2Fblogs%2Fnextjs-fullstack-app-template%2Fstorybook-main_yktgqh.png" alt="Storybook Main"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would encourage you to play around and get familiar with the examples if you've never used it before.&lt;/p&gt;

&lt;p&gt;At this stage I'll be making a commit with message &lt;code&gt;build: implement storybook&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Component Template
&lt;/h2&gt;

&lt;p&gt;It's time to bring together all the configuration we have done and look at how we might create and implement our first component using the standards we have set for ourselves.&lt;/p&gt;

&lt;p&gt;We'll just create a simple card. Create the following directory structure:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/components/templates/base&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And inside that directory we'll create &lt;code&gt;BaseTemplate.tsx&lt;/code&gt;. This will follow a standard pattern of filename matching the directories leading up to it. This allows us for example to have other types of cards in the &lt;code&gt;cards&lt;/code&gt; directory like &lt;code&gt;PhotoCard&lt;/code&gt; or &lt;code&gt;TextCard&lt;/code&gt; etc.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BaseTemplate.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IBaseTemplate&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;BaseTemplate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IBaseTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello world!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;BaseTemplate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Every single one of our components is going to follow this exact structure. Even if it does not use props it will still export an empty props interface for the component. The reason for this is it will allow us to replicate this exact structure across many components and files, and interchange components/imports using the same expected pattern and just find/replace the names of the components.&lt;/p&gt;

&lt;p&gt;When you begin working with the stories and mock props etc it will become quickly apparent how convenient and powerful it is to maintain a consistent naming scheme and interface for all your component files.&lt;/p&gt;

&lt;p&gt;This goes back to the &lt;strong&gt;consistency is everything&lt;/strong&gt; point we made earlier.&lt;/p&gt;

&lt;p&gt;Next I am going to make a style module file that lives next to the component. By default Next.js gives you a &lt;code&gt;/styles&lt;/code&gt; directory which I personally do not use, but if you prefer to keep all your styles in the same place that's a fine choice. I just prefer to keep them with the components.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BaseTemplate.module.css&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="nc"&gt;.component&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;As a standard empty template for where your top level styles will go on your component. You can update your &lt;code&gt;BaseTemplate&lt;/code&gt; as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BaseTemplate.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&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;./BaseTemplate.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IBaseTemplate&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;BaseTemplate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IBaseTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello world!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;BaseTemplate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now we have a clean template for our styling.&lt;/p&gt;

&lt;p&gt;Let's add an example prop to our template so we can handle the standard we'll be using for components props:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BaseTemplate.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&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;./BaseTemplate.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IBaseTemplate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;sampleTextProp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BaseTemplate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IBaseTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;sampleTextProp&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&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;sampleTextProp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;BaseTemplate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;With each component we create we're going to want a very quick and easy way to test it in different environments (Storybook for example, but also the app, and maybe our unit tests). It will be handy to have quick access to data to render the component.&lt;/p&gt;

&lt;p&gt;Let's create a file to store some mock data for this component to use for testing:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BaseTemplate.mocks.ts&lt;/code&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;IBaseTemplate&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;./BaseTemplate&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;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IBaseTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;sampleTextProp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world!&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockBaseTemplateProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;base&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;This structure may seem a bit convoluted, but we'll see the benefits soon. I am using very intentional consistent naming patterns so this template is very easy to copy and paste to each new component you create.&lt;/p&gt;

&lt;p&gt;Now let's create a create a story for this component:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BaseTemplate.stories.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;ComponentStory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ComponentMeta&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;@storybook/react&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;BaseTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IBaseTemplate&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;./BaseTemplate&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;mockBaseTemplateProps&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;./BaseTemplate.mocks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;templates/BaseTemplate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BaseTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// More on argTypes: https://storybook.js.org/docs/react/api/argtypes&lt;/span&gt;
  &lt;span class="na"&gt;argTypes&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;as&lt;/span&gt; &lt;span class="nx"&gt;ComponentMeta&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;BaseTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ComponentStory&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;BaseTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&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;BaseTemplate&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
&lt;span class="c1"&gt;// More on args: https://storybook.js.org/docs/react/writing-stories/args&lt;/span&gt;

&lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mockBaseTemplateProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;IBaseTemplate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;I'm not going to get into all the details of what each different part of a &lt;code&gt;stories&lt;/code&gt; file entails, for that your best resource is the official Storybook documentation.&lt;/p&gt;

&lt;p&gt;The goal here is to create a consistent easily copy/paste-able pattern of component building and testing.&lt;/p&gt;

&lt;p&gt;Let's try this one out. Run:&lt;/p&gt;

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

yarn storybook


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

&lt;/div&gt;

&lt;p&gt;If all goes well you will be greeted by your fine looking base component (if not I encourage you to revisit the previous section and check if you missed any of the configurations).&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649133832%2Fblogs%2Fnextjs-fullstack-app-template%2Fstorybook-base-template_uwna7h.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649133832%2Fblogs%2Fnextjs-fullstack-app-template%2Fstorybook-base-template_uwna7h.png" alt="Storybook Base Template"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we're starting to create more files it's good to get into the habit of running &lt;code&gt;yarn lint&lt;/code&gt; before doing your commits to make sure everything is clean and ready to go. I'm going to make a commit with message &lt;code&gt;build: create BaseTemplate component&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Component Template
&lt;/h2&gt;

&lt;p&gt;Since we have our template, let's go through the process of using it to create a real component.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;components/cards&lt;/code&gt; directory. Then copy the entirety of the &lt;code&gt;base&lt;/code&gt; directory from &lt;code&gt;templates&lt;/code&gt; into &lt;code&gt;cards&lt;/code&gt; and rename it &lt;code&gt;cat&lt;/code&gt;. We are going to make a &lt;code&gt;CatCard&lt;/code&gt;. Rename each of the files to match. When done it should look 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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649134894%2Fblogs%2Fnextjs-fullstack-app-template%2Fcomponent-directory-structure_ddw1ll.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649134894%2Fblogs%2Fnextjs-fullstack-app-template%2Fcomponent-directory-structure_ddw1ll.png" alt="Component Directory Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can press &lt;code&gt;ctrl + shift + F&lt;/code&gt; (or mac equivalent) in VS Code to do a full project search and replace. Include only &lt;code&gt;components/cards/cat&lt;/code&gt; and do a replace for &lt;code&gt;CatCard&lt;/code&gt; to replace &lt;code&gt;BaseTemplate&lt;/code&gt;. It should look like the following:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649134987%2Fblogs%2Fnextjs-fullstack-app-template%2Fvscode-find-replace_ithpow.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649134987%2Fblogs%2Fnextjs-fullstack-app-template%2Fvscode-find-replace_ithpow.png" alt="VS Code Find Replace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you're ready to work, you've got a clean pre-generated template to work from that includes a story and mock data for your card. Pretty handy! Let's make it look like a real card:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(For the record I did not create this beautiful card, it's based on an example created &lt;a href="https://codepen.io/lyon-etyo/pen/OJmyMGd" rel="noopener noreferrer"&gt;here&lt;/a&gt; by the talented Lyon Etyo)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CatCard.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&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;./CatCard.module.css&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;Image&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ICatCard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CatCard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ICatCard&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card__header&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;Image&lt;/span&gt;
            &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/time-cat.jpg"&lt;/span&gt;
            &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"card__image"&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card__image&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt;
            &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"400"&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card__body&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tag&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;styles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tag-blue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tag&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;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h4&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;title&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;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&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;body&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card__footer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&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;Image&lt;/span&gt;
              &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://i.pravatar.cc/40?img=3"&lt;/span&gt;
              &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"user__image"&lt;/span&gt;
              &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user__image&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"40"&lt;/span&gt;
              &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"40"&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user__info&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h5&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;author&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;h5&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;small&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;time&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;small&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;CatCard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Set the styles:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CatCard.module.css&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300..700&amp;amp;display=swap')&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;object-fit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Quicksand'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20rem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20rem&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="m"&gt;2vw&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;22rem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0.1rem&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ece9e6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;linear-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#ece9e6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.tag&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;align-self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex-start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.25em&lt;/span&gt; &lt;span class="m"&gt;0.75em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.tag-blue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#56ccf2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;linear-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nb"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#2f80ed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;#56ccf2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fafafa&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__body&lt;/span&gt; &lt;span class="nt"&gt;h4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;capitalize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card__footer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.user&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.user__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.user__info&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;small&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#666&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And set the mock data:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CatCard.mocks.ts&lt;/code&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;ICatCard&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;./CatCard&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;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ICatCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Felines&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`What's new in Cats`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lorem ipsum dolor sit amet consectetur adipisicing elit. Sequi perferendis molestiae non nemo doloribus. Doloremque, nihil! At ea atque quidem!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2h ago&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mockCatCardProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;base&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;Note that this uses an image of a cat &lt;code&gt;(/time-cat.jpg)&lt;/code&gt; from the project's public directory. You can find it in the project repository.&lt;/p&gt;

&lt;p&gt;The only thing we need to update in &lt;code&gt;CatCard.stories&lt;/code&gt; is to change the story title from &lt;code&gt;templates/CatCard&lt;/code&gt; to &lt;code&gt;cards/CatCard&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We do need to update our &lt;code&gt;next.config.js&lt;/code&gt; because we are using a domain we haven't explicitly stated as permitted (for the avatar). Simply update your config file to look like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;next.config.js&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="cm"&gt;/** @type {import('next').NextConfig} */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;reactStrictMode&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="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i.pravatar.cc&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Alternatively you could just place the avatar image in your own public directory, but for the sake of learning the process of using an external domain, we'll leave this setup in place.&lt;/p&gt;

&lt;p&gt;Now nun Storybook, and if you're lucky, you'll be greeted with:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649136596%2Fblogs%2Fnextjs-fullstack-app-template%2Fcat-card-storybook_f10yic.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649136596%2Fblogs%2Fnextjs-fullstack-app-template%2Fcat-card-storybook_f10yic.png" alt="Storybook Cat Card"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This component can then easily be dropped anywhere in your actual application. Use the &lt;code&gt;mock&lt;/code&gt; props in the short term while testing and replace with real props when you're ready!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&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;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/image&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;CatCard&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/cards/cat/CatCard&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;mockCatCardProps&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;../components/cards/cat/CatCard.mocks&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;styles&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;../styles/Home.module.css&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;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPage&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create Next App&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Generated by create next app"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Welcome to &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://nextjs.org"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Next.js!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grid&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;CatCard&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mockCatCardProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&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;CatCard&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mockCatCardProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&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;CatCard&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mockCatCardProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&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;CatCard&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mockCatCardProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;footer&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;footer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
          &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://vercel.com?utm_source=create-next-app&amp;amp;utm_medium=default-template&amp;amp;utm_campaign=create-next-app"&lt;/span&gt;
          &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;
          &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Powered by&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logo&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;Image&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/vercel.svg"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Vercel Logo"&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Let's take a look at the final masterpiece with:&lt;/p&gt;

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

yarn dev


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649137105%2Fblogs%2Fnextjs-fullstack-app-template%2Ffinal-masterpiece_cbpxu1.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649137105%2Fblogs%2Fnextjs-fullstack-app-template%2Ffinal-masterpiece_cbpxu1.png" alt="Final Masterpiece"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Custom Document
&lt;/h2&gt;

&lt;p&gt;Though it is not necessary at this stage you will likely want to have more fine grained control over what is in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of your app. Creating a custom &lt;code&gt;_document.tsx&lt;/code&gt; in your &lt;code&gt;pages&lt;/code&gt; directory allows you to do that. Create that file now.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/_document.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextScript&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/document&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyDocument&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Document&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;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"preconnect"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"preconnect"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.gstatic.com"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt;
            &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Quicksand:wght@300..700&amp;amp;display=swap"&lt;/span&gt;
            &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&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;Main&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;NextScript&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&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;Html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;MyDocument&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Note that I have removed the &lt;code&gt;@import&lt;/code&gt; URL font from &lt;code&gt;components/cards/cat/CatCard.module.css&lt;/code&gt; and placed that Google font here in the head to preload.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Anything else you need to do or customize in your &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element can now be done in this file.&lt;/p&gt;

&lt;p&gt;Be aware that this &lt;code&gt;&amp;lt;Head&amp;gt;&lt;/code&gt; is not the same as the one imported from &lt;code&gt;next/head&lt;/code&gt;. They will both work together and this one is used solely for data you would like loaded on every single page.&lt;/p&gt;

&lt;p&gt;For more info on how to use a custom &lt;code&gt;_document&lt;/code&gt; see the &lt;a href="https://nextjs.org/docs/advanced-features/custom-document" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Layouts
&lt;/h2&gt;

&lt;p&gt;Layouts are an important concept in Next.js. They help you manage state between pages. For this section we will be using the same basic template as provided in the &lt;a href="https://github.com/vercel/next.js/tree/canary/examples/layout-component" rel="noopener noreferrer"&gt;official example&lt;/a&gt; and simply customizing it to fit our project.&lt;/p&gt;

&lt;p&gt;Create a new directory called &lt;code&gt;layouts&lt;/code&gt; in &lt;code&gt;components&lt;/code&gt;. We will be copying our &lt;code&gt;templates/case&lt;/code&gt; directory again two times. One to call&lt;code&gt;primary&lt;/code&gt; and one called &lt;code&gt;sidebar&lt;/code&gt;. It should look as follows when complete:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649187194%2Fblogs%2Fnextjs-fullstack-app-template%2Flayout-folders_g3hzyt.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649187194%2Fblogs%2Fnextjs-fullstack-app-template%2Flayout-folders_g3hzyt.png" alt="Layout Folders"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do a case-sensitive find/replace for &lt;code&gt;BaseTemplate&lt;/code&gt; inside each of the files as well to replace with &lt;code&gt;PrimaryLayout&lt;/code&gt; and &lt;code&gt;SidebarLayout&lt;/code&gt; respectively.&lt;/p&gt;

&lt;p&gt;If you have any difficulty with this step, feel free to just &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;take the structure from the repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All credit to _leerob&lt;/em&gt; and &lt;em&gt;JJ Kasper&lt;/em&gt; from Vercel for the structure of these layout templates_&lt;/p&gt;

&lt;p&gt;Update the content of &lt;code&gt;PrimaryLayout.tsx&lt;/code&gt; and &lt;code&gt;PrimaryLayout.module.css&lt;/code&gt; to be:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/layouts/primary/PrimaryLayout.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&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;./PrimaryLayout.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IPrimaryLayout&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;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IPrimaryLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Primary Layout Example&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&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;children&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;main&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="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;components/layouts/primary/PrimaryLayout.module.css&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100vh&lt;/span&gt; &lt;span class="n"&gt;-&lt;/span&gt; &lt;span class="m"&gt;64px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&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;Then for sidebar:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;components/layouts/sidebar/SidebarLayout.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&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;./SidebarLayout.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISidebarLayout&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;SidebarLayout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ISidebarLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nav&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Search..."&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;About&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/contact"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Contact&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;SidebarLayout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;components/layouts/sidebar/SidebarLayout.module.css&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="nc"&gt;.nav&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;250px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fafafa&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.nav&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;uppercase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;letter-spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.025em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;0.125s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.nav&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-decoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#eaeaea&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;28px&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;Now that these templates have been created, we need to use them. We are going to update our Home page and create another page called &lt;code&gt;about.tsx&lt;/code&gt; to show how to use shared layouts and persist component state between pages.&lt;/p&gt;

&lt;p&gt;First we need to add a type which extends the default &lt;code&gt;NextPage&lt;/code&gt; interface as for some reason it does not include the &lt;code&gt;getLayout&lt;/code&gt; function out of the box. Create a custom type file that will handle that for us &lt;a href="https://stackoverflow.com/a/65898224" rel="noopener noreferrer"&gt;inspired by this solution&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/page.d.ts&lt;/code&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;NextPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&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;ComponentType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ReactNode&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NextPageWithLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;NextPage&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;getLayout&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;_page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactElement&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;ReactNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ComponentType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You can now use that &lt;code&gt;NextPageWithLayout&lt;/code&gt; interface in place of &lt;code&gt;NextPage&lt;/code&gt; when you need to create pages with custom layouts.&lt;/p&gt;

&lt;p&gt;Now let's update our home page:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CatCard&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/cards/cat/CatCard&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;mockCatCardProps&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;../components/cards/cat/CatCard.mocks&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;PrimaryLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/layouts/primary/PrimaryLayout&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;SidebarLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/layouts/sidebar/SidebarLayout&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;styles&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;../styles/Home.module.css&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;NextPageWithLayout&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;./page&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;Home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPageWithLayout&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Welcome to &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://nextjs.org"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Next.js!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&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;CatCard&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;mockCatCardProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PrimaryLayout&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;SidebarLayout&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;page&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;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;and also create a new &lt;code&gt;about&lt;/code&gt; page in the &lt;code&gt;pages&lt;/code&gt; directory:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/about.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PrimaryLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/layouts/primary/PrimaryLayout&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;SidebarLayout&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/layouts/sidebar/SidebarLayout&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;NextPageWithLayout&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;./page&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;About&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPageWithLayout&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Layout Example (About)&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        This example adds a property &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;getLayout&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; to your page,
        allowing you to return a React component for the layout. This allows you
        to define the layout on a per-page basis. Since we&lt;span class="ni"&gt;&amp;amp;apos;&lt;/span&gt;re returning a
        function, we can have complex nested layouts if desired.
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        When navigating between pages, we want to persist page state (input
        values, scroll position, etc.) for a Single-Page Application (SPA)
        experience.
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        This layout pattern will allow for state persistence because the React
        component tree is persisted between page transitions. To preserve state,
        we need to prevent the React component tree from being discarded between
        page transitions.
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Try It Out&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        To visualize this, try tying in the search input in the&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Sidebar&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; and then changing routes. You&lt;span class="ni"&gt;&amp;amp;apos;&lt;/span&gt;ll notice the
        input state is persisted.
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;About&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;About&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PrimaryLayout&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;SidebarLayout&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;page&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;PrimaryLayout&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then update &lt;code&gt;_app.tsx&lt;/code&gt; as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pages/_app.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/app&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./globals.css&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;NextPageWithLayout&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;./page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AppPropsWithLayout&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;AppProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextPageWithLayout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;AppPropsWithLayout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Use the layout defined at the page level, if available&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;||&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getLayout&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Finally, in the &lt;code&gt;mocks&lt;/code&gt; files I have updated &lt;code&gt;PrimaryLayout.mocks.ts&lt;/code&gt; to use &lt;code&gt;children: '{{component}}'&lt;/code&gt; as a placeholder value to show in Storybook where a component would go, and I have removed the mock props in &lt;code&gt;SidebarLayout.mocks.ts&lt;/code&gt; (though I do not remove the file, so I have the interface ready to go in case I ever need to add props).&lt;/p&gt;

&lt;p&gt;I have also changed the story titles from &lt;code&gt;templates/...&lt;/code&gt; to &lt;code&gt;layouts/...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally we can test it out. Save and run&lt;/p&gt;

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

yarn dev


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

&lt;/div&gt;

&lt;p&gt;Click between the two routes on the sidebar (Home and About) to toggle between pages. Note that the layouts used will persist without needing to reload (as was our intention) and you are left with a super fast and snappy experience.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649190823%2Fblogs%2Fnextjs-fullstack-app-template%2Fnext-layout-01_ijadox.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649190823%2Fblogs%2Fnextjs-fullstack-app-template%2Fnext-layout-01_ijadox.png" alt="Next Layout 01"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649190823%2Fblogs%2Fnextjs-fullstack-app-template%2Fnext-layout-02_v8hoti.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649190823%2Fblogs%2Fnextjs-fullstack-app-template%2Fnext-layout-02_v8hoti.png" alt="Next Layout 02"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the Storybook side, we can even view and test out layout components independent of the application. The &lt;code&gt;PrimaryLayout&lt;/code&gt; isn't too useful without content inside of it, but the sidebar is quite nice to have.&lt;/p&gt;

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

yarn storybook


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649191018%2Fblogs%2Fnextjs-fullstack-app-template%2Fstorybook-sidebar_actilj.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649191018%2Fblogs%2Fnextjs-fullstack-app-template%2Fstorybook-sidebar_actilj.png" alt="Storybook Sidebar"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Our final step will be to show the process of deployment of a Next.js app.&lt;/p&gt;

&lt;p&gt;We will be using Vercel as it is the simplest and most straightforward deployment solution for a Next.js app (primarily due to the fact that Vercel owns Next and so one can always assume they will offer best in class support).&lt;/p&gt;

&lt;p&gt;Be aware Vercel is absolutely not the only option, other major services like &lt;a href="https://aws.amazon.com/blogs/mobile/host-a-next-js-ssr-app-with-real-time-data-on-aws-amplify/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt;, &lt;a href="https://www.netlify.com/with/nextjs/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;, etc all work as well if you choose to go that route.&lt;/p&gt;

&lt;p&gt;Ultimately you just need a service where you can run the &lt;code&gt;next start&lt;/code&gt; command presuming you're not using an entirely &lt;a href="https://nextjs.org/docs/advanced-features/static-html-export" rel="noopener noreferrer"&gt;statically generated site&lt;/a&gt; (in which case any static hosting tool would work and no custom Next server would be required).&lt;/p&gt;

&lt;p&gt;Deploying on Vercel as a hobby user is completely free. To begin we will &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;create an account on Vercel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once logged in, click &lt;code&gt;+ New Project&lt;/code&gt; and give Vercel access to your Github repositories. You can give global access, or you can select only the repository you want to deploy. I am going to select this repository called &lt;code&gt;nextjs-fullstack-app-template&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once you have selected it you'll need to configure it. In the &lt;code&gt;Build and Output Settings&lt;/code&gt; section make sure you replace the default NPM commands with your yarn commands (unless you are using NPM).&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649164443%2Fblogs%2Fnextjs-fullstack-app-template%2Fnext-configure_dtywld.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649164443%2Fblogs%2Fnextjs-fullstack-app-template%2Fnext-configure_dtywld.png" alt="Next Configure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have not used any environment variables yet so no need to add any.&lt;/p&gt;

&lt;p&gt;Once that's it just click &lt;code&gt;Deploy&lt;/code&gt; and you're done! It's that easy.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649164722%2Fblogs%2Fnextjs-fullstack-app-template%2Fsuccessful-depoy_pyg2ry.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1649164722%2Fblogs%2Fnextjs-fullstack-app-template%2Fsuccessful-depoy_pyg2ry.png" alt="Successful Deploy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(The screenshot above is a bit out of date, I originally wrote the deployment section before the layout section, but you get the idea)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not only is your site deployed now, it will continue to get re-deployed automatically every time you commit to your primary branch. If you don't want this behavior, then it's easy to configure in the Vercel dashboard.&lt;/p&gt;

&lt;p&gt;The nice thing is that you already configured your &lt;code&gt;yarn build&lt;/code&gt; command to ensure a working production build before you can push you code, so you can push with confidence in presuming your deployment will be successful.&lt;/p&gt;

&lt;p&gt;The only thing you need to keep in mind are the differences between your two environments. It's still possible for your build to succeed locally but fail on Vercel if for example your scripts are different (using NPM instead of yarn or vice versa) or more commonly if you are missing environment variables.&lt;/p&gt;

&lt;p&gt;We will be adding &lt;code&gt;env&lt;/code&gt; values in future tutorials so you will need to make sure those values are configured in both your local and production environment, since they are secrets and should never be committed to a public (or even private if can be avoided) repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;I hope you found this tutorial and learned something about setting up a solid and scaleable Next.js project for you and your team.&lt;/p&gt;

&lt;p&gt;This is the first part of what is intended to be a multi-part series on creating a production quality Next.js app.&lt;/p&gt;

&lt;p&gt;Some of my ideas for future installments are below, I'd encourage you to leave some feedback about which ones you'd find most useful (or other ones if you don't see them below).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to build a fullstack Next.js app using API routes and Tailwind CSS&lt;/li&gt;
&lt;li&gt;How to add a global state manager to your Next.js app with Recoil&lt;/li&gt;
&lt;li&gt;How to implement unit and end-to-end testing in a Next.s app with jest and playwright&lt;/li&gt;
&lt;li&gt;How to create a CI/CD pipeline with Github actions and Vercel&lt;/li&gt;
&lt;li&gt;How to implement SSO authentication and internationalization in a Next.js app using NextAuth and i18next&lt;/li&gt;
&lt;li&gt;How to connect a database to your Next.js app with Prisma and Supabase&lt;/li&gt;
&lt;li&gt;How to manage multiple applications in a monorepo with Next.js and Nx&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned and please don't hesitate to ask any questions, I'm happy to answer if I can!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Remember that all code from this tutorial as a complete package is available in &lt;a href="https://github.com/alexeagleson/nextjs-fullstack-app-template" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please check some of my other learning tutorials. Feel free to leave a comment or question and share with others if you find any of them helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-connect-a-react-app-to-a-notion-database-51mc"&gt;How to Connect a React App to a Notion Database&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-nodejs-to-backup-your-personal-files-and-learn-some-webdev-skills-along-the-way-541a"&gt;How to use Node.js to backup your personal files&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/docker-for-javascript-developers-41me"&gt;Introduction to Docker for Javascript Developers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg"&gt;Learnings from React Conf 2021&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg"&gt;How to Create a Dark Mode Component in React&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34"&gt;How to Analyze and Improve your 'Create React App' Production Build &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe"&gt;How to Create and Publish a React Component Library&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-indexeddb-to-store-data-for-your-web-application-in-the-browser-1o90"&gt;How to use IndexedDB to Store Local Data for your Web App &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g"&gt;Running a Local Web Server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-linters-eslint-59pm"&gt;ESLint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-prettier-214j"&gt;Prettier&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp"&gt;Babel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7"&gt;React &amp;amp; JSX&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-1-2mn1"&gt;Webpack: The Basics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>How to Connect a React App to a Notion Database</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Sun, 09 Jan 2022 02:23:44 +0000</pubDate>
      <link>https://dev.to/alexeagleson/how-to-connect-a-react-app-to-a-notion-database-51mc</link>
      <guid>https://dev.to/alexeagleson/how-to-connect-a-react-app-to-a-notion-database-51mc</guid>
      <description>&lt;p&gt;All code from this tutorial as a complete package is available in &lt;a href="https://github.com/alexeagleson/react-node-notion" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;If you find this tutorial helpful, please share it with your friends and colleagues!  For more like it you can subscribe on &lt;a href="https://www.youtube.com/channel/UCV5YqK3AaInd3lYFQqlp7Lw" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/eagleson_alex" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This tutorial is available as a video lesson if you prefer that format:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OXmCm-DChp8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What is Notion?&lt;/li&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Project Setup&lt;/li&gt;
&lt;li&gt;Creating a Notion Database&lt;/li&gt;
&lt;li&gt;Creating the Server&lt;/li&gt;
&lt;li&gt;Querying the Server&lt;/li&gt;
&lt;li&gt;Creating a Notion Integration&lt;/li&gt;
&lt;li&gt;Querying the Database&lt;/li&gt;
&lt;li&gt;Connecting the App&lt;/li&gt;
&lt;li&gt;Wrapping Up&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Before we jump in I want to explain quickly a little bit what &lt;a href="https://www.notion.so/product" rel="noopener noreferrer"&gt;Notion&lt;/a&gt; is.&lt;/p&gt;

&lt;p&gt;It's basically an organizational tool that runs in the cloud and supports multiple user collaboration at the same time.  &lt;/p&gt;

&lt;p&gt;It can be used for anything from organizing daily tasks, keeping track of school schedules, to managing the documentation of large enterprise projects.  &lt;/p&gt;

&lt;p&gt;Basically if you want to "organize" any kind of information, Notion is a great tool for that.  &lt;/p&gt;

&lt;p&gt;Similar products you might be familiar with would be something like Confluence, Evernote or OneNote.  &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/oTahLEX3NXo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Recently I discovered that Notion provides an API to read and modify data on your Notion workspace.  &lt;/p&gt;

&lt;p&gt;They also have fantastic support for simple databases (even relational ones) so I thought it would be fun to try a little app that could use Notion as a quick and dirty CMS, and I had a lot of fun doing it, so I thought I would write up a little tutorial to share the process with others.  &lt;/p&gt;

&lt;p&gt;I want to be clear that &lt;em&gt;&lt;strong&gt;I am absolutely not advocating for the use of Notion as a real database for a production application&lt;/strong&gt;&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;I do not know anything about the actual speed and performance of querying it at any scale, and I also wouldn't trust any critical data on a service that isn't specifically designed to offer a reliability guarantee.&lt;/p&gt;

&lt;p&gt;However, for fun little projects I think it's a great option, especially for front end developers who don't have a lot of existing knowledge about databases and just want to get their feet wet.&lt;/p&gt;

&lt;p&gt;It can also be a great way to collaborate with less technical folks and allow them the flexibility that Notion offers for creating content, and giving developers the ability to directly reference that content in code.&lt;/p&gt;

&lt;p&gt;So without further delay, let's play around with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;The structure of our project will be:&lt;/p&gt;

&lt;p&gt;React App -&amp;gt; Node server -&amp;gt; Notion database&lt;/p&gt;

&lt;p&gt;The reason we need the Node server is because if we were to query directly from our React app,  we would have to expose our Notion account credentials and secret/database ID.  Anything on the client side is always visible to the user.&lt;/p&gt;

&lt;p&gt;By querying on the server we can keep the credentials there, out of reach of the front end, and only provide the database table data itself to the front end. &lt;/p&gt;

&lt;p&gt;We'll begin by creating the project directory and React app.  We're using &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt; here as it's still the simplest way to get an instant React project up and running with minimal complexity:&lt;/p&gt;

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

mkdir react-node-notion
cd react-node-notion
npx create-react-app@latest sample-app --template typescript
cd sample-app
npm run start


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

&lt;/div&gt;

&lt;p&gt;Make sure you are able to see the example React app on &lt;a href=""&gt;http://localhost:3000/&lt;/a&gt; before you continue.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Notion Database
&lt;/h2&gt;

&lt;p&gt;Next we are going to create our Notion workspace and database.  &lt;/p&gt;

&lt;p&gt;Navigate to:&lt;/p&gt;

&lt;p&gt;&lt;a href=""&gt;https://www.notion.so/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can create an account or login with an existing Google or Apple account.  Notion is free to use for an individual.  &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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_10%2Cbo_3px_solid_darkgrey%2Fv1641346161%2Fblogs%2Fnotion-cms%2Fnew-page_nwh5hq.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_10%2Cbo_3px_solid_darkgrey%2Fv1641346161%2Fblogs%2Fnotion-cms%2Fnew-page_nwh5hq.png" alt="Create New Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we'll create a page where our database will live.  My database is going to help me keep track of stuff I want to learn in 2022.  &lt;/p&gt;

&lt;p&gt;Click anywhere on the "My Cool Project" page and type &lt;code&gt;/page&lt;/code&gt;.  You'll have te option of creating a new page.  Create one and give it an icon.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_10%2Cbo_3px_solid_darkgrey%2Fv1641687406%2Fblogs%2Fnotion-cms%2Fcreate-page_uuctgq.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_10%2Cbo_3px_solid_darkgrey%2Fv1641687406%2Fblogs%2Fnotion-cms%2Fcreate-page_uuctgq.png" alt="New Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open your new page.  You can give it a cover image at the top.  CLick anywhere on the blank page and type &lt;code&gt;/database&lt;/code&gt;.  You're going to select &lt;strong&gt;&lt;em&gt;"Table Database - Inline"&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first column should be a unique value (our primary key).  I'm simply going to name that column &lt;code&gt;key&lt;/code&gt;.  The second column I will name &lt;code&gt;label&lt;/code&gt; and the third column I will name &lt;code&gt;url&lt;/code&gt;.  The key column will be of type &lt;code&gt;title&lt;/code&gt; by default, but you will need to set the label column to &lt;code&gt;text&lt;/code&gt; and the url column to &lt;code&gt;url&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;I've made the column headers lowercase on purpose since we will be referring to them with Javascript properties when we query (which are traditionally lowercase).  &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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_10%2Cbo_3px_solid_darkgrey%2Fv1641687724%2Fblogs%2Fnotion-cms%2Fcreate-database_rrrnco.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_10%2Cbo_3px_solid_darkgrey%2Fv1641687724%2Fblogs%2Fnotion-cms%2Fcreate-database_rrrnco.png" alt="Create Database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will be using this database to keep track of the things I want to learn, and a URL link to the resource to learn them.  This is super simple but you can come up with anything as complex as you want, we're mostly just here to give an example of how to query this data and display it in an app (or anywhere you like really).&lt;/p&gt;

&lt;p&gt;Populate the DB with whatever data suits you best.  Here's mine:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_10%2Cbo_3px_solid_darkgrey%2Fv1641688013%2Fblogs%2Fnotion-cms%2Ffinal-database_qs1zxb.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_10%2Cbo_3px_solid_darkgrey%2Fv1641688013%2Fblogs%2Fnotion-cms%2Ffinal-database_qs1zxb.png" alt="Final Database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Server
&lt;/h2&gt;

&lt;p&gt;We're next going to spin up a super simple Node server to serve the data.  All we need is the &lt;code&gt;http&lt;/code&gt; module and the Notion client library from NPM.  &lt;/p&gt;

&lt;p&gt;Let's begin with just the server and confirm we can query the data before we add the Notion integration:&lt;/p&gt;

&lt;p&gt;Go back to the root directory &lt;code&gt;react-node-notion&lt;/code&gt; before running these commands:&lt;/p&gt;

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

mkdir server
cd server
npm init -y
npm install -D typescript @types/node
npx tsc --init
mkdir src
touch src/server.ts


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

&lt;/div&gt;

&lt;p&gt;In case you aren't creating your files from the command line, the above instructions will install the necessary packages and create a &lt;code&gt;server&lt;/code&gt; directory and an &lt;code&gt;src&lt;/code&gt; directory inside with a &lt;code&gt;server.ts&lt;/code&gt; file.  Your full directory structure for the entire project should look like:&lt;/p&gt;

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

.
├── sample-app
│   └── (React app files)
└── server
    ├── src
    │   └── server.ts
    ├── tsconfig.json
    ├── package-lock.json
    └── package.json


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

&lt;/div&gt;

&lt;p&gt;Your &lt;code&gt;server.ts&lt;/code&gt; file will look like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;server/src/server.ts&lt;/code&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="nx"&gt;http&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;http&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;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;localhost&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8000&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;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&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="c1"&gt;// Avoid CORS errors&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;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Origin&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&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="k"&gt;switch &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="c1"&gt;// Will respond to queries to the domain root (like http://localhost/)&lt;/span&gt;
    &lt;span class="k"&gt;case&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Only supports the / route&lt;/span&gt;
    &lt;span class="nl"&gt;default&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;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&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;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Resource not found&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;server&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;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server is running on http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;host&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;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Your &lt;code&gt;npx tsc --init&lt;/code&gt; command will have created a &lt;code&gt;tsconfig.json&lt;/code&gt; file.  All the defaults are fine, you just need to add one value:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./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;That will output the result of the &lt;code&gt;tsc&lt;/code&gt; command into a &lt;code&gt;dist&lt;/code&gt; folder with a JS file that you can run.&lt;/p&gt;

&lt;p&gt;Give it a try by running:&lt;/p&gt;

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

npx tsc &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; node dist/server.js&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;

That says &lt;span class="s2"&gt;"run typescript and then use Node to run the resulting Javascript file it creates in the output folder"&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;  

&lt;span class="c"&gt;## Querying the Server&lt;/span&gt;

Navigate back to the &lt;span class="sb"&gt;`&lt;/span&gt;sample-app&lt;span class="sb"&gt;`&lt;/span&gt; directory and open the &lt;span class="sb"&gt;`&lt;/span&gt;src&lt;span class="sb"&gt;`&lt;/span&gt; directory.  We can delete &lt;span class="sb"&gt;`&lt;/span&gt;App.css&lt;span class="sb"&gt;`&lt;/span&gt; and the &lt;span class="sb"&gt;`&lt;/span&gt;logo.svg&lt;span class="sb"&gt;`&lt;/span&gt; file.  

We&lt;span class="s1"&gt;'ll update the `index.css` with some super simple CSS based off [this minimalist style](https://www.swyx.io/css-100-bytes/).

`sample-app/src/index.css`
```css
html {
  max-width: 70ch;
  padding: 3em 1em;
  margin: auto;
  line-height: 1.75;
  font-size: 1.25em;
}

h1,h2,h3,h4,h5,h6 {
  margin: 3em 0 1em;
}

p,ul,ol {
  margin-bottom: 2em;
  color: #1d1d1d;
  font-family: sans-serif;
}
```

Now we update the contents of `App.tsx`.  Remove all the default content inside the file (including the imports) and replace it with the following:

`sample-app/src/App.tsx`
```tsx
function App() {

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Things to Learn&amp;lt;/h1&amp;gt;

      &amp;lt;button
        type="button"
        onClick={() =&amp;gt; {
          fetch("http://localhost:8000/")
            .then((response) =&amp;gt; response.json())
            .then((payload) =&amp;gt; {
              console.log(payload)
            });
        }}
      &amp;gt;
        Fetch List
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
```

We use the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to query the simple server we just wrote that we made listen on port 8000 and respond on the root domain route `/`.

So that means to reach that endpoint we need to query `http://localhost:8000/`.  Save and run your app, then press the "Fetch List" button.  Open the dev console with F12 and you will see:


![Fetch Success](https://res.cloudinary.com/dqse2txyi/image/upload/r_10,bo_3px_solid_darkgrey/v1641689103/blogs/notion-cms/fetch-success_sujvb8.png)

Notice the `{ data: "success" }` response there in the console.  Great!  

Our React app is connected to our server and we can query basic data.  Let'&lt;/span&gt;s get Notion hooked up.

&lt;span class="c"&gt;## Creating a Notion Integration&lt;/span&gt;

Before you can query data from your Notion account you need to create an _integration_ that has the necessary permissions.  You can configure integrations to have different permissions like &lt;span class="nb"&gt;read&lt;/span&gt;/write/insert depending on &lt;span class="nb"&gt;who &lt;/span&gt;you are sharing the integration secret with.

Go to the following URL:

&lt;span class="o"&gt;[&lt;/span&gt;https://www.notion.so/my-integrations]&lt;span class="o"&gt;()&lt;/span&gt;

And click the big &lt;span class="k"&gt;**&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;+ New Integration]&lt;span class="k"&gt;**&lt;/span&gt; button on the left.  

You can configure and name your integration how you like.  For mine I only want to be able to &lt;span class="nb"&gt;read &lt;/span&gt;content from my database, so I am only giving it &lt;span class="nb"&gt;read &lt;/span&gt;permissions and no access to user data:

&lt;span class="o"&gt;![&lt;/span&gt;Integration Setup]&lt;span class="o"&gt;(&lt;/span&gt;https://res.cloudinary.com/dqse2txyi/image/upload/r_10,bo_3px_solid_darkgrey/v1641689746/blogs/notion-cms/integration-setup_piu1pt.png&lt;span class="o"&gt;)&lt;/span&gt;

After you have created the integration you will be provided with a &lt;span class="s2"&gt;"secret"&lt;/span&gt; that gives access to your integration.  Keep this handy as we will need it soon:

&lt;span class="o"&gt;![&lt;/span&gt;Notion Secret]&lt;span class="o"&gt;(&lt;/span&gt;https://res.cloudinary.com/dqse2txyi/image/upload/r_10,bo_3px_solid_darkgrey/v1641689915/blogs/notion-cms/notion-secret_r0nytu.png&lt;span class="o"&gt;)&lt;/span&gt;

In addition to the secret, we also need to configure the database itself to be allowed to be read.  Go back to your &lt;span class="s2"&gt;"Things to Learn"&lt;/span&gt; database &lt;span class="o"&gt;(&lt;/span&gt;or whatever you wrote&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

At the upper right corner of your database page is a &lt;span class="s2"&gt;"Share"&lt;/span&gt; button.  Click it and &lt;span class="k"&gt;then &lt;/span&gt;click the &lt;span class="s2"&gt;"Invite"&lt;/span&gt; button.  You will have the ability to invite your new integration that you created to have access to this database.  It will still be private and hidden from the general public.

&lt;span class="o"&gt;![&lt;/span&gt;Share Database]&lt;span class="o"&gt;(&lt;/span&gt;https://res.cloudinary.com/dqse2txyi/image/upload/r_10,bo_3px_solid_darkgrey/v1641690016/blogs/notion-cms/share-database_d9smky.png&lt;span class="o"&gt;)&lt;/span&gt;

The two values you need to query this database from your Node app are the Notion secret &lt;span class="o"&gt;(&lt;/span&gt;which you already have&lt;span class="o"&gt;)&lt;/span&gt; and the database ID.  The database ID you can get from the URL when you are looking at your database.  The URL will look something like this:

&lt;span class="sb"&gt;```&lt;/span&gt;
https://www.notion.so/aaaaaaaaaaaaaaaaaaaaaaaaaa?v&lt;span class="o"&gt;=&lt;/span&gt;bbbbbbbbbbbbbbbbbbbbbbbbbbb
&lt;span class="sb"&gt;```&lt;/span&gt;

In the above example your &lt;span class="sb"&gt;`&lt;/span&gt;database &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; is the &lt;span class="sb"&gt;`&lt;/span&gt;aaaaaaaaaaaaaaaaaaaaaa&lt;span class="sb"&gt;`&lt;/span&gt; part before the question mark.

You now have everything you need to query the data.  Back to the Node server.

&lt;span class="c"&gt;## Querying the Database&lt;/span&gt;

We are going to need a secure place to store our Notion secret and database ID.  If we put them &lt;span class="k"&gt;in &lt;/span&gt;our code they will become visible to anyone &lt;span class="nb"&gt;who &lt;/span&gt;checks the &lt;span class="nb"&gt;source &lt;/span&gt;when we push to a remote repository.  To get around this we will store our credentials &lt;span class="k"&gt;in &lt;/span&gt;a &lt;span class="sb"&gt;`&lt;/span&gt;.env.&lt;span class="sb"&gt;`&lt;/span&gt; file.

Inside your &lt;span class="sb"&gt;`&lt;/span&gt;server&lt;span class="sb"&gt;`&lt;/span&gt; directory create two new files &lt;span class="o"&gt;(&lt;/span&gt;note that both of them are hidden files that are prefix with a &lt;span class="sb"&gt;`&lt;/span&gt;.&lt;span class="sb"&gt;`&lt;/span&gt; before the filename&lt;span class="o"&gt;)&lt;/span&gt;:

&lt;span class="sb"&gt;`&lt;/span&gt;server/.env&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;
&lt;span class="nv"&gt;NOTION_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"secret_xxxxxxxxxxxxxxxxxxxxxx"&lt;/span&gt;
&lt;span class="nv"&gt;NOTION_DATABASE_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;

Where the dummy values above are replaced by the values you took from Notion.  Remember your secret key does need the &lt;span class="sb"&gt;`&lt;/span&gt;secret_&lt;span class="sb"&gt;`&lt;/span&gt; prefix &lt;span class="k"&gt;in &lt;/span&gt;front of it.

We also want to create a &lt;span class="sb"&gt;`&lt;/span&gt;.gitignore&lt;span class="sb"&gt;`&lt;/span&gt; file:

&lt;span class="sb"&gt;`&lt;/span&gt;server/.gitignore&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;
.env
dist
node_modules
&lt;span class="sb"&gt;```&lt;/span&gt;

This will tell &lt;span class="sb"&gt;`&lt;/span&gt;git&lt;span class="sb"&gt;`&lt;/span&gt; not to push your secret &lt;span class="sb"&gt;`&lt;/span&gt;.env&lt;span class="sb"&gt;`&lt;/span&gt; file our your automatically generated &lt;span class="sb"&gt;`&lt;/span&gt;dist&lt;span class="sb"&gt;`&lt;/span&gt; folder when you commit.  

While we&lt;span class="s1"&gt;'re at it let'&lt;/span&gt;s add a start script &lt;span class="k"&gt;for &lt;/span&gt;our server that does the &lt;span class="sb"&gt;`&lt;/span&gt;tsc&lt;span class="sb"&gt;`&lt;/span&gt; build and runs the JS output:

&lt;span class="sb"&gt;`&lt;/span&gt;server/package.json&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;json
&lt;span class="o"&gt;{&lt;/span&gt;
  ...
  &lt;span class="s2"&gt;"scripts"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"start"&lt;/span&gt;: &lt;span class="s2"&gt;"tsc &amp;amp;&amp;amp; node dist/server.js"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;

Alright!  Now that that is taken care of we just need two packages.  One is the official Notion client &lt;span class="k"&gt;for &lt;/span&gt;Node, and the other is &lt;span class="sb"&gt;`&lt;/span&gt;dotenv&lt;span class="sb"&gt;`&lt;/span&gt; library that will made it super simple to &lt;span class="nb"&gt;read &lt;/span&gt;your secret and database &lt;span class="nb"&gt;id &lt;/span&gt;values from that &lt;span class="sb"&gt;`&lt;/span&gt;.env&lt;span class="sb"&gt;`&lt;/span&gt; file:

&lt;span class="sb"&gt;```&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @notionhq/client@0.4.9 dotenv
&lt;span class="sb"&gt;```&lt;/span&gt;

Note that I have locked Notion client to &lt;span class="sb"&gt;`&lt;/span&gt;0.4.9&lt;span class="sb"&gt;`&lt;/span&gt; as the API may change since this is a relatively new product and I would like this tutorial to work &lt;span class="k"&gt;for &lt;/span&gt;anyone &lt;span class="nb"&gt;who &lt;/span&gt;uses it &lt;span class="k"&gt;in &lt;/span&gt;the future.  You can try running the latest build however you may need to refer to their documentation and make corrections &lt;span class="k"&gt;if &lt;/span&gt;anything has changed.

Now we&lt;span class="s1"&gt;'re going to update our `server.ts` file.  We'&lt;/span&gt;ll &lt;span class="k"&gt;do &lt;/span&gt;it all at once but I&lt;span class="s1"&gt;'ll add lots of comments to explain everything:

`server/src/server.ts`
```ts
require("dotenv").config();
import http from "http";
import { Client } from "@notionhq/client";

// This is Typescript  interface for the shape of the object we will
// create based on our database to send to the React app
// When the data is queried it will come back in a much more complicated shape, so our goal is to
// simplify it to make it easy to work with on the front end
interface ThingToLearn {
  label: string;
  url: string;
}

// The dotenv library will read from your .env file into these values on `process.env`
const notionDatabaseId = process.env.NOTION_DATABASE_ID;
const notionSecret = process.env.NOTION_SECRET;

// Will provide an error to users who forget to create the .env file
// with their Notion data in it
if (!notionDatabaseId || !notionSecret) {
  throw Error("Must define NOTION_SECRET and NOTION_DATABASE_ID in env");
}

// Initializing the Notion client with your secret
const notion = new Client({
  auth: notionSecret,
});

const host = "localhost";
const port = 8000;

// Require an async function here to support await with the DB query
const server = http.createServer(async (req, res) =&amp;gt; {
  res.setHeader("Access-Control-Allow-Origin", "*");

  switch (req.url) {
    case "/":
      // Query the database and wait for the result
      const query = await notion.databases.query({
        database_id: notionDatabaseId,
      });

      // We map over the complex shape of the results and return a nice clean array of
      // objects in the shape of our `ThingToLearn` interface
      const list: ThingToLearn[] = query.results.map((row) =&amp;gt; {
        // row represents a row in our database and the name of the column is the
        // way to reference the data in that column
        const labelCell = row.properties.label;
        const urlCell = row.properties.url;

        // Depending on the column "type" we selected in Notion there will be different
        // data available to us (URL vs Date vs text for example) so in order for Typescript
        // to safely infer we have to check the `type` value.  We had one text and one url column.
        const isLabel = labelCell.type === "rich_text";
        const isUrl = urlCell.type === "url";

        // Verify the types are correct
        if (isLabel &amp;amp;&amp;amp; isUrl) {
          // Pull the string values of the cells off the column data
          const label = labelCell.rich_text?.[0].plain_text;
          const url = urlCell.url ?? "";

          // Return it in our `ThingToLearn` shape
          return { label, url };
        }

        // If a row is found that does not match the rules we checked it will still return in the
        // the expected shape but with a NOT_FOUND label
        return { label: "NOT_FOUND", url: "" };
      });

      res.setHeader("Content-Type", "application/json");
      res.writeHead(200);
      res.end(JSON.stringify(list));
      break;

    default:
      res.setHeader("Content-Type", "application/json");
      res.writeHead(404);
      res.end(JSON.stringify({ error: "Resource not found" }));
  }
});

server.listen(port, host, () =&amp;gt; {
  console.log(`Server is running on http://${host}:${port}`);
});
```

Should be good!  We'&lt;/span&gt;ll start the server with the new script we made &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;package.json&lt;span class="sb"&gt;`&lt;/span&gt;:

&lt;span class="sb"&gt;```&lt;/span&gt;
npm run start
&lt;span class="sb"&gt;```&lt;/span&gt;

&lt;span class="c"&gt;## Connecting the App&lt;/span&gt;

A quick jump back into the React app and hit that &lt;span class="s2"&gt;"Fetch Data"&lt;/span&gt; button again.  If everything went well you will be greeted with the content of your database &lt;span class="k"&gt;in &lt;/span&gt;your browser console:

&lt;span class="o"&gt;![&lt;/span&gt;React Notion Query]&lt;span class="o"&gt;(&lt;/span&gt;https://res.cloudinary.com/dqse2txyi/image/upload/r_10,bo_3px_solid_darkgrey/v1641691474/blogs/notion-cms/notion-react-query_kdwswh.png&lt;span class="o"&gt;)&lt;/span&gt;

You&lt;span class="s1"&gt;'ve now got the data in your React app, you can do whatever you want with it!  We could probably wrap up the tutorial here, but let'&lt;/span&gt;s make one final step of turning the data into an actual list of links:

&lt;span class="sb"&gt;`&lt;/span&gt;sample-app/src/App.tsx&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;tsx
import &lt;span class="o"&gt;{&lt;/span&gt; useState &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s2"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

// Copy the payload shape interface from our server
// We want to copy &lt;span class="o"&gt;(&lt;/span&gt;rather than import&lt;span class="o"&gt;)&lt;/span&gt; since we we won&lt;span class="s1"&gt;'t necessarily deploy our
// front end and back end to the same place
interface ThingToLearn {
  label: string;
  url: string;
}

function App() {
  // A state value will store the current state of the array of data which can be updated
  // by editing your database in Notion and then pressing the fetch button again
  const [thingsToLearn, setThingsToLearn] = useState&amp;lt;ThingToLearn[]&amp;gt;([]);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Things to Learn&amp;lt;/h1&amp;gt;
      &amp;lt;button
        type="button"
        onClick={() =&amp;gt; {
          fetch("http://localhost:8000/")
            .then((response) =&amp;gt; response.json())
            .then((payload) =&amp;gt; {
              // Set the React state with the array response
              setThingsToLearn(payload);
            });
        }}
      &amp;gt;
        Fetch List
      &amp;lt;/button&amp;gt;

      {/* Map the resulting object array into an ordered HTML list with anchor links */}
      {/* Using index as key is harmless since we will only ever be replacing the full list */}
      &amp;lt;ol&amp;gt;
        {thingsToLearn.map((thing, idx) =&amp;gt; {
          return (
            &amp;lt;li key={idx}&amp;gt;
              &amp;lt;a href={thing.url} target="_blank" rel="noopener noreferrer"&amp;gt;
                {thing.label}
              &amp;lt;/a&amp;gt;
            &amp;lt;/li&amp;gt;
          );
        })}
      &amp;lt;/ol&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
```

And with that, a click of the fetch button and we get a nice list of things to do which reflects the state of our Notion database and creates links to the relevant pages.  

![Final Result](https://res.cloudinary.com/dqse2txyi/image/upload/r_10,bo_3px_solid_darkgrey/v1641691929/blogs/notion-cms/final-result_irlemi.png)

Go ahead, try changing some text in your DB and hitting the button again.

## Wrapping Up

Well that'&lt;/span&gt;s pretty neat!  Now that you know how to &lt;span class="k"&gt;do &lt;/span&gt;this, what cool projects can you think to build?

Remember that all code from this tutorial as a &lt;span class="nb"&gt;complete &lt;/span&gt;package is available &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;this repository]&lt;span class="o"&gt;(&lt;/span&gt;https://github.com/alexeagleson/react-node-notion&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;  

Please check some of my other learning tutorials.  Feel free to leave a comment or question and share with others &lt;span class="k"&gt;if &lt;/span&gt;you find any of them helpful:

- &lt;span class="o"&gt;[&lt;/span&gt;How to use Node.js to backup your personal files]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/how-to-use-nodejs-to-backup-your-personal-files-and-learn-some-webdev-skills-along-the-way-541a&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;Introduction to Docker &lt;span class="k"&gt;for &lt;/span&gt;Javascript Developers]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/docker-for-javascript-developers-41me&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;Learnings from React Conf 2021]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;How to Create a Dark Mode Component &lt;span class="k"&gt;in &lt;/span&gt;React]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;How to Analyze and Improve your &lt;span class="s1"&gt;'Create React App'&lt;/span&gt; Production Build &lt;span class="o"&gt;](&lt;/span&gt;https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;How to Create and Publish a React Component Library]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;How to use IndexedDB to Store Local Data &lt;span class="k"&gt;for &lt;/span&gt;your Web App &lt;span class="o"&gt;](&lt;/span&gt;https://dev.to/alexeagleson/how-to-use-indexeddb-to-store-data-for-your-web-application-in-the-browser-1o90&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;Running a Local Web Server]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;ESLint]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/understanding-the-modern-web-stack-linters-eslint-59pm&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;Prettier]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/understanding-the-modern-web-stack-prettier-214j&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;Babel]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;React &amp;amp; JSX]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;Webpack: The Basics]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-1-2mn1&lt;span class="o"&gt;)&lt;/span&gt;

- &lt;span class="o"&gt;[&lt;/span&gt;Webpack: Loaders, Optimizations &amp;amp; Bundle Analysis]&lt;span class="o"&gt;(&lt;/span&gt;https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-2-49bj&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nt"&gt;---&lt;/span&gt;

If you find this tutorial helpful, please share it with your friends and colleagues!  For more like it you can subscribe on &lt;span class="o"&gt;[&lt;/span&gt;Youtube]&lt;span class="o"&gt;(&lt;/span&gt;https://www.youtube.com/channel/UCV5YqK3AaInd3lYFQqlp7Lw&lt;span class="o"&gt;)&lt;/span&gt; or follow me on &lt;span class="o"&gt;[&lt;/span&gt;Twitter]&lt;span class="o"&gt;(&lt;/span&gt;https://twitter.com/eagleson_alex&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>node</category>
    </item>
    <item>
      <title>How to use Node.js to backup your personal files (and learn some webdev skills along the way)</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Wed, 29 Dec 2021 04:44:16 +0000</pubDate>
      <link>https://dev.to/alexeagleson/how-to-use-nodejs-to-backup-your-personal-files-and-learn-some-webdev-skills-along-the-way-541a</link>
      <guid>https://dev.to/alexeagleson/how-to-use-nodejs-to-backup-your-personal-files-and-learn-some-webdev-skills-along-the-way-541a</guid>
      <description>&lt;p&gt;All code from this tutorial as a complete package is available in &lt;a href="https://github.com/alexeagleson/template-node-backup-directory" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.  If you find this tutorial helpful, please share it with your friends and colleagues!&lt;/p&gt;

&lt;p&gt;For more tutorials like this, follow me &lt;a href="https://twitter.com/eagleson_alex?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@eagleson_alex&lt;/a&gt; on Twitter&lt;/p&gt;

&lt;p&gt;This tutorial is also available as a video:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/eT2oyCDiv0o"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Like many other people out there, I have quite a few digital documents and pictures that are important to me. &lt;/p&gt;

&lt;p&gt;Although I know I have at least one copy of these locally, and I do use Dropbox as cloud storage; I'll freely admit I don't meet the coveted &lt;a href="https://www.backblaze.com/blog/the-3-2-1-backup-strategy/" rel="noopener noreferrer"&gt;3-2-1 backup strategy&lt;/a&gt; standards 😳.&lt;/p&gt;

&lt;p&gt;Over the holidays I received a new 4TB hard drive and with it, a renewed interest in backing up my data (at least the important stuff like pictures of my kids, and financial records.  I &lt;em&gt;guess&lt;/em&gt; in the worst case scenario, I could probably replace my Star Trek TNG blu-ray rips; so I'll keep those separate for now).&lt;/p&gt;

&lt;p&gt;With that in mind, I decided to combine it with an exercise that dives a bit further than I usually go into the Node.js ecosystem.&lt;/p&gt;

&lt;p&gt;This tutorial is the result of that exploration, and the result is a little tool for synchronizing backup copies of any directory on your machine. As a bonus we're going to configure it to support Linux, Mac and Windows.&lt;/p&gt;

&lt;p&gt;This is one of those posts where the biggest beneficiary in many ways is &lt;em&gt;myself&lt;/em&gt;.  I wanted to try something new and simply documented my experience with learning.  It follows &lt;a class="mentioned-user" href="https://dev.to/swyx"&gt;@swyx&lt;/a&gt;'s philosophy of &lt;a href="https://www.swyx.io/learn-in-public/" rel="noopener noreferrer"&gt;learn in public&lt;/a&gt; and share what you've learned with the wider community so hopefully everyone can benefit.&lt;/p&gt;

&lt;p&gt;That said, I should be very clear that this is primarily meant as a learning experience and is &lt;strong&gt;&lt;em&gt;absolutely not meant to be the best backup solution&lt;/em&gt;&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;If you're serious about remote storage then something like &lt;a href="https://www.google.com/intl/en_ca/drive/" rel="noopener noreferrer"&gt;Google Drive&lt;/a&gt; will get the job done for you. For local backups setting up a &lt;a href="https://en.wikipedia.org/wiki/RAID" rel="noopener noreferrer"&gt;RAID drive&lt;/a&gt; will cover your ass better than this little backup app will.&lt;/p&gt;

&lt;p&gt;That said, those options are a lot less &lt;strong&gt;&lt;em&gt;fun&lt;/em&gt;&lt;/strong&gt; so if you're willing to use this as a learning opportunity to practice your Node.js skills, and get some bonus scheduled backups out of it, I think you'll find this to be a really interesting tutorial.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What You Will Learn&lt;/li&gt;
&lt;li&gt;Try it Out (Optional)&lt;/li&gt;
&lt;li&gt;Configuring Your Machine (Optional)&lt;/li&gt;
&lt;li&gt;Creating the Project&lt;/li&gt;
&lt;li&gt;Cross Platform Support&lt;/li&gt;
&lt;li&gt;Running as a Background Process&lt;/li&gt;
&lt;li&gt;Adding a Discord Webhook (Bonus)&lt;/li&gt;
&lt;li&gt;Wrapping Up&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What You Will Learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Common Linux tools like &lt;code&gt;rsync&lt;/code&gt; (copying files locally and over SSH), &lt;code&gt;cron&lt;/code&gt; (scheduling tasks on a specific interval) and &lt;code&gt;nohup&lt;/code&gt; (run something as a background process that doesn't stop when the terminal session is ended)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Running Node (Javascript) apps as background processes, including automatic reboot on crash using &lt;code&gt;pm2&lt;/code&gt;, a production viable tool for Node.js servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More about the different values available on the &lt;code&gt;process&lt;/code&gt; object in Node.js including &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;platform&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create an app that behaves differently depending on which OS it's running on and works on both Bash (Mac/Linux) and Microsoft PowerShell (Windows)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send messages to a webhook with HTTP POST requests, in our example that webhook will be a Discord bot&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it Out (Optional)
&lt;/h2&gt;

&lt;p&gt;If you want to try it out first, then follow the instructions below. If you want to jump into creating your own version, then skip this section.&lt;/p&gt;

&lt;p&gt;This app will work on both Mac/Linux (Bash) and Windows (PowerShell).  &lt;/p&gt;

&lt;p&gt;All you need installed are &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;nodejs&lt;/code&gt;.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the project from  &lt;a href="https://github.com/alexeagleson/template-node-backup-directory" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; from the project directory&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the root with the following structure:&lt;/li&gt;
&lt;/ol&gt;

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

SOURCE_DIR="example-source/"
DESTINATION_DIR="example-destination/"
CRON_STRING="* * * * * *"
WEBHOOK_ID="DISCORD_WEBHOOK_ID"


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

&lt;/div&gt;

&lt;p&gt;Update &lt;code&gt;SOURCE_DIR&lt;/code&gt; to be the directory you want to copy, and &lt;code&gt;DESTINATION_DIR&lt;/code&gt; where you want to synchronize.  &lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;CRON_STRING&lt;/code&gt; to determine the schedule the copying occurs on.  If you are not familiar with cron strings use &lt;a href="https://crontab.guru/" rel="noopener noreferrer"&gt;this tool&lt;/a&gt; to help you create one.  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;DISCORD_WEBHOOK_ID&lt;/code&gt; is optional.  If you don't use it it will not impact the app.  If you do use it you remove the &lt;code&gt;https://discord.com/api/webhooks/&lt;/code&gt; portion of the webhook URLm the remainder is the &lt;code&gt;DISCORD_WEBHOOK_ID&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you can run the app with:&lt;/p&gt;

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

node backup.js


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

&lt;/div&gt;

&lt;p&gt;If you plan to run it as a long-term background process you can use PM2 which is described in the Running as a Background Process section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Your Machine (Optional)
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(Note: if you already have a machine and folders that you want to use for your backups setup, then you can skip this step entirely.  All we are going to cover in this section is setting up Ubuntu Linux on an old laptop, configuring it to run 24/7, and using SSH so that we can access and manage it remotely from other machines on our home network)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I'll be using this little blue Dell Inspiron with a whopping 2GB of RAM sitting around collecting dust.  &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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Fv1640763672%2Fblogs%2Fnode-backup%2Fbluey_k0oen1.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Fv1640763672%2Fblogs%2Fnode-backup%2Fbluey_k0oen1.jpg" alt="Little Bluey"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Honestly it's a great machine with an SSD inside of it, unfortunately it's just too bottlenecked by its 2GB of RAM, and there is no way to upgrade it (I've tried).  &lt;/p&gt;

&lt;p&gt;So for that reason I haven't been able to get much use out of it, but that changes now.  &lt;/p&gt;

&lt;p&gt;I began by following &lt;a href="https://ubuntu.com/tutorials/create-a-usb-stick-on-ubuntu#1-overview" rel="noopener noreferrer"&gt;this tutorial for installing Ubuntu with a USB stick&lt;/a&gt; and got the little laptop up and running with the latest Ubuntu.&lt;/p&gt;

&lt;p&gt;Next I needed to make sure I could access the laptop from the terminal on my main machine.  That will be done over SSH so I followed &lt;a href="https://linuxize.com/post/how-to-enable-ssh-on-ubuntu-20-04/" rel="noopener noreferrer"&gt;this tutorial on enabling SSH on Ubuntu&lt;/a&gt;.  Afterwards I confirmed I could successfully SSH into the laptop from my machine.&lt;/p&gt;

&lt;p&gt;Next I need to make sure that both &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;node&lt;/code&gt; are installed on the machine, so that I can clone my project and run it.  Fortunately &lt;code&gt;git&lt;/code&gt; comes by default with Ubuntu and I can installed &lt;code&gt;node&lt;/code&gt; with:&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;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nodejs


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

&lt;/div&gt;

&lt;p&gt;If this gives you any trouble just &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04" rel="noopener noreferrer"&gt;follow this tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next I plug in my external hard drives that I am going to be using as backups.  When I create my app I'll be pointing from one directory on one hard drive to another directory on the other hard drive to sync each week.&lt;/p&gt;

&lt;p&gt;Lastly I need to do a bit of housekeeping for the laptop to make sure it stays running and knows what to do when the lid is closed.  &lt;/p&gt;

&lt;p&gt;To keep it from sleeping it's as simple as &lt;code&gt;Settings -&amp;gt; Power&lt;/code&gt; and turn off &lt;code&gt;Automatic Suspend&lt;/code&gt;.  Basically disable anything that reads as if it will put your machine to sleep.&lt;/p&gt;

&lt;p&gt;Next I need to deal with what happens when I close the lid.  Unfortunately I don't see anything about that in Power settings so I need to edit the config file directly:&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;sudo &lt;/span&gt;gedit /etc/systemd/logind.conf


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

&lt;/div&gt;

&lt;p&gt;And change the following value from the default to &lt;code&gt;ignore&lt;/code&gt;:&lt;/p&gt;

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

HandleLidSwitch=ignore


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

&lt;/div&gt;

&lt;p&gt;If it is commented out (prefixed with &lt;code&gt;#&lt;/code&gt;) then remove the &lt;code&gt;#&lt;/code&gt; and save.  &lt;/p&gt;

&lt;p&gt;That's it!  I can now take the machine, close the lid and set it up in a nice cool area with the external drives attached ready to run all the time.  Ideally you should plug it into your router directly with ethernet to minimize wifi issues, however the laptop I have unfortunately has no ethernet, so I'll need to settle for wifi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Project
&lt;/h2&gt;

&lt;p&gt;Let's create a directory and initialize our Javascript project inside of it:&lt;/p&gt;

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

npm init &lt;span class="nt"&gt;-y&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Next we install the three dependency libraries for the project:&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;cron rsync dotenv


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

&lt;/div&gt;

&lt;p&gt;Here's what each one is used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;cron&lt;/strong&gt;: Will allow us to schedule the backup at specific intervals. This package uses a Javascript implementation of the &lt;em&gt;cron&lt;/em&gt; syntax and not the actual &lt;em&gt;cron&lt;/em&gt; daemon meaning we don't need to worry about OS compatibility issues with this package.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;rsync&lt;/strong&gt;: This will handle the copying and syncing of files for us. This package &lt;em&gt;does&lt;/em&gt; use the actual &lt;code&gt;rsync&lt;/code&gt; program installed on the user's machine so we will have to manage compatibility within our Node.js app for this one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;dotenv&lt;/strong&gt;: Allows us to read &lt;code&gt;.env&lt;/code&gt; files from our project directory. This will let us include our personal directory paths and also our private Discord webhook without sharing that data in the git repo. Users who clone the project can provide their own values.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll create a Javascript file called &lt;code&gt;backup.js&lt;/code&gt; and get the absolute basics working:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backup.js&lt;/code&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;CronJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;CronJob&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;Rsync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rsync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Equivalent to writing `rsync -a example-source/ example-destination/` on terminal&lt;/span&gt;
&lt;span class="nx"&gt;rsync&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;Rsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// The -a flag means "archive" to say we are copying the full directory not just a file&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;source&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example-source/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example-destination/&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;job&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;CronJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// Run this function once every minute&lt;/span&gt;
  &lt;span class="c1"&gt;// To learn more about this cron string visit the below link&lt;/span&gt;
  &lt;span class="c1"&gt;// https://crontab.guru/#*_*_*_*_*&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="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;rsync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&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="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cmd&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="c1"&gt;// List of rsync status codes&lt;/span&gt;
      &lt;span class="c1"&gt;// https://stackoverflow.com/a/20738063&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;backup completed with status code: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;code&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="kc"&gt;null&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="c1"&gt;// Replace with your time zone&lt;/span&gt;
  &lt;span class="c1"&gt;// https://gist.github.com/diogocapela/12c6617fc87607d11fd62d2a4f42b02a&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;America/Toronto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Begin the cronjob&lt;/span&gt;
&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Also create directories called &lt;code&gt;example-source&lt;/code&gt; and &lt;code&gt;example-destination&lt;/code&gt;.  Inside &lt;code&gt;example-source&lt;/code&gt; create a TXT file inside called &lt;code&gt;sample-file.txt&lt;/code&gt; with any content inside that file you like.  Doesn't matter what it is, it's just used to confirm our backup is working.&lt;/p&gt;

&lt;p&gt;Here's what things look like before the script has been run (note the empty &lt;code&gt;example-destination&lt;/code&gt; directory):&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Cbo_2px_solid_darkgrey%2Fv1640672226%2Fblogs%2Fnode-backup%2Fbackup-before_q0ndw5.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Cbo_2px_solid_darkgrey%2Fv1640672226%2Fblogs%2Fnode-backup%2Fbackup-before_q0ndw5.png" alt="Backup Before"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the script has run once:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Cbo_2px_solid_darkgrey%2Fv1640672226%2Fblogs%2Fnode-backup%2Fbackup-after_licaio.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Cbo_2px_solid_darkgrey%2Fv1640672226%2Fblogs%2Fnode-backup%2Fbackup-after_licaio.png" alt="Backup After"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Things are looking good, we have a once-every-minute interval backup of our &lt;code&gt;example-source&lt;/code&gt; directory to our &lt;code&gt;example-destination&lt;/code&gt; directory. &lt;/p&gt;

&lt;p&gt;At this point you could replace those directory strings with whatever folders you like and create a regular directory backup system on your machine.&lt;/p&gt;

&lt;p&gt;Let's make it easier to customize for those who are downloading and using our tool by adding &lt;code&gt;dotenv&lt;/code&gt; package to read &lt;code&gt;.env&lt;/code&gt; files as part of the configuration.&lt;/p&gt;

&lt;p&gt;If you've already followed the tutorial you have the &lt;code&gt;dotenv&lt;/code&gt; package installed with NPM so it's just a matter of importing it. Before we do let's create the &lt;code&gt;.env&lt;/code&gt; file. Make sure to note that is &lt;code&gt;.env&lt;/code&gt; with a starting &lt;code&gt;.&lt;/code&gt; (to indicate hidden files):&lt;/p&gt;

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

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

SOURCE_DIR="example-source/"
DESTINATION_DIR="example-destination/"
CRON_STRING="* * * * *"


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

&lt;/div&gt;

&lt;p&gt;Now we can update our code to read from that file. We just have to &lt;code&gt;require&lt;/code&gt; the &lt;code&gt;dotenv&lt;/code&gt; package at the top of our code:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backup.js&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&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;CronJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;CronJob&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;Rsync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rsync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Equivalent to writing `rsync -a example-source/ example-destination/` on terminal&lt;/span&gt;
&lt;span class="nx"&gt;rsync&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;Rsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// The -a flag means "archive" to say we are copying the full directory not just a file&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// Reads from the `.env` file in the project directory&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;source&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;SOURCE_DIR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destination&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;DESTINATION_DIR&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;job&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;CronJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// Run this function once every minute&lt;/span&gt;
  &lt;span class="c1"&gt;// To learn more about this cron string visit the below link&lt;/span&gt;
  &lt;span class="c1"&gt;// https://crontab.guru/#*_*_*_*_*&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;CRON_STRING&lt;/span&gt;&lt;span class="p"&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="nx"&gt;rsync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&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="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cmd&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="c1"&gt;// List of rsync status codes&lt;/span&gt;
      &lt;span class="c1"&gt;// https://stackoverflow.com/a/20738063&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;backup completed with status code: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;code&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="kc"&gt;null&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="c1"&gt;// Replace with your time zone&lt;/span&gt;
  &lt;span class="c1"&gt;// https://gist.github.com/diogocapela/12c6617fc87607d11fd62d2a4f42b02a&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;America/Toronto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Begin the cronjob&lt;/span&gt;
&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;When we run &lt;code&gt;node backup.js&lt;/code&gt; again we get the same result, but this time our source and destination directories are being read from the &lt;code&gt;.env&lt;/code&gt; file. This will make it easier for users to add their own source/destination directories and cron string when they download the tool.&lt;/p&gt;

&lt;p&gt;It also improves privacy as we will be adding &lt;code&gt;.env&lt;/code&gt; to our &lt;code&gt;.gitignore&lt;/code&gt; file so the directories that I choose to copy on my machine will not be included in the git repository for this project.&lt;/p&gt;

&lt;p&gt;In fact, let's do that now. If you're creating this project for yourself you'll want to be able to commit it to your remote git host, so run:&lt;/p&gt;

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

git init


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

&lt;/div&gt;

&lt;p&gt;Then create a &lt;code&gt;.gitignore&lt;/code&gt; file in the root directory with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt;&lt;/p&gt;

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

node_modules
.env
nohup.out


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

&lt;/div&gt;

&lt;p&gt;We exclude &lt;code&gt;.env&lt;/code&gt; for reasons mentioned above, and &lt;code&gt;node_modules&lt;/code&gt; since it will be re-created by running &lt;code&gt;npm install&lt;/code&gt; for anyone who uses our project.  The last one &lt;code&gt;nohup.out&lt;/code&gt; will contain some logs later in the tutorial that we don't need to share with others, so we're just adding it now in advance.&lt;/p&gt;

&lt;p&gt;Excellent! You now have a great little tool that works on Linux and Mac... but what about Windows?&lt;/p&gt;

&lt;p&gt;The truth is, basically all the development work I do is in a Linux environment. &lt;/p&gt;

&lt;p&gt;Even though I do all my daily development on Windows 11 with &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/compare-versions" rel="noopener noreferrer"&gt;WSL2&lt;/a&gt; I'm still doing everything inside a native installing of Ubuntu despite logging into Windows each day.&lt;/p&gt;

&lt;p&gt;I honestly don't even know how to use Windows &lt;code&gt;cmd&lt;/code&gt; or PowerShell beyond the DOS commands I still remember from when I was a kid (dir?)... but if the majority of my personal stuff (photos and documents) are stored on Windows, maybe this is a good opportunity for me to learn?&lt;/p&gt;

&lt;p&gt;I like learning new things! I challenge myself: what do I need to do to get this working on Windows?&lt;/p&gt;

&lt;p&gt;Turns out it was surprisingly easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross Platform Support
&lt;/h2&gt;

&lt;p&gt;Most of our app will work fine on Windows as-is, the big challenge here is &lt;a href="https://en.wikipedia.org/wiki/Rsync" rel="noopener noreferrer"&gt;rsync&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;As you can see from that link, &lt;code&gt;rsync&lt;/code&gt; is a Unix copying tool that will be natively available on most Linux and mac environments; but not Windows.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rsync&lt;/code&gt; package on NPM is simply a wrapper around the tool installed on your OS, so running our &lt;code&gt;backup.js&lt;/code&gt; in PowerShell gives us an error. The error is that the &lt;code&gt;rsync&lt;/code&gt; program does not exist.&lt;/p&gt;

&lt;p&gt;Here's the really cool thing though: not only does Windows have a very &lt;em&gt;similar&lt;/em&gt; tool with a similar API called &lt;a href="https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy" rel="noopener noreferrer"&gt;robocopy&lt;/a&gt;, the &lt;code&gt;rsync&lt;/code&gt; NPM package allows us to chain a method called &lt;code&gt;executable()&lt;/code&gt; that takes a string.&lt;/p&gt;

&lt;p&gt;That string is the name of the copying tool we want to use.&lt;/p&gt;

&lt;p&gt;It defaults to &lt;code&gt;rsync&lt;/code&gt;, but we can provide it with any name we want.&lt;/p&gt;

&lt;p&gt;We can check what OS the program is running on with &lt;code&gt;process.platform&lt;/code&gt; which will return &lt;code&gt;win32&lt;/code&gt; as a string when running on Windows.&lt;/p&gt;

&lt;p&gt;Let's update &lt;code&gt;backup.js&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backup.js&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&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;CronJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;CronJob&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;Rsync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rsync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// The value of process.platform will be:&lt;/span&gt;
&lt;span class="c1"&gt;// Windows: win32&lt;/span&gt;
&lt;span class="c1"&gt;// Mac: darwin&lt;/span&gt;
&lt;span class="c1"&gt;// Ubuntu: linux&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncProgram&lt;/span&gt; &lt;span class="o"&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;platform&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;win32&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;robocopy&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;rsync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Equivalent to writing `rsync -a example-source/ example-destination/` on terminal&lt;/span&gt;
&lt;span class="nx"&gt;rsync&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;Rsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncProgram&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// The -a flag means "archive" to say we are copying the full directory not just a file&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// Reads from the `.env` file in the project directory&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;source&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;SOURCE_DIR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destination&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;DESTINATION_DIR&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;job&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;CronJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// Run this function once every minute&lt;/span&gt;
  &lt;span class="c1"&gt;// To learn more about this cron string visit the below link&lt;/span&gt;
  &lt;span class="c1"&gt;// https://crontab.guru/#*_*_*_*_*&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;CRON_STRING&lt;/span&gt;&lt;span class="p"&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="nx"&gt;rsync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&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="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cmd&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;result&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// List of rsync status codes&lt;/span&gt;
        &lt;span class="c1"&gt;// https://stackoverflow.com/a/20738063&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Code &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;code&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;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Backup complete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentDate&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;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// Write log to the console, or will be redirected to a&lt;/span&gt;
      &lt;span class="c1"&gt;// nohup.out file if using nohup&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;stdout&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentDate&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;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&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="kc"&gt;null&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="c1"&gt;// Replace with your time zone&lt;/span&gt;
  &lt;span class="c1"&gt;// https://gist.github.com/diogocapela/12c6617fc87607d11fd62d2a4f42b02a&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;America/Toronto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Begin the cronjob&lt;/span&gt;
&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Notice the changes above. I did a check against &lt;code&gt;process.platform&lt;/code&gt; and if it returns &lt;code&gt;win32&lt;/code&gt; we set the executable copy program to &lt;code&gt;robocopy&lt;/code&gt; instead of &lt;code&gt;rsync&lt;/code&gt; which will allow it to run on Windows.&lt;/p&gt;

&lt;p&gt;Lucky for us the syntax for &lt;code&gt;robocopy&lt;/code&gt; is exactly the same as &lt;code&gt;rsync&lt;/code&gt;:&lt;/p&gt;

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

robocopy &amp;lt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &amp;lt;destination&amp;gt;


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

&lt;/div&gt;

&lt;p&gt;This means we don't have to change anything else about the way our program already works, the &lt;code&gt;rsync&lt;/code&gt; package will call &lt;code&gt;robocopy&lt;/code&gt; exactly the same way when we're on Windows.&lt;/p&gt;

&lt;p&gt;We're ready to try it out. In order to get the project files on Windows, I'm going to push them to Github and then clone them on by Windows filesystem.&lt;/p&gt;

&lt;p&gt;So here's what I do: &lt;a href="https://github.com/alexeagleson/template-node-backup-directory" rel="noopener noreferrer"&gt;I push this project to Github&lt;/a&gt;. Then I open PowerShell.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(I am a PowerShell noob, but I'm doing my best.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Turns out I don't even have &lt;code&gt;git&lt;/code&gt; or &lt;code&gt;node&lt;/code&gt; installed on Windows so I'm not going to get very far here. &lt;/p&gt;

&lt;p&gt;First I need to &lt;a href="https://git-scm.com/download/win" rel="noopener noreferrer"&gt;download git&lt;/a&gt; so I can clone the project, then I need to &lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;download node&lt;/a&gt; so I can run it.&lt;/p&gt;

&lt;p&gt;Once downloaded and installed I can run both these commands in PowerShell and get valid output:&lt;/p&gt;

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

PS C:\Users\ME&amp;gt; git --version
git version 2.34.1.windows.1

PS C:\Users\ME&amp;gt; node --version
v16.13.1


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

&lt;/div&gt;

&lt;p&gt;Now that everything is set I can &lt;code&gt;git clone MY_PROJECT_URL&lt;/code&gt; and then &lt;code&gt;cd&lt;/code&gt; into that directory and run:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before I can run the project though I need to create the &lt;code&gt;.env&lt;/code&gt; file since I did not include it in the repo for privacy reasons:&lt;/p&gt;

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

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

SOURCE_DIR="example-source/"
DESTINATION_DIR="example-destination/"
CRON_STRING="* * * * *"


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

&lt;/div&gt;

&lt;p&gt;Finally now in PowerShell in the project directory i run:&lt;/p&gt;

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

node backup.js


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

&lt;/div&gt;

&lt;p&gt;And my result:&lt;/p&gt;

&lt;p&gt;Before the script has been run on Windows (note the empty &lt;code&gt;example-destination&lt;/code&gt; directory)&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Cbo_2px_solid_darkgrey%2Fv1640676104%2Fblogs%2Fnode-backup%2Fwindows-backup-before_poxfzp.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Cbo_2px_solid_darkgrey%2Fv1640676104%2Fblogs%2Fnode-backup%2Fwindows-backup-before_poxfzp.png" alt="Backup Before"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the script has run once on Windows:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Cbo_2px_solid_darkgrey%2Fv1640676104%2Fblogs%2Fnode-backup%2Fwindows-backup-after_ziq2ck.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fr_20%2Cbo_2px_solid_darkgrey%2Fv1640676104%2Fblogs%2Fnode-backup%2Fwindows-backup-after_ziq2ck.png" alt="Backup After"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the status code doesn't necessarily match up with the &lt;code&gt;rsync&lt;/code&gt; status codes, but the result is correct: the copying process was successful.&lt;/p&gt;

&lt;p&gt;So that's really cool. You now have a tool that will copy the contents of one directory to another on an interval of your choice. Right now we have it setup to run every minute which is pretty overkill, but thanks to tools like &lt;a href="https://crontab.guru/" rel="noopener noreferrer"&gt;crontab guru&lt;/a&gt; it's easy to create exactly the interval you want.&lt;/p&gt;

&lt;p&gt;For example I only need to backup my directory once a week, so I'm going to set it to run &lt;a href="https://crontab.guru/#0_3_*_*_0" rel="noopener noreferrer"&gt;at 3am every Sunday&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We now have a backup process that runs on a schedule and works on Linux, Mac and Windows!&lt;/p&gt;

&lt;p&gt;But... how are we going to keep this running all the time?&lt;/p&gt;

&lt;p&gt;If we simply use &lt;code&gt;node backup.js&lt;/code&gt; the process is going to stop as soon as we close our terminal. We need this process to be running in the background, ideally 24/7.&lt;/p&gt;

&lt;p&gt;We are going to need a better solution. Enter &lt;code&gt;pm2&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running as a Background Process
&lt;/h2&gt;

&lt;p&gt;Before we get into our final solution using &lt;a href="https://pm2.keymetrics.io/" rel="noopener noreferrer"&gt;pm2&lt;/a&gt;, I'd like to quickly show Mac/Linux users how you can get this to work &lt;em&gt;without&lt;/em&gt; installing any addition tools at all using &lt;a href="https://en.wikipedia.org/wiki/Nohup" rel="noopener noreferrer"&gt;nohup&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can skip this section on &lt;code&gt;nohup&lt;/code&gt; if you like and go right to the final solution using PM2 if you like, it's just here to give you a bit of a deeper insight on how to create background processes using native Unix tools.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Using nohup (Optional - Mac and Linux Only)
&lt;/h3&gt;

&lt;p&gt;You can find out if you system supports &lt;code&gt;nohup&lt;/code&gt; with:&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;nohup&lt;/span&gt; &lt;span class="nt"&gt;--version&lt;/span&gt;


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

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

$ nohup --version
nohup (GNU coreutils) 8.30


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

&lt;/div&gt;

&lt;p&gt;If you get a version number successfully, then this next step should work for you.&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;nohup &lt;/span&gt;node backup.js &amp;amp;


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

&lt;/div&gt;

&lt;p&gt;The leading &lt;code&gt;nohup&lt;/code&gt; will tell your system that even when your session ends you don't want the process to stop, and the final trailing &lt;code&gt;&amp;amp;&lt;/code&gt; symbol means to run it as a background &lt;a href="https://en.wikipedia.org/wiki/Daemon_(computing)" rel="noopener noreferrer"&gt;daemon&lt;/a&gt; process.&lt;/p&gt;

&lt;p&gt;You will likely get an output that looks like:&lt;/p&gt;

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

[1] 7604


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

&lt;/div&gt;

&lt;p&gt;After running the command. This is the &lt;code&gt;process ID&lt;/code&gt; of your node program. If for any reason you lose track of it you can find it again with this command:&lt;/p&gt;

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

pstree &lt;span class="nt"&gt;-p&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You'll get output showing all the processes running on your system with their IDs. If you notice in the &lt;code&gt;backup.js&lt;/code&gt; code example above we used &lt;code&gt;process.title&lt;/code&gt; and gave it a string value of &lt;code&gt;node-backup-script&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This helps find and identify the process ID when we use the &lt;code&gt;pstree -p&lt;/code&gt; command:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640679514%2Fblogs%2Fnode-backup%2Fpstree_clntnk.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640679514%2Fblogs%2Fnode-backup%2Fpstree_clntnk.png" alt="Pstree Output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice the &lt;code&gt;node-backup-sc(7604)&lt;/code&gt; in there showing the same PID that we were given when the script started, and also the &lt;code&gt;title&lt;/code&gt; value we set with &lt;code&gt;process.title&lt;/code&gt; to make it easier to find and identify.&lt;/p&gt;

&lt;p&gt;Since we can no longer simply &lt;code&gt;ctrl+C&lt;/code&gt; to cancel the node script execution, we have to do something different. We have to kill the process by referencing the PID directly.&lt;/p&gt;

&lt;p&gt;To do that you can run:&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;kill&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; YOUR_PID


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

&lt;/div&gt;

&lt;p&gt;Where &lt;code&gt;YOUR_PID&lt;/code&gt; is the ID that is given on your machine. In my example above it's 7604. The &lt;code&gt;-9&lt;/code&gt; tells it to override anything that might stop or intercept a system kill signal, you want to end the program no matter what.&lt;/p&gt;

&lt;p&gt;So the &lt;code&gt;nohup&lt;/code&gt; option will work will for Unix systems that support it as long as they are running 24/7, the process will keep running. There are a couple of issues with it though:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your program crashes, &lt;code&gt;nohup&lt;/code&gt; will not reboot it&lt;/li&gt;
&lt;li&gt;This solution is Unix specific and will not work on Windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how do we create a solution that will run 24/7, will reboot on crash, and supports cross-platform? &lt;/p&gt;

&lt;p&gt;That's what &lt;a href="https://pm2.keymetrics.io/" rel="noopener noreferrer"&gt;pm2&lt;/a&gt; is for.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using PM2 (Cross Platform)
&lt;/h3&gt;

&lt;p&gt;Using PM2 we can run our backup script in the background on any system, including Windows, all we need is to have NPM installed.&lt;/p&gt;

&lt;p&gt;We'll use NPM to install PM2 globally:&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; pm2


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

&lt;/div&gt;

&lt;p&gt;After installing you'll be able to verify it is available with:&lt;/p&gt;

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

pm2 &lt;span class="nt"&gt;--version&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;To run your backup script:&lt;/p&gt;

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

pm2 start backup.js


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640680969%2Fblogs%2Fnode-backup%2Fpm2_thc0br.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640680969%2Fblogs%2Fnode-backup%2Fpm2_thc0br.png" alt="PM2 Start"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now the process is running in the background and will keep running even if you close your terminal, and will reboot on crash.&lt;/p&gt;

&lt;p&gt;You can view the running process anytime with &lt;code&gt;pm2 list&lt;/code&gt; and you can stop it with &lt;code&gt;pm2 stop backup&lt;/code&gt; where "backup" is the name of the process.&lt;/p&gt;

&lt;p&gt;You can also view the logs of your app by running  &lt;code&gt;pm2 logs backup&lt;/code&gt;.  You'll get an output that looks like:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640739353%2Fblogs%2Fnode-backup%2Fpm2-logs_wrzsld.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640739353%2Fblogs%2Fnode-backup%2Fpm2-logs_wrzsld.png" alt="PM2 Logs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately this will not survive a full system reboot. Configuring &lt;code&gt;pm2&lt;/code&gt; to start with your app automatically on reboot is beyond the scope of this tutorial, but there are very good instructions on how to handle it if you would like to do.&lt;/p&gt;

&lt;p&gt;Here's for &lt;a href="https://pm2.keymetrics.io/docs/usage/startup/" rel="noopener noreferrer"&gt;Unix based systems&lt;/a&gt; and &lt;a href="https://github.com/jessety/pm2-installer" rel="noopener noreferrer"&gt;Windows&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can now keep this running on an old laptop, or on your own cloud server like a $5 monthly &lt;a href="https://www.digitalocean.com/products/droplets/" rel="noopener noreferrer"&gt;Digital Ocean Droplet&lt;/a&gt; for example.&lt;/p&gt;

&lt;p&gt;Just be careful when looking at Node app hosting solutions, there are a lot of options out there, but the majority of free ones (Heroku for example) will put your app to "sleep" sometimes, which isn't a viable option as it must be awake when the scheduled backup triggers in order to work properly.&lt;/p&gt;

&lt;p&gt;Lastly we'll add a little bonus tutorial showing how to use webhooks to send the status output of our backups to a Discord bot so that we can keep track of it easily.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Discord Webhook (Bonus)
&lt;/h2&gt;

&lt;p&gt;This section will teach you how to print the resulting status code from your backup action to a bot on your Discord server in addition to the PM2 logs.  &lt;/p&gt;

&lt;p&gt;Start by creating your webhook on your server.  Follow &lt;a href="https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt; up to the end of the section called &lt;strong&gt;Making a Webhook&lt;/strong&gt;.  Stop when you get to &lt;strong&gt;Quick Example: GitHub Webhook Integration&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;All you need is to get to the point where you can click the button that says "Copy Webhook URL".  It will look like:&lt;/p&gt;

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

https://discord.com/api/webhooks/YOUR_WEBHOOK_ID


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

&lt;/div&gt;

&lt;p&gt;Where YOUR_WEBHOOK_ID is a long string of characters which may include additional slashes.  Basically everything after the &lt;code&gt;https://discord.com/api/webhooks/&lt;/code&gt; you want to copy and paste into the &lt;code&gt;WEBHOOK_ID&lt;/code&gt; key in your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

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

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

SOURCE_DIR="example-source/"
DESTINATION_DIR="example-destination/"
CRON_STRING="* * * * * *"
WEBHOOK_ID="YOUR_WEBHOOK_ID"


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

&lt;/div&gt;

&lt;p&gt;Next we'll update &lt;code&gt;backup.js&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backup.js&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&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;CronJob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cron&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;CronJob&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;Rsync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rsync&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;https&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&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&lt;/span&gt;&lt;span class="dl"&gt;"&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;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node-backup-script&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Will be true if there is a Discord WEBHOOK_ID set in the `.env` file&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useDiscord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&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;WEBHOOK_ID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;discord.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/api/webhooks/&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;WEBHOOK_ID&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="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;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="c1"&gt;// process.platform will be:&lt;/span&gt;
&lt;span class="c1"&gt;// Windows: win32&lt;/span&gt;
&lt;span class="c1"&gt;// Mac: darwin&lt;/span&gt;
&lt;span class="c1"&gt;// Ubuntu: linux&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;syncProgram&lt;/span&gt; &lt;span class="o"&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;platform&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;win32&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;robocopy&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;rsync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Equivalent to writing `rsync -a example-source/ example-destination/` on terminal&lt;/span&gt;
&lt;span class="nx"&gt;rsync&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;Rsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncProgram&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// The -a flag means "archive" to say we are copying the full directory not just a file&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// Reads from the `.env` file in the project directory&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;source&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;SOURCE_DIR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destination&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;DESTINATION_DIR&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;job&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;CronJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// Run this function once every minute&lt;/span&gt;
  &lt;span class="c1"&gt;// To learn more about this cron string visit the below link&lt;/span&gt;
  &lt;span class="c1"&gt;// https://crontab.guru/#*_*_*_*_*&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;CRON_STRING&lt;/span&gt;&lt;span class="p"&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="nx"&gt;rsync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&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="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cmd&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;result&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;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// List of rsync status codes&lt;/span&gt;
        &lt;span class="c1"&gt;// https://stackoverflow.com/a/20738063&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Code &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;code&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;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Backup complete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentDate&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;toISOString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// Write log to the console, or will be redirected to a&lt;/span&gt;
      &lt;span class="c1"&gt;// nohup.out file if using nohup&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;stdout&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;currentDate&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;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Only sends the request if WEBHOOK_ID is defined&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;useDiscord&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send the request to Discord with the configured options&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&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="nx"&gt;options&lt;/span&gt;&lt;span class="p"&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// do nothing with Discord response&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="c1"&gt;// Discord requires a { content: string } shape for posting messages&lt;/span&gt;
        &lt;span class="nx"&gt;req&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="kc"&gt;null&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="c1"&gt;// Replace with your time zone&lt;/span&gt;
  &lt;span class="c1"&gt;// https://gist.github.com/diogocapela/12c6617fc87607d11fd62d2a4f42b02a&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;America/Toronto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Begin the cronjob&lt;/span&gt;
&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;Presuming you set up your webhook bot correctly, you will see it post a message on your Discord channel with the status of the backup every time the cron job fires.  &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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640678608%2Fblogs%2Fnode-backup%2Fdiscord-bot_ebyx5w.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640678608%2Fblogs%2Fnode-backup%2Fdiscord-bot_ebyx5w.png" alt="Discord Bot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use this as a convenient way to see the log output without having to log into your server and check manually.  If there is an error, the Discord bot will print the error message.  For example if I change the source to a folder that does not exist:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640738833%2Fblogs%2Fnode-backup%2Fdiscord-bot-error_newy9m.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fbo_2px_solid_darkgrey%2Fv1640738833%2Fblogs%2Fnode-backup%2Fdiscord-bot-error_newy9m.png" alt="Discord Bot Error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can lookup the &lt;a href="https://stackoverflow.com/a/20738063" rel="noopener noreferrer"&gt;status code&lt;/a&gt; to get more information about the problem.&lt;/p&gt;

&lt;p&gt;So we've now handled all of the major features required for this project!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a backup of one directory to another&lt;/li&gt;
&lt;li&gt;Support for scheduled times of backups&lt;/li&gt;
&lt;li&gt;Cross platform support&lt;/li&gt;
&lt;li&gt;Communication of success/error (either through PM2 logs or Discord)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;I hope you learned something new from this tutorial, I know it was kind of a hodge-podge of different concepts, but that was a big part of the idea.  One of my favourite ways of learning new things is to connect existing skills and tools in interesting ways.  &lt;/p&gt;

&lt;p&gt;Please check some of my other learning tutorials.  Feel free to leave a comment or question and share with others if you find any of them helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/docker-for-javascript-developers-41me"&gt;Introduction to Docker for Javascript Developers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg"&gt;Learnings from React Conf 2021&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg"&gt;How to Create a Dark Mode Component in React&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34"&gt;How to Analyze and Improve your 'Create React App' Production Build &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe"&gt;How to Create and Publish a React Component Library&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-indexeddb-to-store-data-for-your-web-application-in-the-browser-1o90"&gt;How to use IndexedDB to Store Local Data for your Web App &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g"&gt;Running a Local Web Server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-linters-eslint-59pm"&gt;ESLint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-prettier-214j"&gt;Prettier&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp"&gt;Babel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7"&gt;React &amp;amp; JSX&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-1-2mn1"&gt;Webpack: The Basics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-2-49bj"&gt;Webpack: Loaders, Optimizations &amp;amp; Bundle Analysis&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;For more tutorials like this, follow me &lt;a href="https://twitter.com/eagleson_alex?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@eagleson_alex&lt;/a&gt; on Twitter.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>linux</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Introduction to Docker for Javascript Developers (feat Node.js and PostgreSQL)</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Wed, 22 Dec 2021 13:24:29 +0000</pubDate>
      <link>https://dev.to/alexeagleson/docker-for-javascript-developers-41me</link>
      <guid>https://dev.to/alexeagleson/docker-for-javascript-developers-41me</guid>
      <description>&lt;p&gt;All code from this tutorial as a complete package is available in &lt;a href="https://github.com/alexeagleson/docker-node-postgres-template" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.  If you find this tutorial helpful, please share it with your friends and colleagues!&lt;/p&gt;

&lt;p&gt;For more tutorials like this, follow me &lt;a href="https://twitter.com/eagleson_alex?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@eagleson_alex&lt;/a&gt; on Twitter&lt;/p&gt;

&lt;p&gt;A video version is also available:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Te41e4urFO0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;What is Docker?&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Installing Docker&lt;/li&gt;
&lt;li&gt;Creating a Container&lt;/li&gt;
&lt;li&gt;Creating a Node App&lt;/li&gt;
&lt;li&gt;Deprecating the Node App&lt;/li&gt;
&lt;li&gt;Creating a Dockerfile&lt;/li&gt;
&lt;li&gt;Docker Layers and Cache&lt;/li&gt;
&lt;li&gt;Adding a Docker Volume&lt;/li&gt;
&lt;li&gt;What is Docker-Compose?&lt;/li&gt;
&lt;li&gt;Adding a Database&lt;/li&gt;
&lt;li&gt;Connecting the App to the Database&lt;/li&gt;
&lt;li&gt;Adding a Frontend&lt;/li&gt;
&lt;li&gt;Creating a Docker Compose YML File&lt;/li&gt;
&lt;li&gt;Adding a pgAdmin Panel (Bonus)&lt;/li&gt;
&lt;li&gt;Useful Docker Commands&lt;/li&gt;
&lt;li&gt;Wrapping Up&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this tutorial you will learn what Docker is and what purpose it serves by building a fullstack Node.js app complete with frontend and PostgreSQL database.  &lt;/p&gt;

&lt;p&gt;We will use Docker Compose to connect and network each container together so that they are easy to share among project contributors, and deploy to whatever hosting service you've chosen.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Docker?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/get-started/overview/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; is a tool that allows you package the environment for running your application along with the application itself.  You can accomplish this as simply as including a single file called &lt;code&gt;Dockerfile&lt;/code&gt; with your project.&lt;/p&gt;

&lt;p&gt;It uses a concept it calls &lt;em&gt;containers&lt;/em&gt; which are lighter weight (require less resources) than full on virtual machines to create the environment for your application.  These containers are designed to be extremely &lt;em&gt;portable&lt;/em&gt; which means that you can quickly deploy them anywhere, and also scale up your app quickly by simply deploying more copies of your container.  &lt;/p&gt;

&lt;p&gt;All you need to do is define the requirements for your environment in the &lt;code&gt;Dockerfile&lt;/code&gt; (for example Ubuntu 18, Node.js, etc) and every time your container is started on any machine, it will recreate exactly that environment. So you already know in advance that you will not have any issue with missing dependencies or incorrect versions.&lt;/p&gt;

&lt;p&gt;That said, it can be challenging to really demonstrate the need for Docker to those new to the development world who haven't yet experienced a lot of the problems that it solves.  &lt;/p&gt;

&lt;p&gt;This tutorial aims to simulate a a couple of realistic scenarios you might encounter in a work environment, and show how Docker helps to solve those issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Scenario
&lt;/h3&gt;

&lt;p&gt;There are two common development issues we will be replicating with this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your company's project relies on an older version of a tool (in our case &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;) than the development team has installed on their machine&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We want to make it easy to test the application with a copy of the database on the developers' local machine, without requiring them to install the database software (in our case PostgreSQL)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you follow this tutorial you will have a working application running on your machine and querying a Postgres DB without the need to have either Node.js or Postgres installed.  The only tool you will need is Docker.  &lt;/p&gt;

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

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;The only prerequisite software required to have installed for this tutorial is an IDE (code editor, I use VS Code) and Docker.  &lt;/p&gt;

&lt;p&gt;How you install Docker will depend on the operating system you are running.  I am running it on &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-manual#step-2---check-requirements-for-running-wsl-2" rel="noopener noreferrer"&gt;WSL2&lt;/a&gt; on Windows 11 which is a fantastic experience.  It works just as well on Mac and Linux, you simply need to &lt;a href="https://www.docker.com/get-started" rel="noopener noreferrer"&gt;follow the installation instructions for your OS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I recommend Docker Desktop which will give you a nice GUI for working with Docker, however it is not required.  For this tutorial will will be managing Docker entirely through the command line (though I may use Docker Desktop for screenshots to show what is happening).&lt;/p&gt;

&lt;p&gt;I also suggest having &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; installed as well.  Technically you &lt;em&gt;can&lt;/em&gt; get away without it, but in the first couple of steps we're going to run the app locally before we get Docker involved.  It will also help demonstrate how Docker fixes our versioning issue.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Docker
&lt;/h2&gt;

&lt;p&gt;Once you have Docker installed let's make sure that it works.  When you type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get a version number (as opposed to "not found").  My version right now shows 20.10.11, but any version close to that number should work fine.  &lt;/p&gt;

&lt;p&gt;Most containers are hosted on a service called &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt;, including the ones we will be using.  &lt;/p&gt;

&lt;p&gt;Let's begin by testing the simplest container called &lt;code&gt;hello-world&lt;/code&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Container
&lt;/h2&gt;

&lt;p&gt;Run the following command to download the &lt;code&gt;hello-world&lt;/code&gt; image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will pull the &lt;em&gt;image&lt;/em&gt; from Docker hub.  Important to get the terminology correct, we haven't created a &lt;em&gt;container&lt;/em&gt; yet.  A Docker image is a &lt;em&gt;set of instructions for how to create a container&lt;/em&gt;.  If you are familiar with web development, think of the image like HTML (blueprints) and the container like the DOM (the structure).  &lt;/p&gt;

&lt;p&gt;You can add additional instructions to the default image instructions in your &lt;code&gt;Dockerfile&lt;/code&gt; which we will get to soon.&lt;/p&gt;

&lt;p&gt;Presuming you got a success message like &lt;code&gt;Status: Image is up to date for hello-world:latest&lt;/code&gt;, you are ready to create a container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If successful, you will see this output in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations!  You have run your first Docker container!  Although you can manage it very easily if you are using Docker Desktop, let's look at a couple of the most common commands to manage it on the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker image &lt;span class="nb"&gt;ls&lt;/span&gt;

&lt;span class="c"&gt;# OR&lt;/span&gt;

docker container &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will show you a list of all the images or containers you have on your system at the moment.  Because &lt;code&gt;hello-world&lt;/code&gt; stops as soon as it's finished printing the test message, it does not keep running forever like a container running a web app would.  You won't see it in your list of containers, but you will see it in your list of images.&lt;/p&gt;

&lt;p&gt;Both the ID of the image/container and the name are important to be able to lookup because they allow you to refer to those images/containers to start/stop them.  &lt;/p&gt;

&lt;p&gt;When you stop running a container it doesn't get deleted.  That is a good thing!  It means it's super fast to just start it up again the next time you need it without downloading and installing it again.  &lt;/p&gt;

&lt;p&gt;While working with Docker you'll find that sometimes these images and containers begin to pile up when you change things or build new versions.  To quickly remove all old/unused ones you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker image prune

&lt;span class="c"&gt;# OR&lt;/span&gt;

docker container prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If these don't seem too helpful now, don't worry, but keep them in mind because you will likely want to refer back to them later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Node App
&lt;/h2&gt;

&lt;p&gt;Before we get any further into Docker, let's build a small web app we can use to help demonstrate some of the more advanced features of Docker.  We're going to build a simple web server in Node.js and Express:&lt;/p&gt;

&lt;p&gt;I've created a new empty directory called &lt;code&gt;docker-template&lt;/code&gt; and initialized an NPM repo inside of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;docker-template
&lt;span class="nb"&gt;cd &lt;/span&gt;docker-template
npm init
npm &lt;span class="nb"&gt;install &lt;/span&gt;express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&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="nf"&gt;express&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&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;/&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;setHeader&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;h1&amp;gt;Hello world&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&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;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run your app with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And go to &lt;a href=""&gt;http://localhost:8080&lt;/a&gt; to see:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1640125011%2Fblogs%2Fdocker-node%2Fdocker-hello-world_gdeltv.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1640125011%2Fblogs%2Fdocker-node%2Fdocker-hello-world_gdeltv.png" alt="Node Hello World"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One extra thing we would like to enable for this project is file watching and automatic reloading of the server whenever the file is changed.&lt;/p&gt;

&lt;p&gt;The easiest way to do that is a tool called &lt;a href="https://www.npmjs.com/package/nodemon" rel="noopener noreferrer"&gt;nodemon&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;nodemon &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add a &lt;code&gt;start&lt;/code&gt; script to your &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&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 json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"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;"nodemon server.js"&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;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"me"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ISC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&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;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.17.2"&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;"devDependencies"&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;"nodemon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.0.15"&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;Run your app with:&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;Try editing your &lt;code&gt;server.js&lt;/code&gt; file when your app is running (change "hello world" to "hello world!!!!" or something) and verify that your Node app reloads and you see the change in your browser when you hit the refresh button (the file watching won't trigger a browser refresh automatically).&lt;/p&gt;

&lt;p&gt;Once that is working continue to the next step!&lt;/p&gt;

&lt;h2&gt;
  
  
  Deprecating the Node App
&lt;/h2&gt;

&lt;p&gt;This next part is kinda fun.  Let's intentionally turn this server into a legacy project.  &lt;/p&gt;

&lt;p&gt;We'll be assuming you are running a recent version of Node (15 or later).  You can check by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My output is &lt;code&gt;v16.11.1&lt;/code&gt;.  If yours is older than 15 you can either use &lt;a href="https://github.com/nvm-sh/nvm#installing-and-updating" rel="noopener noreferrer"&gt;NVM&lt;/a&gt; or just read along.  Installing a specific Node version of your machine is not required for this part.  In fact it's exactly the problem we're going to solve with Docker in the next section.&lt;/p&gt;

&lt;p&gt;In Node 15 there is a &lt;em&gt;breaking change&lt;/em&gt; in the way that &lt;a href="https://blog.logrocket.com/node-js-15-whats-new-and-how-the-developer-experience-has-improved/" rel="noopener noreferrer"&gt;unhandled rejected promises&lt;/a&gt; are handled.  Before version 15 a Javascript promise that was rejected without a catch would give a warning and keep running, but after v15 of Node an unhandled promise will &lt;strong&gt;crash the program&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So it's possible for use to add some code that will make our server work on versions of Node older than 15, but &lt;em&gt;not work&lt;/em&gt; on new versions of Node.&lt;/p&gt;

&lt;p&gt;Let's do that now:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @ts-check&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&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="nf"&gt;express&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&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;/&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;setHeader&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;h1&amp;gt;Hello world&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&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;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myPromise&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;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="nf"&gt;setTimeout&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="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;good&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="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bad&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;myPromise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;this will never run&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above creates a new promise that always rejects.  It will run (with a warning) on Node.js v14, but will &lt;em&gt;crash&lt;/em&gt; on v15 and above.  Try running it yourself on v15 and above and you get &lt;code&gt;code: 'ERR_UNHANDLED_REJECTION'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now obviously we could just... add a catch block (or remove the code entirely), but we are trying to replicate a scenario where you are working with an older codebase and you may not necessarily have those options available to you.  &lt;/p&gt;

&lt;p&gt;Let's say for one reason or another this app &lt;em&gt;must&lt;/em&gt; be run on Node v14 or earlier to work.  Every developer on the team must be prepared to operate in that environment... but our company also has a new app that runs on Node v17!  So we need that environment available too.  &lt;/p&gt;

&lt;p&gt;And while we're at it, some other tool on version X! I only have version Y on my machine!  Who knows what version the other members of my team are running.  Or the guy I send the app to for testing.  &lt;/p&gt;

&lt;p&gt;What do I do!?&lt;/p&gt;

&lt;p&gt;Enter Docker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Dockerfile
&lt;/h2&gt;

&lt;p&gt;With Docker we can use code to generate the environment that our app runs in.  We'll begin by searching Docker hub for a Node.js image.  The official Node image is just called &lt;a href="https://hub.docker.com/_/node" rel="noopener noreferrer"&gt;node&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You'll notice when you look at supported tags there are a lot of versions.  Just like having a certain version on your machine, there's Docker images for pretty much every version you could want.  Of course Node itself needs to be installed on some kind of operating system so that's usually the other part of the tag.&lt;/p&gt;

&lt;p&gt;The default Node image runs on &lt;a href="https://wiki.debian.org/DebianReleases" rel="noopener noreferrer"&gt;Debian&lt;/a&gt;, however one of the most popular versions runs on something called &lt;a href="https://alpinelinux.org/" rel="noopener noreferrer"&gt;Alpine Linux&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main reason Alpine is popular is because of its small size, it's a distro of Linux designed to strip out all but the most necessary parts.  This means it will be faster and more cost effective to run and distribute our app on this image (assuming it meets our needs).&lt;/p&gt;

&lt;p&gt;For our simple app, it does.&lt;/p&gt;

&lt;p&gt;Remember we &lt;em&gt;specifically&lt;/em&gt; want an older version of Node (older than v15 so our app runs without crashing) so I am going to choose the image tagged &lt;code&gt;node:14-alpine3.12&lt;/code&gt;.  That's Node v14 and Alpine v3.12.&lt;/p&gt;

&lt;p&gt;We can pull the image in advance with &lt;code&gt;docker pull node:14-alpine3.12&lt;/code&gt; just like we did with &lt;code&gt;hello-world&lt;/code&gt;, but it's not necessary.  By adding it to our &lt;code&gt;Dockerfile&lt;/code&gt; Docker will automatically pull it from Docker Hub if it doesn't find it on our machine.&lt;/p&gt;

&lt;p&gt;Let's create a file called &lt;code&gt;Dockerfile&lt;/code&gt; (no extension) in the root of our project next to &lt;code&gt;server.js&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;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="c"&gt;# select your base image to start with&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:14-alpine3.12&lt;/span&gt;

&lt;span class="c"&gt;# Create app directory&lt;/span&gt;
&lt;span class="c"&gt;# this is the location where you will be inside the container&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="c"&gt;# Install app dependencies&lt;/span&gt;
&lt;span class="c"&gt;# A wildcard is used to ensure both package.json AND package-lock.json are copied&lt;/span&gt;
&lt;span class="c"&gt;# where available (npm@5+)&lt;/span&gt;
&lt;span class="c"&gt;# copying packages first helps take advantage of docker layers&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="c"&gt;# If you are building your code for production&lt;/span&gt;
&lt;span class="c"&gt;# RUN npm ci --only=production&lt;/span&gt;

&lt;span class="c"&gt;# Bundle app source&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Make this port accessible from outside the container&lt;/span&gt;
&lt;span class="c"&gt;# Necessary for your browser to send HTTP requests to your Node app&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;

&lt;span class="c"&gt;# Command to run when the container is ready&lt;/span&gt;
&lt;span class="c"&gt;# Separate arguments as separate values in the array&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "npm", "run", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've added a lot of comments to help explain each piece of the Dockerfile.  You can learn more about &lt;a href="https://docs.docker.com/engine/reference/builder/" rel="noopener noreferrer"&gt;Dockerfiles here&lt;/a&gt;, I would highly encourage you to skim through that page to get familiar with the commands that are available. &lt;/p&gt;

&lt;p&gt;Before we continue I would like to touch briefly on Docker's layers &amp;amp; cache because they are very important topics!&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Layers and Cache
&lt;/h2&gt;

&lt;p&gt;One common question for a simple Dockerfile like this is: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Why are you using the COPY command twice?  Isn't the first COPY unnecessary since the second one copies the whole directory?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer is actually "no" and the reason is because of one of Docker's best features called &lt;em&gt;layers&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;Every time you use one of FROM, COPY, RUN, CMD it creates another image which is based off the previous layer.  That image can be cached and only needs to be created again if something changes.  &lt;/p&gt;

&lt;p&gt;So by creating a specific COPY line on &lt;code&gt;package-*.json&lt;/code&gt; we are creating a layer that is based off the content of that file before we run &lt;code&gt;npm install&lt;/code&gt;.  That means that unless we &lt;em&gt;change&lt;/em&gt; &lt;code&gt;package.json&lt;/code&gt;, the next time we build Docker will use the cache layer where &lt;code&gt;npm install&lt;/code&gt; has already been run and we don't have to install all dependencies every time we run &lt;code&gt;docker build&lt;/code&gt;.  That will save us an enormous amount of time.  &lt;/p&gt;

&lt;p&gt;The next COPY looks at every file in our project directory, so that layer will be rebuilt on any file change (basically any time we update anything OTHER than &lt;code&gt;package.json&lt;/code&gt; in our app).  But that's exactly what we want.  &lt;/p&gt;

&lt;p&gt;This is just one example of efficiencies you can take advantage of when working with Docker, but I would encourage you to read the whole &lt;a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/" rel="noopener noreferrer"&gt;list of best practices for Dockerfiles&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the App Container
&lt;/h2&gt;

&lt;p&gt;Now that your Dockerfile is created we have just one last thing we need to do before we build.&lt;/p&gt;

&lt;p&gt;Similar to &lt;code&gt;.gitignore&lt;/code&gt; that you're probably familiar with (used to prevent committing auto-generated files and private secrets to public repositories), Docker has a similar concept to keep you from unnecessarily copying files that your container doesn't need.&lt;/p&gt;

&lt;p&gt;Let's create a &lt;code&gt;.dockerignore&lt;/code&gt; file now:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.dockerignore&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;node_modules
npm-debug.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both of those will be generated inside the container, so we don't want to copy our local versions of them over.&lt;/p&gt;

&lt;p&gt;At this point we are ready to build.  Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; my-node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will build the &lt;em&gt;image&lt;/em&gt; describe by the Dockerfile in the current directory &lt;code&gt;.&lt;/code&gt; and give it a name called &lt;code&gt;my-node-app&lt;/code&gt;.  When it's done you can see the image and all its details with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker image &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the image created, we are now ready to build a &lt;em&gt;container&lt;/em&gt; off our image which will run our app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:8080 &lt;span class="nt"&gt;--name&lt;/span&gt; my-node-app-container my-node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command tells Docker to use our image to build a running container.  The &lt;code&gt;--name&lt;/code&gt; flag lets us name the container (to make it easier to identify and stop/start later, otherwise the name will be randomly generated).&lt;/p&gt;

&lt;p&gt;I used the name &lt;code&gt;my-node-app-container&lt;/code&gt; to differentiate it from the last argument which is the name of the &lt;em&gt;image&lt;/em&gt; we are building from (&lt;code&gt;my-node-app&lt;/code&gt;).  &lt;/p&gt;

&lt;p&gt;We use the &lt;code&gt;-p&lt;/code&gt; flag to bind ports from our host machine (our computer) environment to the container environment.  &lt;/p&gt;

&lt;p&gt;If you recall we wrote &lt;code&gt;EXPOSE 8080&lt;/code&gt; in our Dockerfile which is the port our app runs on.  The above command maps port 3000 on our machine to port 8080 in the container.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note you can map the same port like 8080:8080 if you like, we just mixed it up in this example to show that it's possible)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Double check that your container started successfully with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker container &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My output looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONTAINER ID   IMAGE         COMMAND                  CREATED         STATUS         PORTS                    NAMES
b6523b2602e1   my-node-app   "docker-entrypoint.s…"   6 minutes ago   Up 6 minutes   0.0.0.0:3000-&amp;gt;8080/tcp   my-node-app-container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Sorry if the words wrap and it make it difficult to line things up)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can see that the container is up for X minutes.  That means that our app is running on port 8080, we can access that port on our machine using port 3000 so open up your browser to &lt;a href=""&gt;http://localhost:3000/&lt;/a&gt; to see:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1640138143%2Fblogs%2Fdocker-node%2Fdocker-hello-world-2_mq9fop.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1640138143%2Fblogs%2Fdocker-node%2Fdocker-hello-world-2_mq9fop.png" alt="Docker Node Hello World"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great!  You've created your first custom Docker image and container with your own app running in it!&lt;/p&gt;

&lt;p&gt;So now that you have your environment setup, naturally one of the next things you might want to do is update your app.  If you make a change to &lt;code&gt;server.js&lt;/code&gt; and save the file, are you going to see those changes when you reload the page?&lt;/p&gt;

&lt;p&gt;No you won't.  The app is running based on a copy of &lt;code&gt;server.js&lt;/code&gt; inside the container which has no direct relation to the one in your project directory.  Is there a way that we can "connect" them somehow?&lt;/p&gt;

&lt;p&gt;Of course there is, we need to introduce Docker volumes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Docker Volume
&lt;/h2&gt;

&lt;p&gt;Docker uses the concept of &lt;a href="https://docs.docker.com/storage/volumes/" rel="noopener noreferrer"&gt;volumes&lt;/a&gt; to allow you to &lt;em&gt;persist&lt;/em&gt; data between running containers.  &lt;/p&gt;

&lt;p&gt;You can imagine you might want to have your app save some data, but with the way Docker works your containers are designed to be destroyed and recreated casually.  &lt;/p&gt;

&lt;p&gt;There are two primary ways to use volumes.  You can create one in advance and give it a &lt;em&gt;name&lt;/em&gt;.  This will save all the volume data by default in the &lt;code&gt;/var/lib/docker/volumes&lt;/code&gt; directory (in a Linux environment, it would be somewhere different but equivalent on Windows).  &lt;/p&gt;

&lt;p&gt;To create a named volume (you don't need to run this command for this tutorial, it's simply an example):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume create my-named-volume
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you would map any directory in your container to that directory on your machine.  You can do so by adding the &lt;code&gt;--volume&lt;/code&gt; flag to your &lt;code&gt;docker run&lt;/code&gt; command like so: &lt;code&gt;--volume  my-named-volume:/usr/src/app my-node-app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That example would map the working directory in your container to the Docker volume on your machine.  This does not help us however because we want to synchronize a &lt;em&gt;specific&lt;/em&gt; directory (our project directory) with the one in the container so we can edit files in our project and have them update in the container.  &lt;/p&gt;

&lt;p&gt;We can do this as well.&lt;/p&gt;

&lt;p&gt;First we need to stop the existing container (which doesn't have a volume), remove it, and then run it again &lt;strong&gt;with&lt;/strong&gt; the volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker container stop my-node-app-container

docker container &lt;span class="nb"&gt;rm &lt;/span&gt;my-node-app-container

docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:8080 &lt;span class="nt"&gt;--name&lt;/span&gt; my-node-app-container &lt;span class="nt"&gt;--volume&lt;/span&gt;  &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/usr/src/app my-node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In most terminals PWD means "print working directory" so it will map the current directory to the &lt;code&gt;/usr/src/app&lt;/code&gt; directory inside your container.  This will accomplish our goal of syncing the files between our project on our computer and the one in our container.  &lt;/p&gt;

&lt;p&gt;Since we have already set up file watching and reloading with &lt;code&gt;nodemon&lt;/code&gt; earlier in the tutorial, you should now be able to edit &lt;code&gt;server.js&lt;/code&gt; in your project directory while the container is running (just edit the hello world text), then refresh your browser to see the changes.&lt;/p&gt;

&lt;p&gt;And that's it!  You now have a Dockerized Node app where you can make changes on your machine and see the updates happen live inside your container.  &lt;/p&gt;

&lt;p&gt;At this point we have mostly completed our introduction to Docker itself.  We have completed our implementation of our first "scenario" where we use coded instructions to recreate the environment that our app requires in order to operate.&lt;/p&gt;

&lt;p&gt;We now need to address our second common scenario: in order to function our application relies on other services, like a database for example.  We could technically add the instruction to install the database in our Dockerfile, but that would not realistically mimic the environment our app would be deployed in.  &lt;/p&gt;

&lt;p&gt;It's not guaranteed that our Node app and our database would be hosted on the same server.  In fact it's probably not even likely.  Not only that, we don't want to have to boot up our web server to make edits to our database, and vice-versa.  Is there a way that we can still use Docker, but create a separation between multiple services that rely on each other?&lt;/p&gt;

&lt;p&gt;Yes we can.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Docker-Compose?
&lt;/h2&gt;

&lt;p&gt;Best described in &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;their own words&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The process is to define the instructions for each of your services with Dockerfiles, and then use Docker Compose to run all those containers together and facilitate network communications between them.&lt;/p&gt;

&lt;p&gt;In this tutorial we are going to connect our Node app to a PostgreSQL database.  Before we can connect them of course we need to establish the database container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Database
&lt;/h2&gt;

&lt;p&gt;Similar to Node, Docker Hub has a super simple easy to use image for &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;.  Of course theres also images for MySQL, Mongo, Redis, etc, etc.  There's no reason you couldn't substitute your favourite out if you want (though if you're still new to Docker I'd suggest you stick with the tutorial for now).&lt;/p&gt;

&lt;p&gt;We search Docker Hub for the official &lt;a href="https://hub.docker.com/_/postgres" rel="noopener noreferrer"&gt;postgres&lt;/a&gt; image.  We don't need anything beyond the bare minimum so once again we'll choose the version running on Alpine.  Image &lt;code&gt;postgres:14.1-alpine&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unlike our Node image, we don't need to copy any files or run any installation scripts, so we don't actually need a Dockerfile for our PostgreSQL installation.  There are some configurations that we do need (like password and ports for example) but we can manage those with our upcoming &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;So aside from deciding which image you are going to use, there is really nothing else we need to do before we create our config file.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting the App to the Database
&lt;/h2&gt;

&lt;p&gt;Before we create the Docker Compose configure file to link the database container, we need to update our app to actually use it.  &lt;/p&gt;

&lt;p&gt;Our goal here is going to be to create a database with some very simple data (like a list of employees), see it with some sample data, and then query that data with our Node app.  &lt;/p&gt;

&lt;p&gt;We'll also create a simple frontend to display that data.&lt;/p&gt;

&lt;p&gt;First we need to install the PostgreSQL NPM package:&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;pg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we are going to create a &lt;code&gt;.sql&lt;/code&gt; file that will automatically seed out database with some sample data to read from.  In the root of the project create the following file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;database-seed.sql&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;employees_pkey&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Meadow Crystalfreak '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Head of Operations'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Buddy-Ray Perceptor'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'DevRel'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Prince Flitterbell'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Marketing Guru'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note I got those ridiculous names from the &lt;a href="https://www.behindthename.com/random/" rel="noopener noreferrer"&gt;random name generator&lt;/a&gt; on the "whimsical" setting)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next we update our Node server to query these values.  In addition to doing that, we are going to use &lt;code&gt;express.static&lt;/code&gt; to serve up an entire directory rather than just sending HTML as sa string.  This will allow us to serve an HTML file along with some CSS and Javascript as well, to create a full-fledged frontend.  &lt;/p&gt;

&lt;p&gt;Comments are added to explain all the new pieces:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;server.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import the postgres client&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pg&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&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="nf"&gt;express&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Connect to our postgres database&lt;/span&gt;
&lt;span class="c1"&gt;// These values like `root` and `postgres` will be&lt;/span&gt;
&lt;span class="c1"&gt;// defined in our `docker-compose-yml` file&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="c1"&gt;// Serves a folder called `public` that we will create&lt;/span&gt;
&lt;span class="nx"&gt;app&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="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// When a GET request is made to /employees&lt;/span&gt;
&lt;span class="c1"&gt;// Our app will return an array with a list of all&lt;/span&gt;
&lt;span class="c1"&gt;// employees including name and title&lt;/span&gt;
&lt;span class="c1"&gt;// this data is defined in our `database-seed.sql` file&lt;/span&gt;
&lt;span class="nx"&gt;app&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;/employees&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT * FROM employees&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Query failed&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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="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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Our app must connect to the database before it starts, so&lt;/span&gt;
&lt;span class="c1"&gt;// we wrap this in an IIFE (Google it) so that we can wait&lt;/span&gt;
&lt;span class="c1"&gt;// asynchronously for the database connection to establish before listening&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;app&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;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myPromise&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;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="nf"&gt;setTimeout&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="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&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="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;oops&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;myPromise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&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;In the above code update you can see that we are serving up a directory called &lt;code&gt;public&lt;/code&gt; that we have not created yet.  That directory will contain an &lt;code&gt;index.html&lt;/code&gt; file to act as the nice looking frontend for our app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Frontend
&lt;/h2&gt;

&lt;p&gt;We'll begin by creating the &lt;code&gt;public&lt;/code&gt; directory that is being served from our Node app:&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;public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the following files:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;public/index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My Docker Template&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://res.cloudinary.com/dqse2txyi/image/upload/v1639943067/blogs/docker-node/profile-picture_eav2ff.png"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Avatar"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"240px"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;h4&amp;gt;&lt;/span&gt;Placeholder&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Placeholder&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;index.html&lt;/code&gt; file takes advantage of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template" rel="noopener noreferrer"&gt;HTML templates&lt;/a&gt; for the employee cards.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;public/styles.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;column-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.03&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&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;Above in &lt;code&gt;styles.css&lt;/code&gt; is some simple CSS to give a clean look to the employee card templates, and flex them out in a row across the page.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;public/script.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="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;/employees&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&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;response&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;employee&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="c1"&gt;// Select the &amp;lt;template&amp;gt; we created in index.html&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cardTemplate&lt;/span&gt; &lt;span class="o"&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;template&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Clone a copy of the template we can insert in the DOM as a real visible node&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cardTemplate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneNode&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="c1"&gt;// Update the content of the cloned template with the employee data we queried from the backend&lt;/span&gt;
      &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;employee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;employee&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="c1"&gt;// Append the card as a child with the employee data to the &amp;lt;body&amp;gt; element on our page&lt;/span&gt;
      &lt;span class="nb"&gt;document&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;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When our app is loaded it will load &lt;code&gt;script.js&lt;/code&gt; which will use the browser &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/fetch" rel="noopener noreferrer"&gt;fetch API&lt;/a&gt; to query the &lt;code&gt;/employees&lt;/code&gt; route on our Node server and get the employee information from out PostgreSQL database.&lt;/p&gt;

&lt;p&gt;Once it is returned it will iterate through each employee and clone the HTML template that we defined in &lt;code&gt;index.html&lt;/code&gt; to make a custom employee card with that employee's &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Phew!  Now that we have our app established and ready to read from the database, we are finally ready to connect our Node container and our PostgreSQL container together with Docker Compose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Docker Compose YML File
&lt;/h2&gt;

&lt;p&gt;For a brief intro to compose see &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;here&lt;/a&gt;,  and for more details than you can ever handle about the compose file spec see &lt;a href="https://github.com/compose-spec/compose-spec/blob/master/spec.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We're going to be creating a simple &lt;code&gt;docker-compose.yml&lt;/code&gt; file to link our Node app with our PostgreSQL database.  Let's jump right in and create the file in our project root directory.  I'll use lots of comments to explain everything:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# These are the configurations for our Node app&lt;/span&gt;
  &lt;span class="c1"&gt;# When Docker Compose starts this container it will automatically&lt;/span&gt;
  &lt;span class="c1"&gt;# use the Dockerfile in the directory to configure it&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Our app does not work without our database&lt;/span&gt;
      &lt;span class="c1"&gt;# so this ensures our database is loaded first&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Maps our current project directory `.` to&lt;/span&gt;
      &lt;span class="c1"&gt;# our working directory in the container&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./:/usr/src/app/&lt;/span&gt;

  &lt;span class="c1"&gt;# This is the configuration for our PostgreSQL database container&lt;/span&gt;
  &lt;span class="c1"&gt;# Note the `postgres` name is important, in out Node app when we refer&lt;/span&gt;
  &lt;span class="c1"&gt;# to  `host: "postgres"` that value is mapped on the network to the &lt;/span&gt;
  &lt;span class="c1"&gt;# address of this container.&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:14.1-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# You can set the value of environment variables&lt;/span&gt;
      &lt;span class="c1"&gt;# in your docker-compose.yml file&lt;/span&gt;
      &lt;span class="c1"&gt;# Our Node app will use these to connect&lt;/span&gt;
      &lt;span class="c1"&gt;# to the database&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=root&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=root&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=root&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Standard port for PostgreSQL databases&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# When the PostgreSQL container is started it will run any scripts&lt;/span&gt;
      &lt;span class="c1"&gt;# provided in the `docker-entrypoint-initdb.d` directory, this connects&lt;/span&gt;
      &lt;span class="c1"&gt;# our seed file to that directory so that it gets run&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./database-seed.sql:/docker-entrypoint-initdb.d/database-seed.sql&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So with that &lt;code&gt;docker-compose.yml&lt;/code&gt; file in place we are finally ready to run our new and highly improved application "suite" that includes a backend, frontend and database.&lt;/p&gt;

&lt;p&gt;From the root directory of the project, all your have to do is type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note the &lt;code&gt;--build&lt;/code&gt; flag is used to force Docker to rebuild the images when you run &lt;code&gt;docker-compose up&lt;/code&gt; to make sure you capture any new changes.  If you simply want to restart existing containers that haven't changed you can omit it)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once active you can finally test it out.  In our &lt;code&gt;docker-compose.yml&lt;/code&gt; config we are mapping post 8080 directly to 8080 so go to &lt;a href=""&gt;http://localhost:8080&lt;/a&gt; to see:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1640151166%2Fblogs%2Fdocker-node%2Fdatabase-employees_lzojcm.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1640151166%2Fblogs%2Fdocker-node%2Fdatabase-employees_lzojcm.png" alt="Docker Postgres Fullstack Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With a cute little hover transition and everything!  Congratulations!&lt;/p&gt;

&lt;p&gt;If you are using the Docker Desktop GUI application you'll have a lot of options to stop all the containers at once, or view each one individually.  If you are using the command line you can stop both containers with this simple command (run from the project root directory for context):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there you have it, a fullstack Node.js application with its own SQL database bundled along with it.  You can now deploy this literally anywhere that has Docker installed and you know that it will work because you have defined all the parameters of the exact environment it needs to function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a pgAdmin Panel (Bonus)
&lt;/h2&gt;

&lt;p&gt;Here's a quick little bonus for those of you who are using PostgreSQL.  Adding the pgAdmin panel container to this app setup is a breeze.  Simply update your &lt;code&gt;docker-compose.yml&lt;/code&gt; config to include the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
        &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Our app does not work without our database&lt;/span&gt;
            &lt;span class="c1"&gt;# so this ensures our database is loaded first&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Maps our current project directory `.` to&lt;/span&gt;
            &lt;span class="c1"&gt;# our working directory in the container&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./:/usr/src/app/&lt;/span&gt;

    &lt;span class="c1"&gt;# This is the configuration for our PostgreSQL database container&lt;/span&gt;
    &lt;span class="c1"&gt;# Note the `postgres` name is important, in out Node app when we refer&lt;/span&gt;
    &lt;span class="c1"&gt;# to  `host: "postgres"` that value is mapped on the network to the &lt;/span&gt;
    &lt;span class="c1"&gt;# address of this container.&lt;/span&gt;
    &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:14.1-alpine&lt;/span&gt;
        &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# You can set the value of environment variables&lt;/span&gt;
            &lt;span class="c1"&gt;# in your docker-compose.yml file&lt;/span&gt;
            &lt;span class="c1"&gt;# Our Node app will use these to connect&lt;/span&gt;
            &lt;span class="c1"&gt;# to the database&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=root&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=root&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=root&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Standard port for PostgreSQL databases&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# When the PostgresSQL container is started it will run any scripts&lt;/span&gt;
            &lt;span class="c1"&gt;# provided in the `docker-entrypoint-initdb.d` directory, this connects&lt;/span&gt;
            &lt;span class="c1"&gt;# our seed file to that directory so that it gets run&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./database-seed.sql:/docker-entrypoint-initdb.d/database-seed.sql&lt;/span&gt;

    &lt;span class="na"&gt;pgadmin-compose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dpage/pgadmin4&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;PGADMIN_DEFAULT_EMAIL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;placeholder@example.com"&lt;/span&gt;
            &lt;span class="na"&gt;PGADMIN_DEFAULT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fakepassword123!"&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;16543:80"&lt;/span&gt;
        &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the pgAdmin panel configuration added at the bottom.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;docker-compose up --build&lt;/code&gt; now and go to:&lt;/p&gt;

&lt;p&gt;&lt;a href=""&gt;http://localhost:16543/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll be greeted with the pgAdmin panel.  Enter the &lt;code&gt;PGADMIN_DEFAULT_EMAIL&lt;/code&gt; and &lt;code&gt;PGADMIN_DEFAULT_PASSWORD&lt;/code&gt; credentials from the &lt;code&gt;docker-compose.yml&lt;/code&gt; file to access it.&lt;/p&gt;

&lt;p&gt;Once inside click &lt;code&gt;Add New Server&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;General -&amp;gt; Name&lt;/code&gt; pick a name.  Can be whatever you want.&lt;/p&gt;

&lt;p&gt;On the &lt;code&gt;Connection&lt;/code&gt; tab values must match the &lt;code&gt;docker-compose.yml&lt;/code&gt; file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Host: &lt;code&gt;postgres&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Username: &lt;code&gt;root&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Password: &lt;code&gt;root&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you can navigate from the left bar:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Servers -&amp;gt; whatever-you-want -&amp;gt; Databases -&amp;gt; root -&amp;gt; Schemas -&amp;gt; public -&amp;gt; Tables -&amp;gt; employees&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Right click &lt;code&gt;employees&lt;/code&gt; an Query Tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see your data.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1640152679%2Fblogs%2Fdocker-node%2Fpg-admin_ozybu2.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1640152679%2Fblogs%2Fdocker-node%2Fpg-admin_ozybu2.png" alt="pgAdmin Employee Data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Docker Commands
&lt;/h2&gt;

&lt;p&gt;List all containers, images, volumes or networks, for example &lt;code&gt;docker image ls&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;docker &lt;span class="o"&gt;{&lt;/span&gt;container&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;image&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;volume&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;network&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove a container, image, volume or network where ID is the id of the container/image/volume or network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="o"&gt;{&lt;/span&gt;container&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;image&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;volume&lt;span class="o"&gt;}&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;network&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;rm &lt;/span&gt;ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start a container in the background (as a daemon):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; IMAGE_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;View logs of a container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker container logs CONTAINER_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;View information about a container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker container inspect CONTAINER_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a shell inside an active container so you can run terminal commands inside of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; CONTAINER_ID /bin/sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop a container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker container stop CONTAINER_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove all dangling/unused Docker data (cached layers, volumes no longer used, etc):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker system prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use the above command with a specific type, like &lt;code&gt;docker container prune&lt;/code&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;I hope you learned a lot about why Docker is a fantastic tool in your toolbelt and how you can use it to reduce the amount of friction related to setting up development environments.  The days of fighting with WAMP and MAMP and XAMPP are thankfully long behind us (no slight against those apps, I know they're fantastic tools when configured properly).&lt;/p&gt;

&lt;p&gt;Remember that Docker can be used both to create a baseline standard development environment on the machines of many different developers.  But it's not just a development tool, Docker can be used in production as well to simplify the process fo scaling your app up with increased traffic by simply deploying more containers.  &lt;/p&gt;

&lt;p&gt;And there's plenty more to learn well beyond what's covered here, the &lt;a href="https://docs.docker.com/" rel="noopener noreferrer"&gt;Docker docs&lt;/a&gt; are the best place to start.  All the best in your Docker journey.  &lt;/p&gt;

&lt;p&gt;Please check some of my other learning tutorials.  Feel free to leave a comment or question and share with others if you find any of them helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/docker-for-javascript-developers-41me"&gt;Introduction to Docker for Javascript Developers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg"&gt;Learnings from React Conf 2021&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg"&gt;How to Create a Dark Mode Component in React&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34"&gt;How to Analyze and Improve your 'Create React App' Production Build &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe"&gt;How to Create and Publish a React Component Library&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-indexeddb-to-store-data-for-your-web-application-in-the-browser-1o90"&gt;How to use IndexedDB to Store Local Data for your Web App &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g"&gt;Running a Local Web Server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-linters-eslint-59pm"&gt;ESLint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-prettier-214j"&gt;Prettier&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp"&gt;Babel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7"&gt;React &amp;amp; JSX&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-1-2mn1"&gt;Webpack: The Basics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-2-49bj"&gt;Webpack: Loaders, Optimizations &amp;amp; Bundle Analysis&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;For more tutorials like this, follow me &lt;a href="https://twitter.com/eagleson_alex?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@eagleson_alex&lt;/a&gt; on Twitter&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>docker</category>
      <category>node</category>
    </item>
    <item>
      <title>How to Create a React Typescript Monorepo with Git Submodules</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Fri, 17 Dec 2021 13:12:16 +0000</pubDate>
      <link>https://dev.to/alexeagleson/how-to-create-a-node-and-react-monorepo-with-git-submodules-2g83</link>
      <guid>https://dev.to/alexeagleson/how-to-create-a-node-and-react-monorepo-with-git-submodules-2g83</guid>
      <description>&lt;p&gt;All code from this tutorial as a complete package is available in &lt;a href="https://github.com/alexeagleson/monorepo-example" rel="noopener noreferrer"&gt;this repository&lt;/a&gt; and a video version of this tutorial is available below:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/McEc5yX6kf4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Do you work with large or semi-large codebases that are starting to get out of control?  Do you have to deal with multiple different projects that interact with each other and have difficulty keeping versions aligned?  &lt;/p&gt;

&lt;p&gt;If you said yes to either of those things (or even if you're just anticipating encountering them in the future) then this tutorial is for you.  &lt;/p&gt;

&lt;p&gt;The purpose of this tutorial is to learn about some of the different ways that you can structure a large project which is composed primarily of smaller projects and modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monorepos
&lt;/h3&gt;

&lt;p&gt;One method of grouping code from multiple projects into one is called a &lt;a href="https://en.wikipedia.org/wiki/Monorepo" rel="noopener noreferrer"&gt;monorepo&lt;/a&gt;.  A &lt;em&gt;monorepo&lt;/em&gt; is simply the practice of placing multiple different projects that are related in some way into the same repository.&lt;/p&gt;

&lt;p&gt;The biggest benefit is that you do not need to worry about version mismatch issues between the different pieces of your project.  If you update an API route in the server of your monorepo, that commit will be associated with the version of the front end that consumes it.  With two different repositories you could find yourself in a situation where your v1.2 front-end is asking for data from your v1.1 backend that somebody forgot to push the latest update for.&lt;/p&gt;

&lt;p&gt;Another big benefit is the ability to import and share code and modules between projects.  Sharing types between the back-end and front-end is a common use case.  Your can define the shape of the data on your server and have the front-end consume it in a typesafe way.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Git Submodules
&lt;/h3&gt;

&lt;p&gt;In addition to monorepos, we also have the concept of &lt;a href="https://git-scm.com/book/en/v2/Git-Tools-Submodules" rel="noopener noreferrer"&gt;submodules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's say that we want to add a feature to our app that we have in another separate project.  We don't want to move the entire project into our monorepo because it remains useful as its own independent project.  Other developers will continue  to work on it outside of our monorepo project.&lt;/p&gt;

&lt;p&gt;We would like a way to include that project inside our monorepo, but not create a separate copy.  Simply have the ability to pull the most recent changes from the original repository, or even make our own contributions to it from inside our monorepo.  Git submodules allows you to do exactly that.&lt;/p&gt;

&lt;p&gt;This tutorial will teach you how to create your own project that implements both of these features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Prerequisites and Setup&lt;/li&gt;
&lt;li&gt;Initializing the Project&lt;/li&gt;
&lt;li&gt;Create the React App&lt;/li&gt;
&lt;li&gt;Create the Monorepo&lt;/li&gt;
&lt;li&gt;Create Your Repository&lt;/li&gt;
&lt;li&gt;Sharing Code and Adding Dependencies&lt;/li&gt;
&lt;li&gt;Create a Shared Package&lt;/li&gt;
&lt;li&gt;Add a Git Submodule&lt;/li&gt;
&lt;li&gt;Namespacing&lt;/li&gt;
&lt;li&gt;Wrapping Up&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Prerequisites and Setup
&lt;/h2&gt;

&lt;p&gt;This tutorial assumes you have a basic familiarity with the following.  Beginner level experience is fine for most as the code can be simply copy/pasted.  For git you should know how to clone, pull, commit and push.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Typescript&lt;/li&gt;
&lt;li&gt;NPM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial requires yarn v1 installed (we use v1.22).  &lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing the Project
&lt;/h2&gt;

&lt;p&gt;To start, we need a &lt;code&gt;packages&lt;/code&gt; directory to hold the different projects in our monorepo.  Your structure should begin looking like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
└── packages
    └── simple-express-app
          └── server.ts

From within the `packages/simple-express-app` directory, run:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn init

yarn add express

yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; typescript @types/express

npx tsc &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final command will create a &lt;code&gt;tsconfig.json&lt;/code&gt; file.  Add the following to it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-express-server/tsconfig.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist"&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;Now create your server file if you haven't yet:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-express-server/server.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&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;express&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="nf"&gt;express&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&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;/data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&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;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point your directory structure should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
└── packages
    └── simple-express-app
          ├── server.ts
          ├── yarn.lock
          ├── package.json
          └── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll create a simple script in &lt;code&gt;package.json&lt;/code&gt; called &lt;code&gt;start&lt;/code&gt; that we can run with &lt;code&gt;yarn&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-express-server/package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"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;"simple-express-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"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;"tsc &amp;amp;&amp;amp; node dist/server.js"&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;"devDependencies"&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;"@types/express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.17.13"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.5.4"&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;"dependencies"&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;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.17.1"&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;Open your browser to &lt;a href="http://localhost:3001/" rel="noopener noreferrer"&gt;&lt;/a&gt; and you will see your data successfully queried:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Create the React App
&lt;/h2&gt;

&lt;p&gt;Next we move onto our React app.  Navigate to the &lt;code&gt;packages&lt;/code&gt; directory and run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create react-app simple-react-app &lt;span class="nt"&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we do anything else we want to confirm that we can communicate with our server and get the JSON data that we are serving up.&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;App.tsx&lt;/code&gt; file in the &lt;code&gt;src&lt;/code&gt; directory of the project generated by &lt;code&gt;create-react-app&lt;/code&gt;.  We are going to add a simple button that uses the browser &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" rel="noopener noreferrer"&gt;fetch API&lt;/a&gt; to grab the data from our server and log it to the console.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-react-app/src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;logo&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;./logo.svg&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-header"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-logo"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"logo"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Edit &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;src/App.tsx&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; and save to reload.
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-link"&lt;/span&gt;
          &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://reactjs.org"&lt;/span&gt;
          &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;
          &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Learn React
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* NEW */&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;button&lt;/span&gt;
          &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="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;http://localhost:3001/&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&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;response&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          GET SOME DATA
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we open the browser's development console (F12) and then click our button, we will see our server data fetched and logged in the browser:&lt;/p&gt;

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

&lt;p&gt;This is great!  We've accidentally created a template for a full stack React and Typescript app!  But that's not the reason we're here, so let's start pushing further into scenarios we might encounter in real projects that would lead us to consider options like a monorepo and git submodules.&lt;/p&gt;

&lt;p&gt;Before you continue take a moment to verify your project structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
└── packages
    ├── simple-express-server
    │   ├── server.ts
    │   ├── yarn.lock
    │   ├── package.json
    │   └── tsconfig.json
    └── simple-react-app
        └── [default setup]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the Monorepo
&lt;/h2&gt;

&lt;p&gt;To manage our monorepo we are going to use two tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://lerna.js.org/" rel="noopener noreferrer"&gt;Lerna&lt;/a&gt;: For running scripts across multiple projects and adding new dependencies.  Lerna is also built to manage publishing your packages (though we will not be doing that as part of this tutorial)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://yarnpkg.com/features/workspaces" rel="noopener noreferrer"&gt;Yarn workspaces&lt;/a&gt;: For hoisting all shared dependencies into a single &lt;code&gt;node_modules&lt;/code&gt; folder in the root directory.  Each project can still define its own dependencies, so that you don't confuse which dependencies are required for which (client vs. server) for example, but it will pool the installed packages in the root.  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For yarn we are using the still most commonly used yarn v1 &lt;em&gt;(current version as of this writing is v1.22).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Navigate to the root directory and run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn init

yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; lerna typescript

npx lerna init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit your Lerna configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"packages"&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="s2"&gt;"packages/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"npmClient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"useWorkspaces"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to specify that &lt;code&gt;yarn&lt;/code&gt; is our NPM client and that we are using workspaces.&lt;/p&gt;

&lt;p&gt;Next we need to define the location of those workspaces in the root &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&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 json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"monorepo-example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"private"&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;"workspaces"&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="s2"&gt;"packages/*"&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;"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;"lerna run --parallel start"&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;"devDependencies"&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;"lerna"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.0.0"&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;We have made three changes above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Set &lt;code&gt;private&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; which is necessary for workspaces to functions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Defined the location of the workspaces as &lt;code&gt;packages/*&lt;/code&gt; which matches any directory we place in &lt;code&gt;packages&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Added a script that uses Lerna to run.  This will allow us to use a single command to run the equivalent of &lt;code&gt;yarn start&lt;/code&gt; in both our Express server and React app simultaneously.  This way they are coupled together so that we don't accidentally forget to run one, knowing that currently they both rely on each other.  The &lt;code&gt;--parallel&lt;/code&gt; flag allows them to run at the same time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we are ready to install the dependencies in root:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note: At this point before you run the install command, I would recommend you synchronize your Typescript version between your &lt;code&gt;simple-express-server&lt;/code&gt; and the one that comes bundled with your &lt;code&gt;simple-react-app&lt;/code&gt;.  Make sure both versions are the same in each project's &lt;code&gt;package.json&lt;/code&gt; and both are listed in &lt;code&gt;devDependencies&lt;/code&gt;.  Most likely the React app version will be older, so that is the one that should be changed.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx lerna clean &lt;span class="nt"&gt;-y&lt;/span&gt;

yarn &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command will clean up the old &lt;code&gt;node_modules&lt;/code&gt; folders in each of your two packages.  This is the equivalent of simply deleting them yourself.  &lt;/p&gt;

&lt;p&gt;The second command will install all dependencies for both projects in a &lt;code&gt;node_modules&lt;/code&gt; folder in the root directory.&lt;/p&gt;

&lt;p&gt;Go ahead and check it out!  You'll see that &lt;code&gt;node_modules&lt;/code&gt; in the root is full of packages, while the &lt;code&gt;node_modules&lt;/code&gt; folders in &lt;code&gt;simple-express-server&lt;/code&gt; and &lt;code&gt;simple-react-app&lt;/code&gt; only have a couple (these are mostly symlinks to binaries that are necessary due to the way yarn/npm function).&lt;/p&gt;

&lt;p&gt;Before we go on we should create a &lt;code&gt;.gitignore&lt;/code&gt; file in the root to make sure we don't commit our auto-generated files:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.gitignore&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;node_modules/
dist/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(If you're using VS Code you'll see the folder names in the side bar go grey as soon as you sae the file, so you know it worked)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Verify your monorepo and workspaces are setup properly by running (from the root folder):&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You will see that both your Express app and React app start up at the same time!  Click the button to verify that your server data is available and logs to the console.  &lt;/p&gt;

&lt;p&gt;Lastly we need to initialize Typescript in the root of the project so that our different packages can import and export between one another.  Run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsc &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the root directory and it will create your &lt;code&gt;.tsconfig.json&lt;/code&gt;.  You can delete all the defaults values from this file (your individual projects will se their own configuration values.)  The only field you need to include is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&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;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./packages"&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;Our project now looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── packages
|   ├── simple-express-server
|   │   ├── server.ts
|   │   ├── yarn.lock
|   │   ├── package.json
|   │   └── tsconfig.json
|   └── simple-react-app
|       └── [default setup]
├── lerna.json
├── tsconfig.json
├── package.json
└── yarn.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Your Repository
&lt;/h2&gt;

&lt;p&gt;This is also a good time to commit your new project to your repository.  I'll be doing that now as well, you can see the &lt;a href="https://github.com/alexeagleson/monorepo-example" rel="noopener noreferrer"&gt;final version here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that in order to learn submodules effectively, we are going to be adding a submodule from a repository that &lt;em&gt;already exists&lt;/em&gt;, we don't want to use the one that &lt;code&gt;create-react-app&lt;/code&gt; generated automatically.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So for that reason I am going to delete the that repository by deleting the &lt;code&gt;.git&lt;/code&gt; directory inside &lt;code&gt;packages/simple-react-app&lt;/code&gt;.  This step is VERY IMPORTANT.  Make sure there is no &lt;code&gt;.git&lt;/code&gt; directory inside &lt;code&gt;simple-react-app&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now from the root directory you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-am&lt;/span&gt; &lt;span class="s1"&gt;'first commit'&lt;/span&gt;
git remote add origin YOUR_GIT_REPO_ADDRESS
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin YOUR_BRANCH_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sharing Code and Adding Dependencies
&lt;/h2&gt;

&lt;p&gt;So let's quickly take a look at some of the benefits we get from our monorepo.  &lt;/p&gt;

&lt;p&gt;Let's say that there's a utility library that we want to use in both our React app and on our Express server.  For simplicity let's choose &lt;a href="https://lodash.com/" rel="noopener noreferrer"&gt;lodash&lt;/a&gt; which many people are familiar with.&lt;/p&gt;

&lt;p&gt;Rather than adding it to each project individually, we can use &lt;code&gt;lerna&lt;/code&gt; to install it to both.  This will help us make sure that we keep the same version in sync and require us to only have one copy of it in the root directory.  &lt;/p&gt;

&lt;p&gt;From the root run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx lerna add lodash packages/simple-&lt;span class="k"&gt;*&lt;/span&gt;

npx lerna add @types/lodash packages/simple-&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install &lt;code&gt;lodash&lt;/code&gt; in any of the projects in the &lt;code&gt;packages&lt;/code&gt; directory that match the &lt;code&gt;simple-*&lt;/code&gt; pattern (which includes both of ours).  When using this command you can install the package to dev and peer dependencies by adding &lt;code&gt;--dev&lt;/code&gt; or &lt;code&gt;--peer&lt;/code&gt; at the end.  More info on this command &lt;a href="https://github.com/lerna/lerna/tree/main/commands/add#lernaadd" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you check the &lt;code&gt;package.json&lt;/code&gt; file in both your packages you'll see that &lt;code&gt;lodash&lt;/code&gt; has been added with the same version to both files, but the actual package itself has a single copy in the &lt;code&gt;node_modules&lt;/code&gt; folder of your root directory.  &lt;/p&gt;

&lt;p&gt;So we'll update our &lt;code&gt;server.ts&lt;/code&gt; file in our Express project to do a couple of new things.  We'll import the shared &lt;code&gt;lodash&lt;/code&gt; library and use one of its functions (&lt;code&gt;_.snakeCase()&lt;/code&gt;) and we'll define a type interface that defines the shape of the data we are sending and export it so that we can &lt;em&gt;also&lt;/em&gt; use that interface in our React app to typesafe server queries.  &lt;/p&gt;

&lt;p&gt;Update your &lt;code&gt;server.ts&lt;/code&gt; file to look like the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-express-server.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&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;express&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;_&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;lodash&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="nf"&gt;express&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;QueryPayload&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;app&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="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="nx"&gt;next&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="c1"&gt;// Allow any website to connect&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;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Origin&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="c1"&gt;// Continue to next middleware&lt;/span&gt;
  &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&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;/&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;_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;const&lt;/span&gt; &lt;span class="na"&gt;responseData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QueryPayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;snakeCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server data returned successfully&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;res&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="nx"&gt;responseData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&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;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Note I have changed the key on the object from &lt;code&gt;data&lt;/code&gt; to &lt;code&gt;payload&lt;/code&gt; for clarity)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next we will update our &lt;code&gt;App.tsx&lt;/code&gt; component in &lt;code&gt;simple-react-app&lt;/code&gt;.  We'll import &lt;code&gt;lodash&lt;/code&gt; just for no other reason to show that we can import the same package in both client and server.  We'll use it to apply &lt;code&gt;_.toUpper()&lt;/code&gt; to the "Learn React" text.  &lt;/p&gt;

&lt;p&gt;We will also import our &lt;code&gt;QueryPayload&lt;/code&gt; interface from our &lt;code&gt;simple-express-server&lt;/code&gt; project.  This is all possible through the magic of workspaces and Typescript.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-react-app/src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;logo&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;./logo.svg&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.css&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;_&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;lodash&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;QueryPayload&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;simple-express-server/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-header"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-logo"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"logo"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Edit &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;src/App.tsx&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; and save to reload.
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-link"&lt;/span&gt;
          &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://reactjs.org"&lt;/span&gt;
          &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;
          &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&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;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Learn React&lt;/span&gt;&lt;span class="dl"&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="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
          &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="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;http://localhost:3001/&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&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;response&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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;QueryPayload&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          GET SOME DATA
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I find this is one of the trickiest parts to get right (the importing between packages).  The key to this is the installation of Typescript in the root of the project, and &lt;code&gt;"baseUrl": "./packages"&lt;/code&gt; value in the the &lt;code&gt;tsconfig.json&lt;/code&gt; in the root directory.  &lt;/p&gt;

&lt;p&gt;If you continue to have difficulty &lt;a href="https://stackoverflow.com/a/61467483" rel="noopener noreferrer"&gt;this&lt;/a&gt; is one of the best explanations I have ever come across for sharing Typescript data between projects in a monorepo.&lt;/p&gt;

&lt;p&gt;Once everything is setup, press the button on your React application and you'll be greeted with:&lt;/p&gt;

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

&lt;p&gt;Notice the snake_case response that matches the correct shape we defined.  Fantastic!&lt;/p&gt;

&lt;p&gt;Now there is one issue with our setup -- currently we are importing the &lt;code&gt;QueryPayload&lt;/code&gt; directly from our server.  That is fairly harmless, but what if we &lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Shared Package
&lt;/h2&gt;

&lt;p&gt;Using the &lt;a href="https://github.com/lerna/lerna/tree/main/commands/create#readme" rel="noopener noreferrer"&gt;lerna create&lt;/a&gt; command we can quickly and easily create new projects within our monorepo.  Run the following commands from the root directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx lerna create simple-shared-data

npx lerna add typescript &lt;span class="nt"&gt;--dev&lt;/span&gt;

yarn &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a directory called &lt;code&gt;simple-shared-data&lt;/code&gt; in your &lt;code&gt;packages&lt;/code&gt;.  We've already added the same version of Typescript as a dev dependency.  &lt;/p&gt;

&lt;p&gt;You can remove the &lt;code&gt;lib&lt;/code&gt; directory that includes the default JS entrypoint as we will not be using it.  &lt;/p&gt;

&lt;p&gt;Create an &lt;code&gt;index.ts&lt;/code&gt; file inside of &lt;code&gt;packages/simple-shared-data&lt;/code&gt; where we will place any types or data that either our front-end, back-end or both can have access to.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-shared-data/index.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;QueryPayload&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then import from this file in both our server and React app:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-express-server/server.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;QueryPayload&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;simple-shared-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;packages/simple-react-app/src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;QueryPayload&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;simple-shared-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benefit of creating this shared project is that your front-end for example won't have a strict dependency on the existence of your server.  You could deploy as:&lt;/p&gt;

&lt;p&gt;Front-End&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;simple-react-ap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;simple-shared-data&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Back-End&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;simple-express-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;simple-shared-data&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have all these different projects setup, lets take a look at git submodules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a Git Submodule
&lt;/h2&gt;

&lt;p&gt;Recently I wrote a blog post on a very simple component for a React app that adds a dark mode, a &lt;code&gt;&amp;lt;DarkMode /&amp;gt;&lt;/code&gt; component.  The component is not part of a separate library we can install with an NPM command, it exists as part of a React application that has its own repository.&lt;/p&gt;

&lt;p&gt;Let's add it to our project, while still keeping it as its own separated repo that can be updated and managed independent of our monorepo.  &lt;/p&gt;

&lt;p&gt;From the &lt;code&gt;packages/simple-react-app/src&lt;/code&gt; directory we'll run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git submodule add git@github.com:alexeagleson/react-dark-mode.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will create the &lt;code&gt;react-dark-mode&lt;/code&gt; directory (the name of the git repository, you can add another argument after the above command to name the directory yourself).&lt;/p&gt;

&lt;p&gt;To import from the submodule it's as simple as... importing from the directory.  If we're going to add the &lt;code&gt;&amp;lt;DarkMode /&amp;gt;&lt;/code&gt; component it's as simple as adding:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-react-app/src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;DarkMode&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;./react-dark-mode/src/DarkMode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&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;DarkMode&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've omitted some of the repetitive stuff above.  Unfortunately the default &lt;code&gt;background-color&lt;/code&gt; styles in &lt;code&gt;App.css&lt;/code&gt; are going to override the &lt;code&gt;body&lt;/code&gt; styles, so we need to update &lt;code&gt;App.css&lt;/code&gt; for it to work:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-react-app/src/App.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="nc"&gt;.App-header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* background-color: #282c34; */&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="m"&gt;2vmin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c"&gt;/* color: white; */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.App-link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* color: #61dafb; */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Comment out those color values and you're good to go!&lt;/p&gt;

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

&lt;p&gt;Now you might be thinking -- couldn't I just have cloned that repo into that folder and done this?  What's the difference with submodules?&lt;/p&gt;

&lt;p&gt;Well now that we have this in place, let's look for the answer to exactly that.  Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the output you'll see &lt;code&gt;new file:   ../../../.gitmodules&lt;/code&gt;.  That's something new if you've never used submodules before.  It's a hidden file that has been added to the project root.  Let's take a look inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[submodule "packages/simple-react-app/src/react-dark-mode"]
    path = packages/simple-react-app/src/react-dark-mode
    url = git@github.com:alexeagleson/react-dark-mode.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It stores a mapping to the directories in our project that map to other repositories.  &lt;/p&gt;

&lt;p&gt;Now if you commit your changes in the root of the monorepo and push, you'll see on Github that rather than being a regular directory inside this project -- it's actually a link to the real repository:&lt;/p&gt;

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

&lt;p&gt;So you can continue to update and make changes to this monorepo without impacting that other repository.  Great!  &lt;/p&gt;

&lt;p&gt;But can you update the dark mode repository from inside this one?  Sure you can!  (As long as you have write permission).&lt;/p&gt;

&lt;p&gt;Let's make a trivial change to the dark mode repository from inside this one and see what happens.  Navigate to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-react-app/src/react-dark-mode/src/DarkMode.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"dark"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--font-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--link-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;peachpuff&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;I'm going to update the colour of the link when the app is in dark mode, from &lt;code&gt;lightblue&lt;/code&gt; to &lt;code&gt;peachpuff&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now obviously you won't be able to update my repository, but if you're following you can continue reading to see where this is going (or you can use your own repository of course).&lt;/p&gt;

&lt;p&gt;From this directory I make a commit and push.  When I check the repository there are no new commits to the &lt;code&gt;monorepo-example&lt;/code&gt; repository, but there IS a new commit to &lt;code&gt;react-dark-mode&lt;/code&gt;.  Even though we are still inside our monorepo project!&lt;/p&gt;

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

&lt;p&gt;When working with submodules it's important to keep them up to date.  Remember that other contributors could be making new commits to the submodules.  The regular &lt;code&gt;git pull&lt;/code&gt; and &lt;code&gt;git fetch&lt;/code&gt; to your main root monorepo aren't going to automatically pull new changes to submodules.  To do that you need to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git submodule update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the latest updates.  &lt;/p&gt;

&lt;p&gt;You also have new command you'll need to run when cloning a project or pulling when new submodules have been added.  When you use &lt;code&gt;git pull&lt;/code&gt; it will pull the information &lt;em&gt;about&lt;/em&gt; relevant submodules, but it won't actually pull the code from them into your repository.  You need to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git submodule init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To pull the code for submodules.&lt;/p&gt;

&lt;p&gt;Lastly, in case you prefer not to run separate commands, there is a way to pull submodule updates with your regular commands you're already using like clone and pull.  Simply add the &lt;code&gt;--recurse-submodules&lt;/code&gt; flag like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git pull --recurse-submodules

or

git clone --recurse-submodules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Namespacing
&lt;/h2&gt;

&lt;p&gt;Although I didn't use it in the tutorial, it is good practice to use namespacing for your packages.  This is commonly done by prefixing with the &lt;code&gt;@&lt;/code&gt; character.  Below I will quickly show how to update this tutorial to add a &lt;code&gt;@my-namespace&lt;/code&gt; namespace:&lt;/p&gt;

&lt;p&gt;Prefix the &lt;code&gt;name&lt;/code&gt; value in each of your three &lt;code&gt;package.json&lt;/code&gt; files with &lt;code&gt;@my-namespace&lt;/code&gt;.  For example &lt;code&gt;simple-express-server/package.json&lt;/code&gt; will now be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"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;"@my-namespace/simple-express-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do that for each of the three packages.&lt;/p&gt;

&lt;p&gt;Next you need to update your imports:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/simple-express-server/server.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;QueryPayload&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;@my-namespace/simple-shared-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;packages/simple-react-app/src/App.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;QueryPayload&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;@my-namespace/simple-shared-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally run &lt;code&gt;yarn install&lt;/code&gt; to update those packages inside your root &lt;code&gt;node_modules&lt;/code&gt; directory and you're good to go!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;I hope you learned something useful about monorepos and submodules.  There are tons of different ways to setup a new project, and there's no one-size-fits-all answer for every team.&lt;/p&gt;

&lt;p&gt;I'd encourage you to play around with small monorepos (even clone this example) and get get comfortable with the different commands.  &lt;/p&gt;

&lt;p&gt;Please check some of my other learning tutorials.  Feel free to leave a comment or question and share with others if you find any of them helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg"&gt;Learnings from React Conf 2021&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg"&gt;How to Create a Dark Mode Component in React&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34"&gt;How to Analyze and Improve your 'Create React App' Production Build &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe"&gt;How to Create and Publish a React Component Library&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-indexeddb-to-store-data-for-your-web-application-in-the-browser-1o90"&gt;How to use IndexedDB to Store Local Data for your Web App &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g"&gt;Running a Local Web Server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-linters-eslint-59pm"&gt;ESLint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-prettier-214j"&gt;Prettier&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp"&gt;Babel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7"&gt;React &amp;amp; JSX&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-1-2mn1"&gt;Webpack: The Basics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-2-49bj"&gt;Webpack: Loaders, Optimizations &amp;amp; Bundle Analysis&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;For more tutorials like this, follow me &lt;a href="https://twitter.com/eagleson_alex?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@eagleson_alex&lt;/a&gt; on Twitter&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>javascript</category>
      <category>git</category>
    </item>
    <item>
      <title>Learnings from React Conf 2021</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Thu, 09 Dec 2021 14:24:54 +0000</pubDate>
      <link>https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg</link>
      <guid>https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg</guid>
      <description>&lt;p&gt;I recently had the opportunity to join the digital &lt;a href="https://conf.reactjs.org/" rel="noopener noreferrer"&gt;React Conf 2021&lt;/a&gt; and listen to some talks from a really great list of &lt;a href="https://conf.reactjs.org/speakers" rel="noopener noreferrer"&gt;speakers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post aims to summarize (in many ways for myself) the big take-aways that I learned from the conference.  For example there were some great talks on design/UI that I found interesting, but since I am more involved with the coding side, those will be the areas that I focus on primarily.&lt;/p&gt;

&lt;p&gt;So without further preamble, here's an unordered list of some of the new topics I found most compelling:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Conference Video Link&lt;/li&gt;
&lt;li&gt;React 18 Release Candidate&lt;/li&gt;
&lt;li&gt;Updating to React 18&lt;/li&gt;
&lt;li&gt;Suspense and Server Components&lt;/li&gt;
&lt;li&gt;React Docs&lt;/li&gt;
&lt;li&gt;Unusual React Environments&lt;/li&gt;
&lt;li&gt;Cross Platform with React Native&lt;/li&gt;
&lt;li&gt;Developer Tooling&lt;/li&gt;
&lt;li&gt;The Future of Memoization&lt;/li&gt;
&lt;li&gt;Shopify's Hydrogen&lt;/li&gt;
&lt;li&gt;All the Rest&lt;/li&gt;
&lt;li&gt;Bonus Tips&lt;/li&gt;
&lt;li&gt;Wrapping Up&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conference Video Link
&lt;/h2&gt;

&lt;p&gt;The entire 5 hour conference is currently available on Youtube for anyone to watch for free.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note they have stated they will be releasing individual videos of each talk, so it is possible this video link will go down in the near future.  I will aim to update links to the individual talks if that occurs)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8dUpL8SCO1w"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  React 18 Release Candidate
&lt;/h2&gt;

&lt;p&gt;The official release candidate for &lt;a href="https://reactjs.org/blog/2021/06/08/the-plan-for-react-18.html" rel="noopener noreferrer"&gt;React 18&lt;/a&gt; was released to coincide with the start of the conference.  This version is considered to be the "expected version for the official release in early 2022" barring any major issues found in the next couple of months.&lt;/p&gt;

&lt;p&gt;So although you may not want to upgrade your critical production applications just yet, as of today React v18 is as close as its ever been to finalized.  You're definitely encouraged to use it from the get-go with any new projects you create.&lt;/p&gt;

&lt;p&gt;Of course the big topic of discussion in the conference were focused around the new features of React 18 itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating to React 18
&lt;/h2&gt;

&lt;p&gt;Run the following command in your existing React project:&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;react@beta react-dom@beta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that as of today you can also install the RC version rather than beta as 18 is now a release candidate.  Check the &lt;em&gt;versions&lt;/em&gt; on &lt;a href="https://www.npmjs.com/package/react" rel="noopener noreferrer"&gt;NPM&lt;/a&gt; to see what is available.&lt;/p&gt;

&lt;p&gt;Then all you need to do is change the app mount point (presumably in your index file) from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&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;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="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&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;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you're ready to begin working with React 18!&lt;/p&gt;

&lt;h2&gt;
  
  
  Suspense and Server Components
&lt;/h2&gt;

&lt;p&gt;Suspense is already available in React 17, you may have worked with code before that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;./MyComponent&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;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="nc"&gt;Loading&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;MyComponent&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However this use of code splitting with Suspense is happening on the client side, where development is driven now is implementing Suspense on the &lt;em&gt;server side&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;Currently SSR (server side rendering) is an "all or nothing approach".  If we have a page with a header, nav, content and comments that we are generating with SSR -- then the time it takes to serve that page will be equal to the slowest of its individual components.  If every other component takes 0.1s and comments takes 1s then you still need to wait for comments before the app can be sent to the client.&lt;/p&gt;

&lt;p&gt;This is no longer true with React server components.  It's now possible that despite being rendered on the server, you can wrap your &lt;code&gt;&amp;lt;Comments /&amp;gt;&lt;/code&gt; in a &lt;code&gt;&amp;lt;Suspense /&amp;gt;&lt;/code&gt; with a fallback loading spinner (or whatever you want) and the app will be sent with the fallback in place until it is ready.&lt;/p&gt;

&lt;p&gt;Once it is ready, the bundle containing the rendered comments will be sent to the client to replace the fallback component.&lt;/p&gt;

&lt;p&gt;As a bonus, the React is smart enough to watch for user interaction.  If one suspended component has been clicked while it's still loading, React will immediately stop what it is doing elsewhere and prioritize the loading of that component!  &lt;/p&gt;

&lt;p&gt;The key takeaway for server components is that they are &lt;em&gt;always rendered on the server&lt;/em&gt;, and never sent to be rendered on the client.  There are two critical take-aways from this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Server components will have no impact on your bundle size, since they always render on the server&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server components can have &lt;em&gt;direct access to your database&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you would like to learn more about server components, here's a great talk from Dan covering all the details:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/TQQPAU21ZUw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And if you would like to see Suspense in action, &lt;a href="https://twitter.com/dan_abramov" rel="noopener noreferrer"&gt;Dan Abramov&lt;/a&gt; of the React team has created a codesandbox example.  &lt;/p&gt;

&lt;p&gt;Hit the refresh button to see the effect.  You'll want to open the full link in another tab to see the example of the code and how it's composed.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/bztrp"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  React Docs
&lt;/h2&gt;

&lt;p&gt;The React documentation has finally been modernized with hooks-first content.  &lt;/p&gt;

&lt;p&gt;They've already been released &lt;a href="https://beta.reactjs.org/" rel="noopener noreferrer"&gt;in beta&lt;/a&gt; and are planning to be released officially to replace the current documentation when React 18 ships.  &lt;/p&gt;

&lt;p&gt;Discussion of the &lt;a href="https://youtu.be/8dUpL8SCO1w?t=8110" rel="noopener noreferrer"&gt;new React docs starts around 2:15&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unusual React Environments
&lt;/h2&gt;

&lt;p&gt;I really enjoyed &lt;a href="https://twitter.com/sarah11918" rel="noopener noreferrer"&gt;Sarah Rainsberger's&lt;/a&gt; talk which focused on "unusual" development environments for React.  &lt;/p&gt;

&lt;p&gt;My wife has been working with React this year for the first time and really connected with this talk, particularly the idea that someone would be able to learn React and its concept without necessarily having to go through a prerequisite stage of learning command line tools, NPM, etc. &lt;/p&gt;

&lt;p&gt;Thanks to online coding environments like &lt;a href="https://codesandbox.io/" rel="noopener noreferrer"&gt;codesandbox&lt;/a&gt;, &lt;a href="https://glitch.com/" rel="noopener noreferrer"&gt;glitch&lt;/a&gt; and &lt;a href="https://replit.com/" rel="noopener noreferrer"&gt;repl.it&lt;/a&gt; for example, you can begin writing real programs in React in a few seconds without installing any dependencies, and that's really powerful.&lt;/p&gt;

&lt;p&gt;One of my favourite trends in conferences I've seen is the push to include speakers who are relatively new to the technology, talking about their experiences and aimed at new developers in similar positions.  It helps a lot to break down the walls that people often hit when they are overwhelmed with the amount of new tools and concepts they need to learn when getting started.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://youtu.be/8dUpL8SCO1w?t=9287" rel="noopener noreferrer"&gt;talk begins around 2:34&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross Platform with React Native
&lt;/h2&gt;

&lt;p&gt;The React team seems to be really pushing for parity of developer experience between all kinds of platforms.  &lt;/p&gt;

&lt;p&gt;There was a lot of talk about what React Native is being used for these days and how optimizations being applied for one platform (Android for example) end up being applied to other platforms (iOS) in ways that they were not expecting.&lt;/p&gt;

&lt;p&gt;They discuss how React Native is being used to develop native experiences on not only mobile platforms, but OS's like Windows (parts of the Microsoft Office suite) and Xbox (the dashbaord for the new Xbox Series X) as well.&lt;/p&gt;

&lt;p&gt;Here's an image that really demonstrates what they are trying to achieve:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1639054384%2Fblogs%2Freact-conf%2FFGGzN2lUcAIFOMN_fdoroc.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1639054384%2Fblogs%2Freact-conf%2FFGGzN2lUcAIFOMN_fdoroc.jpg" alt="React Native"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to watch it yourself, &lt;a href="https://youtu.be/8dUpL8SCO1w?t=12884" rel="noopener noreferrer"&gt;this talk starts around 3:34&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Tooling
&lt;/h2&gt;

&lt;p&gt;There was a lot of focus on new and coming updates to developer tooling for React with a talk from &lt;a href="https://twitter.com/brian_d_vaughn" rel="noopener noreferrer"&gt;Brian Vaughn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;He summarized the big focuses the tooling will be seeing in the coming months:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrating the profiler and timeline to work together&lt;/li&gt;
&lt;li&gt;React Native support&lt;/li&gt;
&lt;li&gt;CPU and memory profiling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This talk &lt;a href="https://youtu.be/8dUpL8SCO1w?t=6083" rel="noopener noreferrer"&gt;starts around 1:41&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of Memoization
&lt;/h2&gt;

&lt;p&gt;One of the most interesting talks (that at times, went completely over my head) was from &lt;a href="https://twitter.com/Huxpro" rel="noopener noreferrer"&gt;Xuan Huang&lt;/a&gt; about the future of &lt;a href="https://en.wikipedia.org/wiki/Memoization" rel="noopener noreferrer"&gt;memoization&lt;/a&gt; in React.&lt;/p&gt;

&lt;p&gt;In the context of React, memoization is used primarily to indicate to React which components may or may not need to re-render depending on some kind of state.  Typically for a component, you can explicitly state that if the props do not change you do not need to re-render the component.&lt;/p&gt;

&lt;p&gt;More info on &lt;a href="https://reactjs.org/docs/react-api.html#reactmemo" rel="noopener noreferrer"&gt;React.memo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the &lt;a href="https://reactjs.org/docs/hooks-reference.html#usememo" rel="noopener noreferrer"&gt;useMemo&lt;/a&gt; hook we can create a memoized value that will not be recalculated if values in the dependency array do not change.  Setting up this kind of scenario is notoriously cumbersome sometimes, requiring the use of a lot of extra code and potentially the &lt;code&gt;useEffect&lt;/code&gt; hook to achieve your goal.  It also has the unfortunate side effect of making the flow of your code less linear (less likely to follow logically from top to bottom).&lt;/p&gt;

&lt;p&gt;Xuan's talk demonstrated this concept by showing an example in real time, then did a 180 and started writing a "theoretical example" of how it "could" look.  To be hones the new example looked a lot more complicated than the original...&lt;/p&gt;

&lt;p&gt;But he brought it all together by explaining that all the code he was writing -- if everything goes well (this idea is still in development) -- could be handled for you automatically.  A tool that detects areas where memoization would help optimize your components and be applied automatically.  Crazy stuff.&lt;/p&gt;

&lt;p&gt;Check it out yourself:  &lt;a href="https://youtu.be/8dUpL8SCO1w?t=6856" rel="noopener noreferrer"&gt;the talk begins at 1:54&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shopify's Hydrogen
&lt;/h2&gt;

&lt;p&gt;Shopify is part of the React Server Component working group and has bet heavily on the power of server components for their new React framework called &lt;a href="https://hydrogen.shopify.dev/" rel="noopener noreferrer"&gt;Hydrogen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hydrogen is a brand new React-based framework designed to unify the combination of server components, smart caching, and Shopify's API.  &lt;/p&gt;

&lt;p&gt;Shiopify maintains their own documentation on Hydrogen's support for &lt;a href="https://shopify.dev/custom-storefronts/hydrogen/framework/react-server-components" rel="noopener noreferrer"&gt;React server components&lt;/a&gt; which they claim to maintain their own stable abstraction layer over server components so you can use them with confidence, despite their current state.  &lt;/p&gt;

&lt;h2&gt;
  
  
  All the Rest
&lt;/h2&gt;

&lt;p&gt;There were still more talks!  Some I missed simply due to time constraints, or lunch or kids or whatnot; others were outside the scope of the work I normally do (though I'm always interested in learning anyway even if it's not directly applicable.)&lt;/p&gt;

&lt;p&gt;Either way I'd encourage you to check out some of the other talks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/8dUpL8SCO1w?t=9933" rel="noopener noreferrer"&gt;React for Designers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/8dUpL8SCO1w?t=16482" rel="noopener noreferrer"&gt;Accessibility in React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/8dUpL8SCO1w?t=15315" rel="noopener noreferrer"&gt;Using External Stores&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/8dUpL8SCO1w?t=11716" rel="noopener noreferrer"&gt;Relay&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/8dUpL8SCO1w?t=17003" rel="noopener noreferrer"&gt;Japanese Forms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/8dUpL8SCO1w?t=5215" rel="noopener noreferrer"&gt;React Working Groups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/8dUpL8SCO1w?t=13816" rel="noopener noreferrer"&gt;Machine Learning and React Native&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bonus Tips
&lt;/h2&gt;

&lt;p&gt;Here's a couple simple and practical things I picked up that are easy to pick up and use today. &lt;/p&gt;

&lt;p&gt;Like most of the talks, these are new features of React 18.  Fortunately the upgrade path to React 18 is aimed to be very simple and completely backward compatible.&lt;/p&gt;

&lt;p&gt;See the update section at the start of this post for a simple example of how to make the update in a couple of lines.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Batching
&lt;/h3&gt;

&lt;p&gt;Previous state updates would always be batched into a single render, even if they were called multiple times in a row.  There was a limitation for this however, if the function calling these state updates was asynchronous, the updates would not be batched.&lt;/p&gt;

&lt;p&gt;This is no longer true as of React 18.  The below code example in v17 would trigger two separate state updates, in v18 they will be batched together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetchFromApi&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&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="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deferred State
&lt;/h3&gt;

&lt;p&gt;One of my favourite new hooks I learned about that I thought was great was the &lt;code&gt;useDeferredValue&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;The first time they showed it in &lt;a href="https://twitter.com/shrutikapoor08" rel="noopener noreferrer"&gt;Shruti Kapoor's&lt;/a&gt; talk I thought it was fantastic.  Not surprisingly it kept coming up at least another 2-3 times in other talks as it seems to be extremely useful in a lot of scenarios.&lt;/p&gt;

&lt;p&gt;Basically what it does is allow you to specify a piece of state that you know will take longer to process than the other state of the component, and allow the component to render itself without waiting for the "big one".  When the big one is ready, it will render that one in.&lt;/p&gt;

&lt;p&gt;To give an example, large lists usually meet this criteria.  If you have a filter button that changes the state of a large list of items being rendered.&lt;/p&gt;

&lt;p&gt;The below example comes from the &lt;a href="https://reactjs.org/docs/concurrent-mode-reference.html#usedeferredvalue" rel="noopener noreferrer"&gt;React documentation&lt;/a&gt; on the feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&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;deferredText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDeferredValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; 

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Keep passing the current text to the input */&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;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&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="cm"&gt;/* But the list is allowed to "lag behind" when necessary */&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;MySlowList&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;deferredText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;I hope you learned something from this post, and I hope you get the chance to check out some of these talks.&lt;/p&gt;

&lt;p&gt;Please check some of my other learning tutorials.  Feel free to leave a comment or question and share with others if you find any of them helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg"&gt;Learnings from React Conf 2021&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg"&gt;How to Create a Dark Mode Component in React&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34"&gt;How to Analyze and Improve your 'Create React App' Production Build &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe"&gt;How to Create and Publish a React Component Library&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-indexeddb-to-store-data-for-your-web-application-in-the-browser-1o90"&gt;How to use IndexedDB to Store Local Data for your Web App &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g"&gt;Running a Local Web Server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-linters-eslint-59pm"&gt;ESLint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-prettier-214j"&gt;Prettier&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp"&gt;Babel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7"&gt;React &amp;amp; JSX&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-1-2mn1"&gt;Webpack: The Basics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-2-49bj"&gt;Webpack: Loaders, Optimizations &amp;amp; Bundle Analysis&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;For more tutorials like this, follow me &lt;a href="https://twitter.com/eagleson_alex?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@eagleson_alex&lt;/a&gt; on Twitter&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Create a Dark Mode Component in React</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Wed, 08 Dec 2021 14:21:35 +0000</pubDate>
      <link>https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg</link>
      <guid>https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg</guid>
      <description>&lt;p&gt;All code from this tutorial is available in &lt;a href="https://github.com/alexeagleson/react-dark-mode" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;, and a video version of this tutorial is available below.  &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/6s_MkSKKV0c"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Live Demo&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Initialize the Project&lt;/li&gt;
&lt;li&gt;Adding Styles&lt;/li&gt;
&lt;li&gt;Adding the Toggle Button&lt;/li&gt;
&lt;li&gt;Creating the DarkMode Component&lt;/li&gt;
&lt;li&gt;Adding Tests (Optional)&lt;/li&gt;
&lt;li&gt;Adding DarkMode to the App&lt;/li&gt;
&lt;li&gt;Setting Preferred Colour Scheme&lt;/li&gt;
&lt;li&gt;Wrapping Up&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Providing users with a dark mode for your web application has become an expectation, and there are many ways to accomplish it.  Typically this is most efficiently done by taking advantage of the power of &lt;em&gt;CSS variables&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;In this tutorial we are going to show how to bundle the entire dark mode feature into a single &lt;code&gt;&amp;lt;DarkMode /&amp;gt;&lt;/code&gt; component that you can take with you and place inside any application.  &lt;/p&gt;

&lt;p&gt;This component will not only persist your choice of settings through a page close or refresh, it will also respect the user's &lt;code&gt;prefers-color-scheme&lt;/code&gt; setting in their browser.  Pretty cool!&lt;/p&gt;

&lt;p&gt;So let's dive into it.&lt;/p&gt;

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

&lt;p&gt;Before we start we'll begin by taking a look a demo of the final product, so you know what to expect from this tutorial.  Once you have completed it, you will have your own &lt;code&gt;&amp;lt;DarkMode /&amp;gt;&lt;/code&gt; component that you can drop into any application to achieve this functionality.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/dry-meadow-64786"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;I'll presume that you have a &lt;em&gt;basic&lt;/em&gt; familiarity with React.  &lt;/p&gt;

&lt;p&gt;You do not need to be an expert.  In fact we don't have a single stateful variable, or any hooks or lifecycle methods.  The goal here (as it should always be) is to minimize complexity.  We don't need them for this feature.&lt;/p&gt;

&lt;p&gt;We will be using &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt; for this tutorial as it is an extremely easy way to quickly and easy establish a React application template that you can build on.&lt;/p&gt;

&lt;p&gt;If you choose not to use CRA you should still be able to follow along with this tutorial.  We will be writing pure CSS, but in order to copy the examples exactly you would need to have &lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;webpack&lt;/a&gt; setup with a CSS loader to support the &lt;code&gt;import&lt;/code&gt; syntax for CSS files.  &lt;/p&gt;

&lt;p&gt;If you are not using &lt;code&gt;webpack&lt;/code&gt; you can simply use a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element for your CSS files in your &lt;code&gt;index.html&lt;/code&gt; rather than importing them.&lt;/p&gt;

&lt;p&gt;We will also be using &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;Typescript&lt;/a&gt; as is the default for every web project I built these days.  If you are not super familiar with Typescript you should still be able to follow along, thee amount of explicit typing in these examples is minimal.  &lt;/p&gt;

&lt;p&gt;Lastly, I have included a section on adding tests for your component using &lt;em&gt;React Testing Library&lt;/em&gt;.  This section is optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialize the Project
&lt;/h2&gt;

&lt;p&gt;If you are using CRA then run the following command &lt;em&gt;(if you have your own existing project then disregard)&lt;/em&gt;&lt;/p&gt;

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

npx create-react-app dark-mode-example &lt;span class="nt"&gt;--template&lt;/span&gt; typescript


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Adding Styles
&lt;/h2&gt;

&lt;p&gt;When the application loads it will determine the dark/light setting in the following order of priority:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User's previous toggle setting&lt;/li&gt;
&lt;li&gt;User's browser preferences&lt;/li&gt;
&lt;li&gt;Light mode&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We'll begin by creating the CSS that handles dark mode.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/DarkMode.css&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;


&lt;span class="c"&gt;/* 1 */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--font-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--link-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;cornflowerblue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* 2 */&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"dark"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--font-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--link-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;lightblue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* 3 */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--background-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--link-color&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;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;:root&lt;/code&gt; selector matches the root element representing the DOM tree.  Anything you place here will be available anywhere in the application.  This is where will will create the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties" rel="noopener noreferrer"&gt;CSS variables&lt;/a&gt; that hold the colours for our light theme.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Here we set the colours for our &lt;code&gt;dark&lt;/code&gt; theme.  Using the attribute selector we target any element with a &lt;code&gt;data-theme="dark"&lt;/code&gt; attribute on it.  This is a custom attribute that we will be placing ourselves on the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We set the background colour and text color of our application.  This will always be the value of the &lt;code&gt;--background-color&lt;/code&gt; and &lt;code&gt;--font-color&lt;/code&gt; variables.  The value of those variables will change depending on when the &lt;code&gt;data-theme="dark"&lt;/code&gt; attribute is set due to the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Cascade" rel="noopener noreferrer"&gt;cascade&lt;/a&gt;.  The dark values are set after the root values so if the selector applies the initial (light) value of those variables will be overwritten with the dark values.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice I have also added a custom link colour here which changes based on the value of the theme.  You can add as many custom colours as you want here and have them all be controlled by your light/dark toggle.  Try adding some more yourself!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding the Toggle Button
&lt;/h2&gt;

&lt;p&gt;Next we will create a custom checkbox input to look like a toggle switch based on &lt;a href="https://www.w3schools.com/howto/howto_css_switch.asp" rel="noopener noreferrer"&gt;this example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I won't comment on how this CSS works as it's not in the scope of this tutorial and not relevant to dark/light mode.  The styles below are simply to override the look of the default HTML checkbox.&lt;/p&gt;

&lt;p&gt;Add them below the above code in &lt;code&gt;src/DarkMode.css&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/DarkMode.css&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="c"&gt;/* Custom Dark Mode Toggle Element */&lt;/span&gt;
&lt;span class="nc"&gt;.toggle-theme-wrapper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.toggle-theme-wrapper&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;28px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.toggle-theme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;34px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.toggle-theme&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.slider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.slider&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;26px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.4s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;26px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;.slider&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;26px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;.slider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;cornflowerblue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.slider.round&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;34px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.slider.round&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&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;
  
  
  Creating the DarkMode Component
&lt;/h2&gt;

&lt;p&gt;Now we will create our &lt;code&gt;DarkMode&lt;/code&gt; component.  &lt;/p&gt;

&lt;p&gt;To start we are just going to focus on the structure of the component itself, no events or functions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/DarkMode.tsx&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./DarkMode.css&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;DarkMode&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"toggle-theme-wrapper"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;☀️&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"toggle-theme"&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"slider round"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;🌒&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;DarkMode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element will be handling the state of our colour theme.  When it is &lt;code&gt;checked&lt;/code&gt; then dark mode is active, when it is not checked then light mode is active.  &lt;/p&gt;

&lt;p&gt;If you render this component you should have a nice looking custom toggle button without any functionality.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638936579%2Fblogs%2Fdark-mode-component%2Ftoggle-switch_dlbaux.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638936579%2Fblogs%2Fdark-mode-component%2Ftoggle-switch_dlbaux.png" alt="Toggle Switch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make our toggle switch work, we have to attack some Javascript functions to the &lt;code&gt;onChange&lt;/code&gt; event of the input that fires when the checkbox is toggled.  &lt;/p&gt;

&lt;p&gt;We also need to decide which mode we are going to show by default when the page or application is first loaded.  There is a lot to unpack here; there will be explanations for what is happening with the numbered comments below the example.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/DarkMode.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./DarkMode.css&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;ChangeEventHandler&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;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;// 1&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setDark&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="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&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;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&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;data-theme&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;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setLight&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="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&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;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&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;data-theme&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;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// 4&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storedTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&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;prefersDark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matchMedia&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(prefers-color-scheme: dark)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;matches&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;defaultDark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;storedTheme&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storedTheme&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;prefersDark&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;defaultDark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setDark&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 5&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggleTheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeEventHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setDark&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setLight&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DarkMode&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"toggle-theme-wrapper"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;☀️&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"toggle-theme"&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;

          &lt;span class="c1"&gt;// 6&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;toggleTheme&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;defaultChecked&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;defaultDark&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"slider round"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;🌒&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;DarkMode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We create functions called &lt;code&gt;setDark&lt;/code&gt; and &lt;code&gt;setLight&lt;/code&gt; which do exactly what the names describe.  We want these to be as simple as possible.  When we invoke them we expect the app to switch to either light or dark mode.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This is how we handle &lt;em&gt;persistance&lt;/em&gt;.  Using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage" rel="noopener noreferrer"&gt;localStorage&lt;/a&gt; will allow us to save a value and have it persist even after the user closes the app or reloads the page.  Every time light or dark mode is set, we save that value in the &lt;code&gt;theme&lt;/code&gt; property of &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This is where we set the &lt;code&gt;data-theme="dark"&lt;/code&gt; (or light) value on the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; DOM element.  This is what actually updates the colours in our app.  When that attribute is added then the &lt;code&gt;[data-theme="dark"]&lt;/code&gt; selector from our CSS becomes active and the dark colour variables are set (and vice versa).  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The section under comment 4 is where the "initial" state is established when the page is loaded before the actual toggle switch has been used.  &lt;code&gt;storedTheme&lt;/code&gt; gets the value from &lt;code&gt;localStorage&lt;/code&gt; if it exists.  &lt;code&gt;prefersDark&lt;/code&gt; checks a media query for the user's browser settings for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme" rel="noopener noreferrer"&gt;prefers-color-scheme&lt;/a&gt;.  Lastly &lt;code&gt;defaultDark&lt;/code&gt; is meant to check both of those and decide whether to default to dark mode based on the 3 rules of priority we established at the beginning of this tutorial.  If it evaluates to true, we set the app to dark mode before the component even renders. &lt;em&gt;(Note the reason we can do this is we are targeting the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; attribute which will already exist.)&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This is the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Events/Event_handlers" rel="noopener noreferrer"&gt;event handler&lt;/a&gt; function we have written to capture the &lt;em&gt;change&lt;/em&gt; event that occurs when a user clicks the checkbox.  If the box is &lt;code&gt;checked&lt;/code&gt; we enable dark mode, otherwise light mode.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We place the event handler we just created onto the &lt;code&gt;onChange&lt;/code&gt; attribute so it fires every time the checkbox changes.  We also use the &lt;code&gt;defaultDark&lt;/code&gt; boolean value we established to determine if the checkbox is enabled by default.  &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Adding Tests (Optional)
&lt;/h2&gt;

&lt;p&gt;Before we add this component to our app we can write a few tests to ensure it works as we expect it to.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Create React App&lt;/em&gt; comes prepackaged with &lt;a href="https://testing-library.com/docs/" rel="noopener noreferrer"&gt;React Testing Library&lt;/a&gt;.  It will automatically pick up any &lt;code&gt;.test.tsx&lt;/code&gt; files you create.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/DarkMode.test.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&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;@testing-library/react&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;DarkMode&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;./DarkMode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renders dark mode component&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="o"&gt;=&amp;gt;&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;DarkMode&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;checkbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toggles dark mode&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="o"&gt;=&amp;gt;&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;DarkMode&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;checkbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 4&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&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="c1"&gt;// 5&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data-theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&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;ol&gt;
&lt;li&gt;&lt;p&gt;A simple test to ensure the component renders.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The input has a role of &lt;code&gt;checkbox&lt;/code&gt; so we would expect to be able to find the element by that role.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A test to ensure that the component actually activates dark mode when the checkbox is toggled&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;em&gt;testing library's&lt;/em&gt; &lt;code&gt;fireEvent&lt;/code&gt; function we can simulate a click on our input.  We assert before clicking that it should not be checked, then after clicking it should be checked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This component by design does have &lt;a href="https://en.wikipedia.org/wiki/Side_effect_(computer_science)" rel="noopener noreferrer"&gt;side effects&lt;/a&gt; and that's what this final assertion is aiming to detect.  Although the component is only a small container for an input, it is designed to apply the &lt;code&gt;data-theme&lt;/code&gt; attribute to the root &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; element.  That element can be accessed directly with the Javascript variable &lt;code&gt;document.documentElement&lt;/code&gt;.  We check here that the &lt;code&gt;dark&lt;/code&gt; value is applied to the attribute after the element is clicked.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If using the default CRA setup (or you have custom configured it to do so) we can run our tests with:&lt;/p&gt;

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

npm run &lt;span class="nb"&gt;test&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And get our results:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638936763%2Fblogs%2Fdark-mode-component%2Ftest-pass_jlcppr.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638936763%2Fblogs%2Fdark-mode-component%2Ftest-pass_jlcppr.png" alt="Test Results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding DarkMode to the App
&lt;/h2&gt;

&lt;p&gt;Below I have simply imported and added &lt;code&gt;&amp;lt;DarkMode /&amp;gt;&lt;/code&gt; to the default App template created when you run &lt;em&gt;Create React App&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/App.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;logo&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;./logo.svg&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.css&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;DarkMode&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;./DarkMode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-header"&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;DarkMode&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-logo"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"logo"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Edit &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;src/App.tsx&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; and save to reload.
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;
          &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App-link"&lt;/span&gt;
          &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://reactjs.org"&lt;/span&gt;
          &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;
          &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Learn React
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Lastly, we need to update the default CSS included with the CRA setup, otherwise some of the color/background-color values will overwrite our theme variables.  &lt;/p&gt;

&lt;p&gt;The below example is the default version of &lt;code&gt;App.css&lt;/code&gt; with the color values commented out.  You can delete them entirely if you like.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/App.css&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="nc"&gt;.App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.App-logo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40vmin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;no-preference&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.App-logo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;App-logo-spin&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt; &lt;span class="m"&gt;20s&lt;/span&gt; &lt;span class="n"&gt;linear&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="nc"&gt;.App-header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* background-color: #282c34; */&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="err"&gt;+&lt;/span&gt; &lt;span class="m"&gt;2vmin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c"&gt;/* color: white; */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.App-link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* color: #61dafb; */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;App-logo-spin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;from&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;360deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;If you followed along with everything you'll be treated to a very function app with your own custom &lt;code&gt;&amp;lt;DarkMode /&amp;gt;&lt;/code&gt; component.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638940160%2Fblogs%2Fdark-mode-component%2Ffinal-exmaple_esa4q6.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638940160%2Fblogs%2Fdark-mode-component%2Ffinal-exmaple_esa4q6.png" alt="Light and Dark Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Preferred Colour Scheme
&lt;/h2&gt;

&lt;p&gt;We mentioned that this app supports the user's browser configuration for preferred colour scheme, but we didn't actually explain how you can set that value.&lt;/p&gt;

&lt;p&gt;Unfortunately browsers do not make it easy, but it can be achieved with the following steps in either Chrome or Firefox:&lt;/p&gt;

&lt;h3&gt;
  
  
  Firefox
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Type &lt;code&gt;about:config&lt;/code&gt; into your navigation bar&lt;/li&gt;
&lt;li&gt;If it doesn't already exist create a value called &lt;code&gt;ui.systemUsesDarkTheme&lt;/code&gt; and set it as a &lt;code&gt;Number&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Se the number as 1 for &lt;code&gt;dark&lt;/code&gt; or 0 for &lt;code&gt;light&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Chrome
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open developer tools (F12)&lt;/li&gt;
&lt;li&gt;Click the ellipsis &lt;code&gt;...&lt;/code&gt; icon at the upper right of the tools&lt;/li&gt;
&lt;li&gt;Click More Tools -&amp;gt; Rendering&lt;/li&gt;
&lt;li&gt;Under "Emulate CSS Media" select "prefers-color-scheme: dark"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chrome is a bit trickier so here is a screenshot showing where to find it:&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638940836%2Fblogs%2Fdark-mode-component%2Fchrome-example_svvvpo.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638940836%2Fblogs%2Fdark-mode-component%2Fchrome-example_svvvpo.png" alt="Prefers Color Scheme Chrome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this tutorial and learned something from it!  You might have picked up on the fact that although this was written from a &lt;em&gt;React&lt;/em&gt; perspective, nearly all the code we are working with would work just as well independently of React.  &lt;/p&gt;

&lt;p&gt;Try it yourself the next time you are working with vanilla HTML/CSS, or even a different framework!  You'll find that this code can be reused anywhere with very few modifications needed.  &lt;/p&gt;

&lt;p&gt;Please check some of my other learning tutorials.  Feel free to leave a comment or question and share with others if you find any of them helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg"&gt;Learnings from React Conf 2021&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg"&gt;How to Create a Dark Mode Component in React&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34"&gt;How to Analyze and Improve your 'Create React App' Production Build &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe"&gt;How to Create and Publish a React Component Library&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-indexeddb-to-store-data-for-your-web-application-in-the-browser-1o90"&gt;How to use IndexedDB to Store Local Data for your Web App &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g"&gt;Running a Local Web Server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-linters-eslint-59pm"&gt;ESLint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-prettier-214j"&gt;Prettier&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp"&gt;Babel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7"&gt;React &amp;amp; JSX&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-1-2mn1"&gt;Webpack: The Basics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-2-49bj"&gt;Webpack: Loaders, Optimizations &amp;amp; Bundle Analysis&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;For more tutorials like this, follow me &lt;a href="https://twitter.com/eagleson_alex?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@eagleson_alex&lt;/a&gt; on Twitter&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Analyze and Improve your 'Create React App' Production Build</title>
      <dc:creator>Alex Eagleson</dc:creator>
      <pubDate>Tue, 30 Nov 2021 14:04:24 +0000</pubDate>
      <link>https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34</link>
      <guid>https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34</guid>
      <description>&lt;p&gt;If you are interested in a video version of this tutorial, check out the link below. You can follow along with the code in this blog.  &lt;em&gt;(The video is entirely optional, every step and instruction is covered in the blog post.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/gJxgjyhbGHQ" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638284142%2Fblogs%2Fcreate-react-app-bundle-analyze%2FCRA_Youtube_Preview_xaqskf.png" alt="Create React App Analyze Tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial we're gonna take a step-by-step look at how to analyze and optimize your &lt;em&gt;Create React App&lt;/em&gt; project using a custom webpack configuration that is extremely easy to set up.&lt;/p&gt;

&lt;p&gt;We will be using examples that make small adjustments and try different ways of importing modules and splitting your code to see the direct impacts it has on your bundle sizes and performance.  &lt;/p&gt;

&lt;p&gt;The goal here is to help you get a better understanding of what &lt;em&gt;webpack&lt;/em&gt; is actually doing by seeing the exact changes that occur to a production build when you make small changes to your application.&lt;/p&gt;

&lt;p&gt;To begin, we'll create a brand new React app called &lt;code&gt;something-big-and-bloated&lt;/code&gt;&lt;/p&gt;

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

npx create-react-app something-big-and-bloated &lt;span class="nt"&gt;--template&lt;/span&gt; typescript


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

&lt;/div&gt;

&lt;p&gt;Next we'll install the dependencies we need to analyze the project.  &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; @craco/craco webpack-bundle-analyzer &lt;span class="nt"&gt;--save-dev&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;craco&lt;/strong&gt;: A tool to use a custom webpack configuration with &lt;em&gt;Create React App&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;webpack-bundle-analyzer&lt;/strong&gt;: A webpack plugin for analyzing bundle size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We need to create a configuration file for &lt;code&gt;craco&lt;/code&gt; in the root of our project to include our webpack plugin:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;craco.config.js&lt;/code&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;BundleAnalyzerPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webpack-bundle-analyzer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;BundleAnalyzerPlugin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BundleAnalyzerPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;analyzerMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;If we run the usual &lt;code&gt;npm run build&lt;/code&gt; script for a production build, it will use the standard &lt;code&gt;react-scripts&lt;/code&gt; method.  &lt;/p&gt;

&lt;p&gt;However if we run &lt;code&gt;craco build&lt;/code&gt; it will still run the same process, but inject in any webpack configuration you have included in your &lt;code&gt;craco.config.js&lt;/code&gt; file.  Pretty sweet.  &lt;/p&gt;

&lt;p&gt;Let's give it a try.  We'll create a new entry called &lt;strong&gt;analyze&lt;/strong&gt; in &lt;code&gt;package.json&lt;/code&gt; scripts:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="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;"react-scripts start"&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;"react-scripts 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;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts eject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"analyze"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"craco build"&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;Now run:&lt;/p&gt;

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

npm run analyze


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

&lt;/div&gt;

&lt;p&gt;Because we set the &lt;code&gt;analyzerMode&lt;/code&gt; to &lt;code&gt;"server"&lt;/code&gt; in our craco config, we will automatically get our browser open with the results served as a webpage &lt;em&gt;(you can use the &lt;code&gt;"json"&lt;/code&gt; option if you want the output without involving the browser)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638238643%2Fblogs%2Fcreate-react-app-bundle-analyze%2Finitial-size_ynrhea.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638238643%2Fblogs%2Fcreate-react-app-bundle-analyze%2Finitial-size_ynrhea.png" alt="Initial Size"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can hover over each module within the chunks or your can use the little arrow at the upper left which pops out a drawer.  You'll get three different values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;stat&lt;/strong&gt;: The size of the original source code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;parsed&lt;/strong&gt;: the size of the same code as compiled bundles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;gzipped&lt;/strong&gt;: the size of the compiled bundles after being gzipped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So for most deployments you can look at the gzipped value as how much network usage you will need, and the parsed size as how much code the browser is going to handle once unzipping is complete.  Be aware that this value can be just as problematic on users with less powerful CPUs as the gzip size can be for those on slow networks.  Both are important to consider.&lt;/p&gt;

&lt;p&gt;On &lt;code&gt;create-react-app&lt;/code&gt; v4.0.3 for this tutorial the values I get are 205kb / 135kb / 44kb for stat / parsed / gzipped respectively.  You can see right out of the box we get a bit of overhead (though for most users that's a small price to pay for convenience).  &lt;/p&gt;

&lt;p&gt;Now let's try adding some libraries and look at how this value changes.  We'll consider the way that we do our imports and see how we might be able to better control our bundle size by only importing what we need.  &lt;/p&gt;

&lt;p&gt;I'm gonna pick a fairly popular UI library called MUI (Material UI).  It's a good example of a large package that can significantly weigh down your app if not bundled properly.  It will make a good example for our tutorial.&lt;/p&gt;

&lt;p&gt;We will need the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://mui.com/" rel="noopener noreferrer"&gt;@mui/material&lt;/a&gt; - A React component library designed to give you some useful pre-styled components out of the box&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mui.com/components/material-icons/" rel="noopener noreferrer"&gt;@mui/icons-material&lt;/a&gt;: An icon package for MUI based on &lt;a href="https://fonts.google.com/icons" rel="noopener noreferrer"&gt;material icons&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/@emotion/react" rel="noopener noreferrer"&gt;@emotion/react&lt;/a&gt;: Required for &lt;code&gt;@mui/material&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/@emotion/styled" rel="noopener noreferrer"&gt;@emotion/styled&lt;/a&gt;: Required for &lt;code&gt;@mui/material&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&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; @mui/material @mui/icons-material @emotion/react @emotion/styled &lt;span class="nt"&gt;--save&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Before we even do anything let's run our analyzer again.  Remember we've added these libraries, but we aren't actually &lt;em&gt;using&lt;/em&gt; any of them yet.  Do you think our bundle size will increase?  Let's find out:&lt;/p&gt;

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

npm run analyze


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

&lt;/div&gt;

&lt;p&gt;205kb / 135kb / 44kb again.  Exact same result.  That's great!  That means that webpack is not including any libraries we don't actually use.  It's doing its job well.&lt;/p&gt;

&lt;p&gt;Now we'll import a component from MUI.  We'll grab a relatively complex one, something more than a button.  Let's use the &lt;a href="https://mui.com/components/speed-dial/" rel="noopener noreferrer"&gt;Speed Dial&lt;/a&gt;!  Create a new component file in &lt;code&gt;src&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/CustomSpeedDial.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;Box&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;@mui/material/Box&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;SpeedDial&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;@mui/material/SpeedDial&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;SpeedDialIcon&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;@mui/material/SpeedDialIcon&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;SpeedDialAction&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;@mui/material/SpeedDialAction&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;FileCopyIcon&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;@mui/icons-material/FileCopyOutlined&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;SaveIcon&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;@mui/icons-material/Save&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;PrintIcon&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;@mui/icons-material/Print&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;ShareIcon&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;@mui/icons-material/Share&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;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;icon&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;FileCopyIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Copy&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;icon&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;SaveIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Save&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;icon&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;PrintIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Print&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;icon&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;ShareIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Share&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CustomSpeedDial&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt; &lt;span class="na"&gt;sx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;translateZ(0px)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flexGrow&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="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;SpeedDial&lt;/span&gt;
        &lt;span class="na"&gt;ariaLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"SpeedDial basic example"&lt;/span&gt;
        &lt;span class="na"&gt;sx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;icon&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;SpeedDialIcon&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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;action&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;SpeedDialAction&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;tooltipTitle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  );
}


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

&lt;/div&gt;

&lt;p&gt;Replace the contents of your &lt;code&gt;App.tsx&lt;/code&gt; file with the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/App.tsx&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;CustomSpeedDial&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;./CustomSpeedDial&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CustomSpeedDial&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Run the development server to check it out:&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://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638242651%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fspeeddial_ugf7ue.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638242651%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fspeeddial_ugf7ue.png" alt="MUI Speed Dial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything looks good.  Let's see how much that impacted our build.  Run our analyze command again:&lt;/p&gt;

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

npm run analyze


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638242899%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fmui-size_dntazk.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638242899%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fmui-size_dntazk.png" alt="BUndle With Speed Dial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our bundle size is now up to 660kb / 270kb / 88kb.  That's a significant increase for one component!  Of course bear in mind that it's fairly complex, and as soon as you use one you need to include all the other dependencies that make MUI function.  &lt;/p&gt;

&lt;p&gt;I'd bet if you added a second component you wouldn't get such a big jump.  In fact we can try now.  Add the following to your SpeedDial component:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/CustomSpeedDial.tsx&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&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;Box&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;@mui/material/Box&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;SpeedDial&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;@mui/material/SpeedDial&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;SpeedDialIcon&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;@mui/material/SpeedDialIcon&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;SpeedDialAction&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;@mui/material/SpeedDialAction&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;FileCopyIcon&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;@mui/icons-material/FileCopyOutlined&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;SaveIcon&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;@mui/icons-material/Save&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;PrintIcon&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;@mui/icons-material/Print&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;ShareIcon&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;@mui/icons-material/Share&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// NEW&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Button&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;@mui/material/Button&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;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;icon&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;FileCopyIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Copy&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;icon&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;SaveIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Save&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;icon&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;PrintIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Print&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;icon&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;ShareIcon&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Share&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;CustomSpeedDial&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt; &lt;span class="na"&gt;sx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;translateZ(0px)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flexGrow&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="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="cm"&gt;/* NEW */&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;Button&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contained"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello world!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&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;SpeedDial&lt;/span&gt;
        &lt;span class="na"&gt;ariaLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"SpeedDial basic example"&lt;/span&gt;
        &lt;span class="na"&gt;sx&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;icon&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;SpeedDialIcon&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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;action&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;SpeedDialAction&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;tooltipTitle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;SpeedDial&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;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We've imported a button above and included it with our speed dial &lt;em&gt;(two new lines marked with "NEW" comments.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When we run &lt;code&gt;npm run analyze&lt;/code&gt; again we get.... almost the same!  677kb / 278kb / 89kb.  We can see that the button extremely little to the bundle size since most of the building blocks for it were already included with the Speed Dial.  &lt;/p&gt;

&lt;p&gt;But now let's compare when using the traditional commonJS import.  &lt;/p&gt;

&lt;p&gt;Add the following line to the very top of your &lt;code&gt;CustomSpeedDial&lt;/code&gt; component &lt;em&gt;(if ESLint complains about import order, place the line after all your imports statements)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/CustomSpeedDial.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;material&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mui/material&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;Analyze again:&lt;/p&gt;

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

npm run analyze


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638243852%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fmui-everything_vgh01j.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638243852%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fmui-everything_vgh01j.png" alt="MUI Everything Bundled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Holy moly!  1.97*&lt;em&gt;MB&lt;/em&gt;* / 697kb / 194kb.  &lt;/p&gt;

&lt;p&gt;What happened?  Looks like we're bundling the &lt;strong&gt;entire&lt;/strong&gt; MUI library.  Popper?  Tooltip.js?  We're not using any of those, but they're taking up a ton of space in our chunk.&lt;/p&gt;

&lt;p&gt;It turns out that when we are using ES6 modules webpack is very good at figuring out which pieces of code we are actually using based on what we import and export.  &lt;/p&gt;

&lt;p&gt;This process is called &lt;a href="https://webpack.js.org/guides/tree-shaking/" rel="noopener noreferrer"&gt;tree shaking&lt;/a&gt; and it requires you to use ES6 modules in order to work.  You can see that doing so can have a very dramatic effect on our final bundle.  &lt;/p&gt;

&lt;p&gt;Our current program is exactly the same functionally as our previous one, but thanks to a single commonJS import it's a whopping 3x the size.  Yikes!&lt;/p&gt;

&lt;p&gt;Here's what we're going to do though.  Instead of removing that &lt;code&gt;require&lt;/code&gt; in our &lt;code&gt;CustomSpeedDial&lt;/code&gt; we're going to leave it there, and introduce something called &lt;a href="https://create-react-app.dev/docs/code-splitting/" rel="noopener noreferrer"&gt;code spltting&lt;/a&gt; as another option available to you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code splitting&lt;/strong&gt; is effective when you have a certain component or page or general part of your application that isn't necessary required for every visitor.  It might be a datepicker that only appears when a user makes a booking, or it might be a "help" page that only a small percentage of users will need.&lt;/p&gt;

&lt;p&gt;We can use React's &lt;a href="https://reactjs.org/docs/code-splitting.html" rel="noopener noreferrer"&gt;lazy and suspense&lt;/a&gt; features to break these pieces into separate bundle chunks, and only load them when necessary.  &lt;/p&gt;

&lt;p&gt;Let's update &lt;code&gt;App.tsx&lt;/code&gt;.  There's a lot to unpack here, so we'll just show the code first and break it down:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/App.tsx&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CircularProgress&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;@mui/material/CircularProgress&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;Button&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;@mui/material/Button&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;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="nx"&gt;useState&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;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;// 1&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CustomSpeedDial&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="s2"&gt;./CustomSpeedDial&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;showSpeedDial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShowSpeedDial&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 4&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;showSpeedDial&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="c1"&gt;// 5&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="nc"&gt;CircularProgress&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;CustomSpeedDial&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// 3&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"contained"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nf"&gt;setShowSpeedDial&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Click to load speed dial
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The numbers are a little out of order, but that's intentional.  You'll see it follows the actual flow of the component.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We "lazy" import the &lt;code&gt;CustomSpeedDial&lt;/code&gt; module.  Remember that's the one that uses &lt;code&gt;require&lt;/code&gt; for the entire MUI package and comes in at 1-2MB.  By using the lazy import, what happens is that the import only occurs when our primary component here (CustomSpeedDial) actually tries to render it.  We'll see that it doesn't by default.
&lt;/li&gt;
&lt;li&gt;A boolean React state value to keep track of whether which component we want to render.  The default &lt;code&gt;false&lt;/code&gt; value means we will not be rendering &lt;code&gt;CustomSpeedDial&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Our default component is a basic &lt;code&gt;Button&lt;/code&gt; imported directly from MUI.  When this button is pressed it sets the value of &lt;code&gt;showSpeedDial&lt;/code&gt; to &lt;em&gt;true&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Once &lt;code&gt;showSpeedDial&lt;/code&gt; is &lt;em&gt;true&lt;/em&gt; we take this branch at the next render.  The reason we get a re-render is because we  updated a stateful React value (showSpeedDial).&lt;/li&gt;
&lt;li&gt;The purpose of the &lt;code&gt;Suspense&lt;/code&gt; component is to tells React what to render while waiting for the module to import.  Depending on the size it could take a second or more.  For our example we are using MUI's &lt;code&gt;CircularProgress&lt;/code&gt; to imply a loading state while the module is loading.  Once it loads it switches to render the children of the Suspense component.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now it's time to try it out!  We'll begin with an &lt;em&gt;analyze&lt;/em&gt;:&lt;/p&gt;

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

npm run analyze


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

&lt;/div&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638248309%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fmui-code-splitting_u7lju6.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638248309%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fmui-code-splitting_u7lju6.png" alt="MUI Code Splitting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gets really interesting.  Webpack has created new separate chunks.  You'll notice there are more &lt;code&gt;.js&lt;/code&gt; chunks when you toggle the drawer on the left.&lt;/p&gt;

&lt;p&gt;In fact this largest chunk on the left &lt;code&gt;3.5d1a4e88.chunk.js&lt;/code&gt; (1.52mb / 475kb / 122kb) isn't even used on the default load of our app.  Based on our learnings earlier, we can see that huge chunk is definitely our &lt;code&gt;CustomSpeedDial.tsx&lt;/code&gt; component that imports all of MUI with &lt;code&gt;require&lt;/code&gt; commonJS import.  &lt;/p&gt;

&lt;p&gt;On the right we have the much smaller bundle &lt;code&gt;2.c5828938.chunk.js&lt;/code&gt; that includes things like &lt;code&gt;Button&lt;/code&gt; and &lt;code&gt;ButtonBase&lt;/code&gt;.  This is the chunk that will load on every page load.  We can look at the size (451kb / 214kb / 69kb) and validate that in a moment.  &lt;/p&gt;

&lt;p&gt;Since our ultimate goal is to make sure our production app is running as efficiently as possible, we want to run our tests on the production version of the app.  Use the following command to build a production version of the app:&lt;/p&gt;

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

bpm run build


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

&lt;/div&gt;

&lt;p&gt;Next we'll need to serve that &lt;code&gt;build&lt;/code&gt; directory that was created.  If you have your own local serve you prefer to use, use it!  If not just add the &lt;a href="https://www.npmjs.com/package/serve" rel="noopener noreferrer"&gt;serve&lt;/a&gt; package:&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;serve &lt;span class="nt"&gt;--save-dev&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And then use it to serve the &lt;code&gt;build&lt;/code&gt; directory:&lt;/p&gt;

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

npx serve build


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

&lt;/div&gt;

&lt;p&gt;You can find the page at &lt;a href=""&gt;http://localhost:3000/&lt;/a&gt; &lt;em&gt;(or whatever port serve specifies on the command line)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Press F12 to open your browser's &lt;em&gt;Developer Tools&lt;/em&gt; and click the &lt;em&gt;Network&lt;/em&gt; tab.  This process should be roughly the same in both Chrome, Edge and Firefox.&lt;/p&gt;

&lt;p&gt;I am using Firefox so the screenshots should match your experience.  If you are using another browser the options will still be there, just potentially in a different location.&lt;/p&gt;

&lt;p&gt;Click the &lt;em&gt;Disable Cache&lt;/em&gt; checkbox so that we are loading the JS files on every refresh and not a cached version from the browser.  We want to be able to see the load times and sizes.&lt;/p&gt;

&lt;p&gt;Now hit the refresh button (F5).&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638249023%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fcode-split-first-load_d7rat4.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638249023%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fcode-split-first-load_d7rat4.png" alt="Code Splitting First Load"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we predicted, our total transfer is 82KB with 69KB of that being the highlighted smaller &lt;code&gt;c5828938&lt;/code&gt; chunk we identified &lt;em&gt;(remember this is a served production build, so we are working with GZIP sizes just like your real app would for real users)&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;There is no sign of the 122KB gzipped chunk.  Let's click the "load speed dial" button on our app.&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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638249424%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fcode-split-second-load_nt4mlo.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%2Fres.cloudinary.com%2Fdqse2txyi%2Fimage%2Fupload%2Fv1638249424%2Fblogs%2Fcreate-react-app-bundle-analyze%2Fcode-split-second-load_nt4mlo.png" alt="Code SPlitting Second Load"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's that 122KB chunk with our &lt;code&gt;CustomSpeedDial&lt;/code&gt; component inside of it.  &lt;/p&gt;

&lt;p&gt;How cool is it that it only loaded the code on demand?&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;I hope you can start brainstorming ways to reduce the bundle size of your app and potentially introduce code splitting to improve initial load times.  &lt;/p&gt;

&lt;p&gt;Also worth noting: these tips are not exclusive to &lt;em&gt;Create React App&lt;/em&gt;.  All we did was introduce a special tool called &lt;code&gt;craco&lt;/code&gt; to allow us to configure webpack.  Any application running webpack can potentially benefit from these tips!&lt;/p&gt;

&lt;p&gt;It would be irresponsible to me not to mention that &lt;em&gt;Create React App&lt;/em&gt; does recommend a similar tool that doesn't require &lt;code&gt;craco&lt;/code&gt; &lt;em&gt;(although personally I feel it's not as intuitive to read the data)&lt;/em&gt; it still gets the job done well.  Read about it &lt;a href="https://create-react-app.dev/docs/analyzing-the-bundle-size/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continue Learning
&lt;/h2&gt;

&lt;p&gt;Please check some of my other learning tutorials.  Feel free to leave a comment or question and share with others if you find any of them helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/learnings-from-react-conf-2021-17lg"&gt;Learnings from React Conf 2021&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-a-dark-mode-component-in-react-3ibg"&gt;How to Create a Dark Mode Component in React&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-analyze-and-improve-your-create-react-app-production-build-4f34"&gt;How to Analyze and Improve your 'Create React App' Production Build &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-create-and-publish-a-react-component-library-2oe"&gt;How to Create and Publish a React Component Library&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/how-to-use-indexeddb-to-store-data-for-your-web-application-in-the-browser-1o90"&gt;How to use IndexedDB to Store Local Data for your Web App &lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-running-a-local-web-server-4d8g"&gt;Running a Local Web Server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-linters-eslint-59pm"&gt;ESLint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-prettier-214j"&gt;Prettier&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/building-a-modern-web-stack-babel-3hfp"&gt;Babel&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-react-with-and-without-jsx-31c7"&gt;React &amp;amp; JSX&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-1-2mn1"&gt;Webpack: The Basics&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/alexeagleson/understanding-the-modern-web-stack-webpack-part-2-49bj"&gt;Webpack: Loaders, Optimizations &amp;amp; Bundle Analysis&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;For more tutorials like this, follow me &lt;a href="https://twitter.com/eagleson_alex?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@eagleson_alex&lt;/a&gt; on Twitter&lt;/p&gt;

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