<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Chad R. Stewart</title>
    <description>The latest articles on Forem by Chad R. Stewart (@chad_r_stewart).</description>
    <link>https://forem.com/chad_r_stewart</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%2F395121%2F4dd73e99-88c7-4886-b485-cd246beaaf92.jpg</url>
      <title>Forem: Chad R. Stewart</title>
      <link>https://forem.com/chad_r_stewart</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/chad_r_stewart"/>
    <language>en</language>
    <item>
      <title>Compile a single executable from your Node app with Node.js 20 and ESBuild</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Mon, 01 May 2023 16:46:46 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/compile-a-single-executable-from-your-node-app-with-nodejs-20-and-esbuild-210j</link>
      <guid>https://forem.com/chad_r_stewart/compile-a-single-executable-from-your-node-app-with-nodejs-20-and-esbuild-210j</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Node.js 20 was released very recently. Along with several other features, you can now compile your Node.js project into a single executable that can be run in environments without Node.js installed. It’s important to note that this is still experimental and may not be suitable for use in production.&lt;/p&gt;

&lt;p&gt;Node.js has instructions on how to set up these single executables: &lt;a href="https://nodejs.org/api/single-executable-applications.html"&gt;https://nodejs.org/api/single-executable-applications.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, when compiling the executable, you will not compile dependencies into your executable. To solve this problem, we will leverage a JavaScript bundler to bundle our dependencies into one file before compiling it into our single executable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Node.js 20&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note: While TypeScript is used in this article, it is not necessary.&lt;/p&gt;

&lt;h1&gt;
  
  
  Putting Together our Project
&lt;/h1&gt;

&lt;p&gt;First, we need a project that we will build into our executable.&lt;/p&gt;

&lt;p&gt;We’ll first define our server.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;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;https&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;https&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;fs&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;fs&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;path&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;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;//Initialize Request Data Type&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10mb&lt;/span&gt;&lt;span class="dl"&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="kd"&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;Hello World!!&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;3000&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="nx"&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server is live on &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;We define our package.json next:&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;"node-executable-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;"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;"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;"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;"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;"esbuild server.ts --bundle --platform=node --outfile=server-out.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;"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;"echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Error: no test specified&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; exit 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="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;""&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;"esbuild"&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.17.17"&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.18.2"&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.17"&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/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;"^18.15.7"&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;"^5.0.2"&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;Please note the build script. Esbuild will take our &lt;code&gt;.ts&lt;/code&gt; file and bundle it with our dependencies into a single &lt;code&gt;.js&lt;/code&gt; file &lt;code&gt;server-out.js&lt;/code&gt;. You can actually run this file once it is created using &lt;code&gt;node server-out.js&lt;/code&gt; to check if the bundling was done correctly.&lt;/p&gt;

&lt;p&gt;We then define our tsconfig.json&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;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"es2022"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lib"&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;"es2022"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commonjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"esModuleInterop"&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;"forceConsistentCasingInFileNames"&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;"strict"&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;"skipLibCheck"&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;We now define our sea-config.json file.&lt;/p&gt;

&lt;p&gt;This is a configuration file building a blob that can be injected into the single executable application (see Generating single executable preparation blobs for details)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sea-config.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;"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-out.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;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sea-prep.blob"&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 that we have everything we need, we can begin putting together our single executable.&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating the Single Binary File
&lt;/h1&gt;

&lt;p&gt;Begin by installing all the dependencies we’ll need by running 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;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once npm install is completed, we 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;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create our &lt;code&gt;server-out.js&lt;/code&gt; which will be our bundled file we will make into an executable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you rather, you can follow the instructions from the Node.js guide starting from step 3 as the following steps will be exactly the same, located here: &lt;a href="https://nodejs.org/api/single-executable-applications.html"&gt;https://nodejs.org/api/single-executable-applications.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generate the blob to be injected:&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;--experimental-sea-config&lt;/span&gt; sea-config.json 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a copy of the node executable and name it according to your needs:&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;cp&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; node&lt;span class="si"&gt;)&lt;/span&gt; server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you are on a Linux Distro (such as Ubuntu), you can skip the next steps and move straight to running the binary.&lt;/p&gt;

&lt;p&gt;Remove the signature of the binary:&lt;/p&gt;

&lt;p&gt;On macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codesign &lt;span class="nt"&gt;--remove-signature&lt;/span&gt; server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows (optional):&lt;br&gt;
signtool can be used from the installed Windows SDK. If this step is skipped, ignore any signature-related warning from postject.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;signtool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inject the blob into the copied binary by running postject with the following options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;server&lt;/code&gt; - The name of the copy of the node executable created in step 2.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NODE_SEA_BLOB&lt;/code&gt; - The name of the resource / note / section in the binary where the contents of the blob will be stored.
sea-prep.blob - The name of the blob created in step 1.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2&lt;/code&gt; - The fuse used by the Node.js project to detect if a file has been injected.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--macho-segment-name NODE_SEA&lt;/code&gt; (only needed on macOS) - The name of the segment in the binary where the contents of the blob will be stored.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To summarize, here is the required command for each platform:&lt;/p&gt;

&lt;p&gt;On systems other than macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx postject server NODE_SEA_BLOB sea-prep.blob &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--sentinel-fuse&lt;/span&gt; NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx postject server NODE_SEA_BLOB sea-prep.blob &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--sentinel-fuse&lt;/span&gt; NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--macho-segment-name&lt;/span&gt; NODE_SEA 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sign the binary:&lt;/p&gt;

&lt;p&gt;On macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codesign &lt;span class="nt"&gt;--sign&lt;/span&gt; - server 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows (optional):&lt;br&gt;
A certificate needs to be present for this to work. However, the unsigned binary would still be runnable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;signtool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/fd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SHA256&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now have a running Node server similar if you just ran node server-out.js&lt;/p&gt;

&lt;p&gt;If you wanted to see a completed example, go here: &lt;a href="https://github.com/chadstewart/ts-node-executable-article-example"&gt;https://github.com/chadstewart/ts-node-executable-article-example&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="//www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="//www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on &lt;a href="//www.twitter.com/techishiring"&gt;Twitter&lt;/a&gt;, &lt;a href="//www.linkedin.com/company/techishiring"&gt;LinkedIn&lt;/a&gt; or TechIsHiring's website &lt;a href="https://www.TechIsHiring.com/"&gt;https://www.TechIsHiring.com/&lt;/a&gt; for posted jobs and other resources!&lt;/li&gt;
&lt;li&gt;Want to check out a curated list of jobs, job seekers and resources from TechIsHiring? Check out &lt;a href="https://newsletter.techishiring.com"&gt;TechIsHiring's Newsletter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>esbuild</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Prioritization while making progress</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Fri, 25 Nov 2022 00:38:43 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/prioritization-while-making-progress-2cj7</link>
      <guid>https://forem.com/chad_r_stewart/prioritization-while-making-progress-2cj7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I wanted to quickly follow up on the making progress article because I realized recently that there was something missing from my approach.&lt;/p&gt;

&lt;p&gt;So I mentioned how to make tasks that will help you reach your goals but I didn’t say how to prioritize them. Effectively, all the tasks you come up with would have equal weight and it would be expected that you complete as many of them as you can each week. This doesn’t take into account their importance or their likeliness to move you towards your goals. So I wanted to talk about this quickly as supplemental information.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Prioritization
&lt;/h2&gt;

&lt;p&gt;So prioritization is the act of identifying what are the most impactful things you could do with the time you have. For example, you have a list of tasks as a Software Developer. You could fix a bug that could potentially cause an outage or you could work on a new feature. You are confident the feature can add new users to your software but you’ve identified that the likelihood of the bug to occur is pretty high. So you decide to immediately work on fixing the bug. Situations may not be as straight-forward as this example but this gives you an idea of what this would look like.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Prioritize
&lt;/h2&gt;

&lt;p&gt;So how do you prioritize your tasks? Honestly, I’m pretty new to doing this myself so I’m primarily going to defer to &lt;a href="https://twitter.com/kunchenxyz"&gt;Kun The Engineer&lt;/a&gt; who created a video on this topic:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=oYtze7axkkY"&gt;How to do Prioritization as a Software Engineer (From L8 SWE at Microsoft)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this video, Kun talks about the importance of prioritization as an Engineering Leader and then gives a process on how to prioritize tasks. To give a quick synopsis of the video, he proposes using a system which he mentioned has been battle-tested by several teams and has been shown to be very effective. The system is Priority = Impact x Confidence / Cost. Impact here being the value of the activity being successful, Confidence is how confident you are in being able to accomplish the task and Cost being the estimated amount of time (this example is in days) it would take to attempt to complete the task. I don’t want to take too much away from the video, I highly recommend watching it as he does a great job of explaining the system by going through an example.&lt;/p&gt;

&lt;p&gt;He also has a worksheet that he shares in &lt;a href="https://www.youtube.com/redirect?event=video_description&amp;amp;redir_token=QUFFLUhqa2ZIMk9wcHltWFNubzAwc1RIS1lvOUNKXzZ3d3xBQ3Jtc0trUi1PMnViTmhHUW5LZ2JrR3RnRTFhUy1VYjQ2NnkyRDltWGtfYWY2NVVhc0xBRzhZdjlBZnNpc1BMSDhMWlZfRDBJWS1zWlJrTnBNMU1QVU5pUElEX1hfVFVMWUpXaS1kcUNva2FKcTFabUozUGJtRQ&amp;amp;q=https%3A%2F%2Fmedium.com%2Ftech-career%2Fthe-single-most-important-skill-as-a-tech-lead-a08cf77efa7a&amp;amp;v=oYtze7axkkY"&gt;his blog on this topic&lt;/a&gt; which you can find &lt;a href="https://docs.google.com/spreadsheets/d/11NXbPJmhVxikhJWIG5CSjubBSCoZJV_LPGSiU9R2oIM/edit?usp=sharing"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PalAinZE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wpjqhaz7298w0yx7szm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PalAinZE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wpjqhaz7298w0yx7szm.png" alt="Worksheet with items filled out and weights" width="880" height="353"&gt;&lt;/a&gt;Image of worksheet in action calculating a priority after describing a cost, impact and confidence&lt;/p&gt;

&lt;p&gt;The reason why I wanted to point this out is I realized that this process works very nicely with the habits I talk about in planning for your week in the previous article. While the example he works on is more long-term, it can be used for more short-term goals. The main strength here is the addition of data. Personally I make a list every week to say what I need to do each week and I’ll be adding the work I did to come up with my prioritization. While the data is far from precise, it’ll give me an idea of the types of tasks I’m taking on in terms of impact and this’ll give me an idea if I need to switch my focus to something else.&lt;/p&gt;

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

&lt;p&gt;So I just wanted to touch on this quickly cause I think this would be a great addition to what I had talked about earlier. I am still learning myself but this is definitely an important skill to point out and so I wanted to share this with everyone as well!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="//www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="//www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on &lt;a href="//www.twitter.com/techishiring"&gt;Twitter&lt;/a&gt;, &lt;a href="//www.linkedin.com/company/techishiring"&gt;LinkedIn&lt;/a&gt; or TechIsHiring's new website &lt;a href="https://www.TechIsHiring.com/"&gt;https://www.TechIsHiring.com/&lt;/a&gt; for posted jobs and other resources!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>productivity</category>
      <category>selfimprovement</category>
      <category>goals</category>
    </item>
    <item>
      <title>Making Progress: How I've learned to move towards my goals</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Fri, 18 Nov 2022 01:11:56 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/making-progress-how-ive-learned-to-move-towards-my-goals-2jnl</link>
      <guid>https://forem.com/chad_r_stewart/making-progress-how-ive-learned-to-move-towards-my-goals-2jnl</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Sometimes you have plans that you want to move towards, long term career goals, short term career goals but you can’t seem to make progress on them. I was definitely in that position for years honestly. It really took a lot of understanding my pitfalls and setbacks then having a lot of revelation moments to get to a point where I can consistently make progress. I don’t want to say my system is a magic bullet, in fact, my system likely won’t completely work for you. What I want to do here is talk about the insights I came across as I finally came to something that worked for me. Hopefully those insights and examples of me leveraging them will help you start to make progress consistently.&lt;/p&gt;

&lt;p&gt;So the key things I find useful are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Having a long-term goal, a vision of your perfect future&lt;/li&gt;
&lt;li&gt;Knowing what you want to achieve in the short-term to move towards your long term goal&lt;/li&gt;
&lt;li&gt;Planning your weekly to help facilitate your short-term goals&lt;/li&gt;
&lt;li&gt;Building the habit of executing day to day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is skipping a few steps forward but the most important insight I came across is that you don’t need to spend your entire day grinding. Want to know why or know more about how you structure your day so you don’t have to grind? Keep reading to find out!&lt;/p&gt;

&lt;h2&gt;
  
  
  Have a Long Term Vision
&lt;/h2&gt;

&lt;p&gt;Having a long-term vision is very important to making progress towards something. How do you know if you’ve made progress if you don’t have a clear idea of what the end is? Cal Newport, author of ‘So good they can’t ignore you’, talks about the idea of envisioning a lifestyle that you want. What do you want your future to look like? Live in the city, go out and take in the city’s culture? Live out in the country-side? Be with nature? Figure that out and then work backwards to find the things that you need to do to achieve that.&lt;/p&gt;

&lt;p&gt;This isn’t meant to say that the above is exactly how you should make your long-term goal, but stressing that you have one and the benefits is just like the above says. It gives you an idea of how to work towards them just by having them. This doesn’t mean they won’t change but having a North Star helps you make progress towards it. So when should you revisit your goals? There isn’t a set time frame but it shouldn’t be regularly. Maybe every few months or so as life happens. Things will come up or you’ll change and maybe your vision you made no longer serves you. That’s okay, make changes if you need to. It’s there to be a guide, rather than be an anchor so treat it as such.&lt;/p&gt;

&lt;h3&gt;
  
  
  My long-term plans:
&lt;/h3&gt;

&lt;p&gt;This is my long-term plan which I keep in a document under career vision:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Primary Career Vision&lt;/strong&gt;: To gain the freedom to work on whatever projects I want&lt;br&gt;
&lt;strong&gt;Secondary Vision&lt;/strong&gt;: Move to the US to build large software systems and join a strong dev community&lt;/p&gt;

&lt;p&gt;If you’ve been to my Twitter profile, you’d likely have seen a tweet saying that I’ll move to the US this year. As of the time of this writing, that’s likely not gonna happen but it guides me to make decisions towards that goal. I honestly revise this plan more often than I should but it gives me a great idea of what I should be focusing on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Have Short Term Goals that support your vision
&lt;/h2&gt;

&lt;p&gt;A long-term plan is usually that, long-term. It could be years before you’re in the position to achieve that goal, even if it’s more modest. It’s easy to fantasize about our goal  and think we’re working towards it but rarely make any real progress. We need something to keep us more accountable towards our long-term goals. This is where short-term goals come in.&lt;/p&gt;

&lt;p&gt;Short-Term goals are what we want to achieve in a given time period. Where long-term goals tell us why we want to win the war, short-term goals are the strategy of how we will go about winning it. Let’s take some of my examples above and expand on them. Want to live in a big city? You’ll need a well paying job to live comfortably there. Software Engineering is a well-paying job. I guess that means you’ll need to learn to code. Well I think I can feel comfortable writing code in 3 months so let’s go with that. There might be some exaggeration or missing nuance here but that’s the basic idea. From your long-term goal, you can see where you are now and what you’ll need to make progress. You don’t need an entire road map, you just need something you can realistically achieve in a time period you’re comfortable with.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Short-Term Goals (Quarterly):
&lt;/h3&gt;

&lt;p&gt;I try to set a theme for my Quarterly Goals so that they’re easier to reason about:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Theme&lt;/strong&gt;: Optimize for building lasting relationships: “It’s not who you know, it’s who knows you.”&lt;/p&gt;

&lt;p&gt;I heard the saying from Brian Douglas (&lt;a class="mentioned-user" href="https://dev.to/bdougieyo"&gt;@bdougieyo&lt;/a&gt;) and have decided to structure my quarter around it. So the idea is to build stronger relationships in the tech community. I do have a fair amount of relationships currently but I feel they aren’t as strong as I’d like them to be. I’m not very good at managing relationships honestly and so I want to put more effort into that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Have a Weekly Plan
&lt;/h2&gt;

&lt;p&gt;Okay, so let’s continue leveraging our Software Engineer example. We decided we can get comfortable coding in 3 months but how do we plan to do that? I have no clue how to code now! Okay, I looked around and there are some pretty cheap courses on Udemy. I’ll buy the most popular and go with that. Okay, bought it! I’ll just try to go through these videos until I finish it!&lt;/p&gt;

&lt;p&gt;So using the example above (as an example as I’m sure people will find flaws in learning coding this way), we’ve come to the conclusion that going through videos until we finish is a sound strategy. If this wasn’t a Udemy course that tracks your progress, you’ll need a way to know what you’re doing and what you’ve done. This is where a weekly plan comes in. Idea here is to capture everything you need to do for the week and keep it top of mind so that you can remember to accomplish it. In our above example, we can add the specific videos we want to go through to our weekly plan and check them off as we complete them. The weekly plan is also really flexible too so as the week goes on and things come up, you can add them there as well.&lt;/p&gt;

&lt;p&gt;A key thing to do with your weekly plan is to make sure you’re checking things off as you complete them. This does two things: First, you’re getting a dopamine hit every time you check off a task and you’ll build the habit and the craving of that dopamine hit for checking tasks off your plan. This is critical to building up the habit of wanting to accomplish tasks. Second, if you miss any tasks, they can be easily tracked and transferred over to the next week. You can even over time see what type of tasks tend to get carried over and you can make adjustments there.&lt;/p&gt;

&lt;p&gt;So in previous sections, I tried to keep the terms from being time-specific. I honestly don’t have a better name for this section because I personally use a weekly plan. The main idea here is to be able to take your short-term goals and split them into ACTIONABLE things you can do during the week. Where the short-term plans are your strategy for winning the war, your weekly plan (and the next section about your day to day) will make up your tactics and things you repeat to win the war. I’m sure there are other systems out there that accomplish the same thing but the spirit is that you just need a way to generate actionable things from your quarterly plan that you can complete, feel good about it and move to the next one.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Weekly Plan (Nov 14 - Nov 18, 2022):
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Plans for this week&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Begin practicing DSA Interviews&lt;/li&gt;
&lt;li&gt;Update Twitter bot with v2 stream ✔&lt;/li&gt;
&lt;li&gt;Work on Accessibility issues on TechIsHiring ✔&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Plans for next week&lt;/strong&gt;:&lt;br&gt;
Update Design System to show more interactions for components&lt;/p&gt;

&lt;p&gt;The above isn’t my complete plan for this week but it’ll do great as an example. Also missing is I try to keep the theme for the quarter in my weekly plan doc so that I know if I’m working towards my goals or not. While there isn’t anything specific here that goes towards my quarterly goals, practicing DSA will help with long-term goals as I’ll likely be doing DSA interviews to get into companies that’ll offer H1-B support. Notice I have a section for next week as well just so I can capture things I need to do but I don’t need to think about working on them now. Also notice the ticks for completed tasks. Especially when you’re just starting, you’ll feel great adding those ticks to things so don’t neglect it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a Day to Day Habit of Execution
&lt;/h2&gt;

&lt;p&gt;So remember at the beginning of this article, I said the most important insight I came across is that you don’t need to grind every day? Well let me explain.&lt;/p&gt;

&lt;p&gt;You only really need 1 - 2 hours of focused uninterrupted effort each day on the most important things to make significant progress on your goals.&lt;/p&gt;

&lt;p&gt;I can only give you anecdotal evidence but I’ve been leveraging this mindset for the last few months and have made so much progress towards my goals! So the main idea for having a small amount of time of focused effort is to favor consistency over speed. 1 - 2 hours is much more doable long-term by a lot of people rather than potentially 5 - 6 hours daily. Finding 5 - 6 hours a day, even broken up is very difficult especially for those with responsibilities. Then there’s the actual mental strain of maintaining focus over such a long time, even broken up. It’s usually not sustainable. This isn’t to say “DO NOT DO THIS!” but letting people know that it’s okay to put in 1 - 2 hours on your most important tasks because over a long period of time, it’ll definitely compound!&lt;/p&gt;

&lt;p&gt;I want to stress that the time should be UNINTERRUPTED. This is very important because the effort to context switch from one task to another will steal time away from what you’ve allocated and you’ll end up getting less work done overall. This means you’ll need to find some time during the day where you can sit down for long periods of time without an issue. For most people with obligations, this usually means early in the morning when you wake up or late at night right before going to bed. Also important is to reduce the amount of things that can also interrupt you. Working at 9 pm for 2 hours is no good if your phone is constantly ringing and interrupting you. Silence your phone and close whatever apps and windows that’ll buzz you while you work. You want to be closed off from the world virtually for this time period.&lt;/p&gt;

&lt;p&gt;So say you can find 2 hours of uninterrupted time during your day, you now want to structure your tasks throughout the week to fit within this window. Using our Udemy example, we would want to go through videos for up to 2 hours per day. The reason for this is that you want to be able to add that check to your tasks at the end of each 2 hour period per day. Spend 2 hours working, add check, get dopamine reward. This cycle will drive you to getting work done and eventually taking on more and more ambitious tasks. Just remember though, you want to make progress so you can add that check. If a task is too large, break it down into smaller tasks that are accomplishable in the 2 hour period so you can add your check.&lt;/p&gt;

&lt;p&gt;Quick note, if adding a check isn’t enough of a reward to motivate you to continue, feel free to do something else. Reward yourself with watching TV, playing video games, ice cream, whatever your fun activity of choice is. The most important thing is that you put in focus effort and your brain recognizes that it’ll be rewarded for doing that.&lt;/p&gt;

&lt;p&gt;One other note. This does not mean you ONLY work during your 2 hour time period. That period is for focused work on your most important tasks. You’ll likely have a lot of administrative and small tasks you need to accomplish as well (hopefully captured in your weekly plan). The important thing here is that the things that add the most value for you should be worked on during your focused period because they are important. All the mundane things can be worked on throughout the rest of your day. Hopefully those things aren’t too extensive but you may have a fair amount of day left outside of your other obligations to complete these other things.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Day to Day:
&lt;/h3&gt;

&lt;p&gt;So I referenced 2 hours quite often in this section so it’s safe to assume that I spend 2 hours each day of focused effort and you’d be right. I prefer earlier in the morning to do my work so I tend to start my work at 8 am. I don’t have too many obligations so that’s a reasonable time for me but I’ve definitely found myself waking up at 4:30 am to start my personal work at 5 am.&lt;/p&gt;

&lt;p&gt;This is a typical day on my calendar:&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%2Fl5uk8tp8e5wgpxess5z1.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%2Fl5uk8tp8e5wgpxess5z1.png" alt="Calendar with two significant events: Deep Work Logical work and Deep Work Insight Work"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I call my periods of focus ‘Deep Work’ from Cal Newport’s books and the idea is that I work on the most important things to me in that period. You’ll notice that I have two periods, one called ‘Logical Work’ and another called ‘Insight Work’. The idea is as a Software Engineer, I primarily do my coding during the ‘Logical period’. I’ll do my writing, such as this article, during my ‘Insight period’. Technically means I do 3 hours of focused work but I’m more lenient on skipping writing. I also have a tendency to go more than the time I allotted because I don’t have the restraint of other responsibilities to attend to. For instance, I have written most of this article in one sitting which took me about 2 and a half hours. Regardless, it’s the spirit of the system rather than the system itself. It’s there to make executing more consistently over a long period of time easier.&lt;/p&gt;

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

&lt;p&gt;So let’s recap. You have a long-term vision that you want to strive towards. That long-term vision informs what you need to do in the short-term to move towards that vision. You then use your short-term goals to help determine what to accomplish for the week and you spend 2 hours of focused uninterrupted time each day trying to accomplish your major tasks and you fit in the other tasks where you can.&lt;/p&gt;

&lt;p&gt;I might not have mentioned this but the most important part of this is the day to day and identifying your tasks each week. It’s the habit of getting up and making progress each day and having a consistent flow of relevant things to accomplish that’ll get you towards your goal.&lt;/p&gt;

&lt;p&gt;One other thing, none of specific tips are set in stone. A lot of these came from my own reading and what worked for me. The most important takeaway from this is the general idea of the overall system, how they feed into each other and how you can build something similar yourself with the same ideas. &lt;/p&gt;

&lt;p&gt;Adapt these ideas to what best fits you!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="//www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="//www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on &lt;a href="//www.twitter.com/techishiring"&gt;Twitter&lt;/a&gt;, &lt;a href="//www.linkedin.com/company/techishiring"&gt;LinkedIn&lt;/a&gt; or TechIsHiring's new website &lt;a href="https://www.TechIsHiring.com/" rel="noopener noreferrer"&gt;https://www.TechIsHiring.com/&lt;/a&gt; for posted jobs and other resources!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
      <category>goals</category>
      <category>selfimprovement</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Setup a CI / CD process to automatically deploy Storybook in your project to Vercel</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Tue, 08 Nov 2022 23:09:34 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/setup-a-ci-cd-process-to-automatically-deploy-storybook-in-your-project-to-vercel-2i8d</link>
      <guid>https://forem.com/chad_r_stewart/setup-a-ci-cd-process-to-automatically-deploy-storybook-in-your-project-to-vercel-2i8d</guid>
      <description>&lt;p&gt;So you’ve set up a project, deployed it on Vervel, installed Storybook and have been writing stories for your components. Great job! You've taken a huge step forward in creating and documenting your design system! But what if you want to deploy it on Vercel alongside your project? You'll learn to do that here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Have a project set up with Storybook&lt;/li&gt;
&lt;li&gt;Pushed that project to a GitHub repo&lt;/li&gt;
&lt;li&gt;That GitHub repo can use GitHub actions&lt;/li&gt;
&lt;li&gt;Have a Vercel account already deploying the project&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Outline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Setup Storybook Vercel deployment branch&lt;/li&gt;
&lt;li&gt;Create a new domain to the Storybook deployment&lt;/li&gt;
&lt;li&gt;Set up GitHub actions to automatically merge to Storybook branch&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup Storybook Vercel deployment branch
&lt;/h2&gt;

&lt;p&gt;Vercel by default will automatically deploy a project when a new commit is pushed to the branch it's watching. We plan to leverage that behavior to update Storybook when new changes are made.&lt;/p&gt;

&lt;p&gt;First, from the main branch of your project, create a new branch called 'storybook-deploy". In that branch, you want to insert this file:&lt;/p&gt;

&lt;p&gt;vercel.json&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;"$schema"&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://openapi.vercel.sh/vercel.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"buildCommand"&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 build-storybook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devCommand"&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 storybook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"installCommand"&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 ci"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"framework"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outputDirectory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./storybook-static"&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 file will override the default deployment process and deploy Storybook when it sees this file. The storybook-deploy branch is now ready!&lt;/p&gt;

&lt;h2&gt;
  
  
  Point a domain to the Storybook branch
&lt;/h2&gt;

&lt;p&gt;Now go to your Vercel account and point a domain to the storybook-deploy branch that was created on GitHub. Here's an example below:&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%2Fhrexy7oh755wu0bpamt2.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%2Fhrexy7oh755wu0bpamt2.png" alt="Example of domain pointing to storybook-deploy branch on Vercel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up GitHub actions to automatically merge to Storybook branch
&lt;/h2&gt;

&lt;p&gt;We will now need to leverage GitHub Actions to automatically push code to the storybook-deploy branch whenever new code is committed which will cause Vercel to auto deploy it. Going back to the main branch of the project, add this file to the root directory of your project:&lt;/p&gt;

&lt;p&gt;.github/workflows/storybook.yml&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Deploy Storybook&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dev'&lt;/span&gt; &lt;span class="c1"&gt;# Trigger the action only pushed to a specific branch&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!main'&lt;/span&gt; &lt;span class="c1"&gt;# Ignore if pushed to a specific branch&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout 🛎️&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2.3.1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Merge dev -&amp;gt; storybook-deploy 🚀&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devmasx/merge-branch@1.4.0&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;now&lt;/span&gt;
          &lt;span class="na"&gt;from_branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;
          &lt;span class="na"&gt;target_branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storybook-deploy&lt;/span&gt;
          &lt;span class="na"&gt;github_token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.token }}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The above file will automatically merge the main branch into the storybook-deploy. This will then trigger a deploy from Vercel with the deployment configuration that was applied. Now that this is added to your project, push your code to your main branch. The GitHub action should now push it the branch to storybook-deploy and Vercel will now trigger a deploy. Please note that deploying a Storybook can take a few minutes.&lt;/p&gt;

&lt;p&gt;Now you've set up automatic deployment of your Storybook whenever a push is made to your main branch!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="//www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="//www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on &lt;a href="//www.twitter.com/techishiring"&gt;Twitter&lt;/a&gt;, &lt;a href="//www.linkedin.com/company/techishiring"&gt;LinkedIn&lt;/a&gt; or TechIsHiring's new website &lt;a href="https://www.TechIsHiring.com/" rel="noopener noreferrer"&gt;https://www.TechIsHiring.com/&lt;/a&gt; for posted jobs and other resources!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>storybook</category>
      <category>vercel</category>
      <category>cicd</category>
    </item>
    <item>
      <title>The lessons learned: The Story of #TechIsHiring part 3</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Mon, 07 Nov 2022 23:10:00 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/the-lessons-learned-the-story-of-techishiring-part-3-2cn4</link>
      <guid>https://forem.com/chad_r_stewart/the-lessons-learned-the-story-of-techishiring-part-3-2cn4</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the last article, we talked about the work that went into building the current value of TechIsHiring and a few hurdles that comes from running a hashtag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Despite any problems with running TechIsHiring, running and maintaining this has been one of the best decisions I’ve made for my career. I’ve met so many people through maintaining this and have been asked to speak on several topics because of my association with the hashtag. And it all really stemmed from being willing to spend some time to go out and help people find opportunity, even if that just meant poking around Twitter and finding tweets and just retweeting them.&lt;/p&gt;

&lt;p&gt;I think there are a few key lessons I took from TechIsHiring and it’s maintenance that is very applicable to others trying to break into the Tech Industry:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Give Back:&lt;/strong&gt; One of the things TechIsHiring has really taught me that one of the best ways to build your career is to give back to the Tech Community. Giving back to the community helps put your name out there and does so in a way that’s positive. People will see that and will be more interested in reaching out and offering your opportunities. I’ve definitely been offered much more opportunities than I think I really deserved honestly. One caveat though, you need to be giving back in public. You can’t be in a corner working on ‘the next big thing’ and then expect all of this great stuff to happen once you release it. People respond to the journey more than the destination so let others follow you along on that journey. You’ll be so glad you did!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You don’t have to start big:&lt;/strong&gt; TechIsHiring started as a Twitter hashtag, nothing more. There was no account or newsletter or anything. I just had my phone and I retweeted jobs I found. I still do this today. How you give back doesn’t need to be elaborate or needs to be this great big thing. Do something that people find beneficial and you’ll be surprised how much people will react positively to you!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Seek feedback:&lt;/strong&gt; A quick follow up to the previous point is actively for feedback. As you’re working, reach out to people and get their opinion on what you’re doing and how you could be doing better. TechIsHiring wouldn’t be the way it is today without the feedback of several people who were only interested in helping me do better. If you’ve been doing something for a while, people will be much more willing to give you some feedback and help you along, if only to be able to say they were a part of your journey!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don’t underestimate the technical need for what you pursue:&lt;/strong&gt; This advice is specifically for those in or are seeking Engineering roles. I’ve said this a few times before but TechIsHiring was just a hashtag starting out. Since then, I’ve built a Twitter bot which I had to update and built a website for TechIsHiring. All of these solutions needed to be deployed on some form of infrastructure to keep them running. A concern I had as I worked on TechIsHiring is that there wasn’t much of a technical need since I was just retweeting with a hashtag. I’ve since had to bring a fair amount of my Software Engineering skills and experience to solve some of the technical problems TechIsHiring has faced. Don’t underestimate the technical need for whatever you decide to pursue. There are many stories of someone solving a particular problem with a weekend project that turned into their day job or even their life’s work. You’d be surprised how something so simple as, “I need a website,” can balloon to interesting and engaging technical solutions! Just remember to do this work in public!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Be persistent:&lt;/strong&gt; The most important thing that TechIsHiring has taught me was the value of being persistent. Showing up every day, regardless of the quality of the work done, is significantly better than showing up and doing your absolute best work ONLY ONCE! This has been a slow grind and continues to be a slow grind but being persistent definitely pays off. Set yourself up to be able to put in some form of work consistently and over time that work will compound on itself. If you take nothing away from this, please take that!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;And that’s really it. That’s the story of how I came to let everyone know that TechIsHiring! It’s been an interesting journey and I honestly did not think I would have ended up being a part of something like this. But I really am enjoying the ride and looking forward to seeing what this journey brings!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="//www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="//www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on &lt;a href="//www.twitter.com/techishiring"&gt;Twitter&lt;/a&gt;, &lt;a href="//www.linkedin.com/company/techishiring"&gt;LinkedIn&lt;/a&gt; or TechIsHiring's new website &lt;a href="https://www.TechIsHiring.com/"&gt;https://www.TechIsHiring.com/&lt;/a&gt; for posted jobs and other resources!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hiring</category>
      <category>jobsearch</category>
      <category>entrepreneurship</category>
    </item>
    <item>
      <title>Building value in TechIsHiring: The story of #TechIsHiring part 2</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Thu, 03 Nov 2022 22:08:36 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/building-value-in-techishiring-the-story-of-techishiring-part-2-5g9c</link>
      <guid>https://forem.com/chad_r_stewart/building-value-in-techishiring-the-story-of-techishiring-part-2-5g9c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When we last left off, I had just founded TechIsHiring and now had to figure out how to get TechIsHiring into a state where people would be interested in using it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Construction starts
&lt;/h2&gt;

&lt;p&gt;So there were two main concerns I had early on. Outside of the few people who may have voted on the poll or had seen my tweet about the hashtag, no one knew what TechIsHiring was. The second concern was the value of the hashtag itself. The hashtag had no more or less nothing in it so why would anyone want to check it consistently much less contribute to it? While adoption was a problem (and one I continue to struggle with), I felt increasing the value proposition of the hashtag was the best thing for me to do.&lt;/p&gt;

&lt;p&gt;So how do I do that? Well just go find job seeker tweets and job tweets and quote-tweet them with #TechIsHiring. I would do this at least once, Monday thru Friday for the next 8 months.&lt;/p&gt;

&lt;p&gt;Very early on in TechIsHiring’s life, I made the conscious decision to refrain from retweeting tweets I didn’t have permission to do, something I continue to try to do to this day. If anyone follows me has seen this from me AT LEAST ONCE:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DPCJ3nIX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pggtu7ofqsd5wwdihgey.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DPCJ3nIX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pggtu7ofqsd5wwdihgey.jpg" alt='A twitter posting of me saying: "Hey there! I run a space @TechIsHiring in an attempt to consolidate tech job tweets and searching for tech job tweets into one place. Do you mind if I quote tweet your post with the TechIsHiring hashtag?' width="512" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, it might as well make a business card out of it, it’s probably more recognizable than I am. I’ve definitely received a few criticisms for this though nothing really malicious. For me, even though it’s technically public domain, it’s really about respecting other people’s space, virtual or otherwise. This is just an attempt to uphold that philosophy as best as I can.&lt;/p&gt;

&lt;p&gt;The actual TechIsHiring account came a few months after I started posting the hashtag regularly. I knew I needed an account for the hashtag to be more effective and a bot to consistently retweet the hashtag but honestly was dragging my feet on it. It wasn’t until &lt;a href="https://twitter.com/jfc3"&gt;John Croston&lt;/a&gt; really pressured me into creating the account did I really go and do it. The bot came quickly after, mostly because I didn’t want to have to retweet everything myself. I ended up poking through a few bots that were already implemented and just adapted one I was satisfied with to retweet the hashtag. Learned a fair amount about Twitter’s API playing around with it and about Heroku when I finally got it deployed. The early version wasn’t great but the cobbled together code did what it needed to do so I didn’t complain too much. Here's a link to the repo of the first TechIsHiring Twitter bot: &lt;a href="https://github.com/chadstewart/Tech-Is-Hiring-Twitter-Bot"&gt;https://github.com/chadstewart/Tech-Is-Hiring-Twitter-Bot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now I had a place where people’s tweets would live. It wasn’t branded at all and wasn’t pretty but at least it was something.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gaining momentum
&lt;/h2&gt;

&lt;p&gt;Once the TechIsHiring account got made and the bot was actively retweeting posts, it was significantly easier to see how the hashtag was growing. Growth was slow but steady, fueled mainly through my consistent posting to the hashtag with valuable posts. Growth stayed this way for a few months until close to the end of the year 2021.&lt;/p&gt;

&lt;p&gt;It started with me initially hosting a Twitter Space to ask about what TechIsHiring could do to better serve the community. Twitter Spaces had been open to the public for maybe a month or so and I felt it was an active way for me to engage with the community and get feedback. Ironically, I didn’t get too much feedback to push the hashtag forward but I ended up realizing that Twitter Spaces might be a great way of engaging with the community in general. So I started hosting Twitter Spaces more regularly, focusing on topics that I thought people would be interested in talking about. More and more people would come into the Twitter Space and we’d have great discussions on these topics. Then other people started reaching out to me.&lt;/p&gt;

&lt;p&gt;The first was &lt;a href="https://www.twitter.com/bdougieyo"&gt;Brian Douglas&lt;/a&gt; of Open Sauced and GitHub. He had reached out to request that I come to speak in some of the Twitter Spaces he wanted to host. Not only would he host the Twitter Space, he also agreed to put up the TechIsHiring hashtag in the space. Why this was important was because when Twitter Spaces are shared, the hashtags in them are automatically added to the tweet they are shared in. This was the first time I really learned of the power of being tied to a strong event. Both TechIsHiring’s engagement and my own engagement grew as a result of these Twitter Spaces.&lt;/p&gt;

&lt;p&gt;The second was actually a few months later with &lt;a href="https://www.twitter.com/Sham_jab"&gt;Sham&lt;/a&gt; and &lt;a href="https://www.twitter.com/real_temz"&gt;Temz&lt;/a&gt; of &lt;a href="https://www.twitter.com/Tech__UK"&gt;Tech__UK&lt;/a&gt;. They came from Clubhouse to host job hunting Twitter Spaces like they had done previously. Sham actually was the person who reached out to me mainly to leverage the TechIsHiring hashtag. They began hosting the same type of job searching Twitter Spaces like they did in Clubhouse but they were now added the #TechIsHiring hashtag to their space. That each time that space would happen, it would get retweeted constantly and each retweet would have the TechIsHiring hashtag. It technically was kind of spammy but it was extremely effective in getting engagement for the hashtag. So much so that there was a point where TechIsHiring was trending on Twitter. It was absolutely amazing!&lt;/p&gt;

&lt;p&gt;These were some of the things that really grew the hashtag to what it was today. While these events were important, I think the most important attribute was just my own dedication to the hashtag and to trying to get valuable posts into it.&lt;/p&gt;

&lt;p&gt;While not directly related to the hashtag’s growth, TechIsHiring started releasing a newsletter every week. This newsletter focused on promoting interesting jobs, job seekers and other interesting advice and information from the hashtag for that week. The idea actually came from Veni from Diversity Tech when I reached out to her on how to grow TechIsHiring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Growing pains
&lt;/h2&gt;

&lt;p&gt;So while TechIsHiring has experienced a fair amount of growth, that growth has come with some challenges as well. One of the main challenges of running a hashtag, especially one that is being powered by a Twitter bot that is indiscriminate about what it retweets, is spam. Early in TechIsHiring’s life, spam was simply not a problem though that was also because engagement was still low. As the hashtag’s popularity grew, the tendency for spam did too. For the hashtag itself, it wasn’t too much of a problem and honestly is something that can’t really be solved but for the account that is actively retweeting #TechIsHiring tweets, it was problematic but also solvable. From a technical perspective, what needed to happen was to have some form of banned or restricted list and those on that list would not get retweeted. The initial version was crude and was a pain to manage but got the job done initially. That was eventually updated to be significantly more manageable. If you’re interested in a deep dive of how the TechIsHiring Twitter bot got updated, check out this article: &lt;a href="https://dev.to/chad_r_stewart/migrating-the-techishiring-twitter-bot-42fm"&gt;https://dev.to/chad_r_stewart/migrating-the-techishiring-twitter-bot-42fm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next time, we wrap up and talk about the continued success of TechIsHiring and some of the things I've learned from this experience!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="//www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="//www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on &lt;a href="//www.twitter.com/techishiring"&gt;Twitter&lt;/a&gt;, &lt;a href="//www.linkedin.com/company/techishiring"&gt;LinkedIn&lt;/a&gt; or TechIsHiring's new website &lt;a href="https://www.TechIsHiring.com/"&gt;https://www.TechIsHiring.com/&lt;/a&gt; for posted jobs and other resources!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hiring</category>
      <category>entrepreneurship</category>
      <category>jobsearch</category>
    </item>
    <item>
      <title>From job seeker to building bridges for other job seekers: The story of #TechIsHiring Part 1</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Mon, 31 Oct 2022 22:36:12 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/turning-setbacks-into-opportunities-the-story-of-techishiring-part-1-2ce</link>
      <guid>https://forem.com/chad_r_stewart/turning-setbacks-into-opportunities-the-story-of-techishiring-part-1-2ce</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E8bA-EFJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l1i3wa5u9ar3nwzz10b4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E8bA-EFJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l1i3wa5u9ar3nwzz10b4.jpg" alt="Nerando commenting that I turned my entire job search into a product. Me letting Nerando know he's smart!" width="254" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As of this writing, TechIsHiring is a year and a half old. It currently has 11,000+ followers on Twitter, a little over 1,000 followers on LinkedIn and has a newsletter with 750+ subscribers. This is probably the most impactful thing I’ve ever done and most certainly the most impactful thing I currently maintain. As Nerando said in the image above, I managed to turn my job search into a product.&lt;/p&gt;

&lt;p&gt;And it was a happy accident!&lt;/p&gt;

&lt;p&gt;TechIsHiring was born from a question I randomly asked #TechTwitter one day almost two years ago and after some minor encouragement, I decided that I’d try to put this thing together. A lot of the ideas that make up TechIsHiring currently weren’t even mine honestly. The newsletter came from &lt;a href="https://www.twitter.com/veniKunche"&gt;Veni Kunche&lt;/a&gt;, the account itself and the bot was something I dragged my feet on until &lt;a href="https://twitter.com/jfc3"&gt;John Croston&lt;/a&gt; pushed me to do so. The branding that exists today only came to be because &lt;a href="https://www.twitter.com/bdougieyo"&gt;Brian Douglas&lt;/a&gt; insisted that I fix the account page. All I did was come up with the name, and ironically #TechTwitter rejected it in a poll. A collection of happy accidents and good luck makes TechIsHiring what it is today.&lt;/p&gt;

&lt;p&gt;Want to hear how these came to be? Okay, let’s start at what started all this. My pandemic job search.&lt;/p&gt;

&lt;h2&gt;
  
  
  Job Searching is Tough
&lt;/h2&gt;

&lt;p&gt;In February 2020, I had left a previous role and took some time off before going back out on the grind. After my break, I had initially planned to travel to New York and spend some time with the Dev Community there (I didn’t know about TechTwitter at the time). I had family in New York I could stay with to make it affordable for myself and had saved up enough money to not die of hunger during my stay.&lt;/p&gt;

&lt;p&gt;Little did I know that a global pandemic was getting ramped up.&lt;/p&gt;

&lt;p&gt;By March of 2020, my plans were officially dashed as Jamaica entered lockdown. No flights were coming in and out the island and an island-wide curfew was in effect which would last the next 2 years. By this time, the US was well into its own lockdown process and I didn’t feel comfortable flying there anyhow. It was during this time I learned of &lt;a href="https://www.twitter.com/bekahhw"&gt;@BekahHW&lt;/a&gt; and &lt;a href="https://www.twitter.com/virtualcoffeeio"&gt;@VirtualCoffeeIO&lt;/a&gt; (before it got its official name). I spent a lot of time hanging out with a lot of the members there and attending events. A lot of the conversations were about job searching and trying to find a job as a beginner. This really pushed me to really start my job search again and after polishing up my resume and a quick review, off I went.&lt;/p&gt;

&lt;p&gt;Summer 2020 felt like THE WORST time to job search as a foreign worker presenting themselves with only a year of experience (which is a whole other story(link to resume article)). I spent the better part of the year getting rejected from every company imaginable. Even companies that I had a connection with that worked there had absolutely no interest in me. It was a tough time and the only thing I could really think of doing was reworking my resume cause maybe I could spruce it up to make it better.&lt;/p&gt;

&lt;p&gt;It was during this time that I noticed people making tweets about their job search. And so I tried to do the same as well and my tweet did well. I had a lot of people retweeting and liking my tweet and I had a few people reach out that were interested because of it. While I was unable to leverage the opportunities that I got, it did show me I could really leverage Twitter as a mechanism to find great opportunities. &lt;/p&gt;

&lt;p&gt;My own job search had its highs and lows but I kept as best as I could.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is there a space for job searching tweets?
&lt;/h2&gt;

&lt;p&gt;Fast-forward to around April 2021. My job search hadn’t really improved but I kept at it, leveraging the new resource of people making job searching tweets to try and help my own search. It was then when I asked this question which changed my life:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ECZofVsz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nypcvi2dgrfu59c4lr0v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ECZofVsz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nypcvi2dgrfu59c4lr0v.jpg" alt="A tweet I made to that would eventually start the hashtag: Is there a hashtag for technology professionals looking for work? If there isn't, someone should definitely create one (has no problem being that somebody). #cybermentoringmonday #techtwitter #blacktechtwitter" width="512" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be 100% honest with you, I might not have followed up on this if it weren’t for someone reaching out and urging me to push forward with the idea. That person was @SpencerGTyson who decided that this was a great idea and that I should seriously pursue this. The poll to decide the original name was his idea:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--peeSyKRV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rzeqwt9x6wv5jkzzwsdg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--peeSyKRV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rzeqwt9x6wv5jkzzwsdg.jpg" alt="A tweet I made about polling for the name of the hashtag. #TechIsHiring came second to #TechHireHere" width="276" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you probably noticed, TechIsHiring actually didn’t win that poll. So wha’ ha’ happen was, when I checked out #TechHireHere, I noticed there was a company using it. It was irregular but it was enough to deter me from the name. Also honestly, I liked #TechIsHiring more. And so after a bit of grumbling, I decided that I’d stake a claim to my new piece of digital land:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D6dzNMHS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2pkdbcwczfpwr5e7q5k4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D6dzNMHS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2pkdbcwczfpwr5e7q5k4.jpg" alt="The very first #TechIsHiring tweet: Just wanted to promote a hashtag for tech hiring on Twitter! #TechIsHiring If you are making a looking for work tweet or job posting, please consider using this hashtag to help people find it easier. I claim this hashtag in the name of Mar-uhh... Tech! And there's an image of Marvin the Martian looking at a Mars flag" width="280" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that’s how TechIsHiring was born. Now the real challenge was to begin. How the hell was I going to get people to use this thing? &lt;/p&gt;

&lt;p&gt;In the next article, I'll talk about actually attempting the grow the hashtag!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="//www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="//www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on &lt;a href="//www.twitter.com/techishiring"&gt;Twitter&lt;/a&gt;, &lt;a href="//www.linkedin.com/company/techishiring"&gt;LinkedIn&lt;/a&gt; or TechIsHiring's new website &lt;a href="https://www.TechIsHiring.com/"&gt;https://www.TechIsHiring.com/&lt;/a&gt; for posted jobs and other resources!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hiring</category>
      <category>jobsearch</category>
      <category>entrepreneurship</category>
    </item>
    <item>
      <title>Build Resilient UIs: Frontend Architecture that doesn't suck!</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Tue, 25 Oct 2022 00:21:54 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/frontend-architecture-and-tooling-that-will-lead-to-a-more-resilient-codebase-7ib</link>
      <guid>https://forem.com/chad_r_stewart/frontend-architecture-and-tooling-that-will-lead-to-a-more-resilient-codebase-7ib</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Frontend code can get really complex really quickly. This comes from how we naturally tend to build webpages and how we tend to write CSS. Web Pages tend to be built from the top down where we define and style the page, then sections we want to work on, then the individual pieces of that section and so on. It’s easy to forgo good engineering practices and then end up building highly coupled components.&lt;/p&gt;

&lt;p&gt;How can we deal with this in our frontend code and keep it more resilient? We can make strong architectural decisions early on in the project that benefit us as the project evolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  OutLine
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Benefits of thinking about Architecture early&lt;/li&gt;
&lt;li&gt;Tools and methodologies I found beneficial&lt;/li&gt;
&lt;li&gt;Loose Coupling&lt;/li&gt;
&lt;li&gt;Component Driven Design&lt;/li&gt;
&lt;li&gt;Atomic Design&lt;/li&gt;
&lt;li&gt;Storybook&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Benefits of thinking about Architecture early
&lt;/h2&gt;

&lt;p&gt;In most codebases the primary reason for the codebase becoming difficult to work with is the haphazard nature of writing frontend code. You start a project with the intention of solving a problem or getting a design on the page. You spend most of your time focusing on what renders in the browser that it’s very easy to forget to manage the codebase as well. I’ve seen greenfield projects become difficult to work on within a matter of a few weeks.&lt;/p&gt;

&lt;p&gt;CSS also has the ability to add to significant coupling of our components by unintentionally applying CSS rules to components through poor selectors. Naming and selecting components is extremely important when writing good CSS. It’s very easy to write poor selectors that work for your particular use case and then when needing to extend your frontend code and its CSS, you find you have to code around your previous selectors. This quickly devolves into CSS spaghetti and you now spend more time trying to properly select your components in CSS than writing code that adds value. Even with component-based frameworks like React and Vue, this is how frontend codebases tend to evolve without proper care.&lt;/p&gt;

&lt;p&gt;These types of problems can be avoided by making architectural decisions about your frontend code early in the project and sticking to them throughout its lifespan. Here’s an example of a project that made architectural decisions early on:&lt;/p&gt;

&lt;p&gt;Quite early on a recent project I worked on, we started having discussions of the architecture of the frontend codebase. We decided to go with Atomic Design for how we created components and eventually we’d start to practice Component-Driven Development when writing components, building components in isolation using Storybook before putting them on the page. Within a month after setting up all the necessary infrastructure and getting used to our development process, development moved extremely quickly as we were leveraging the previously built components in our design system to move forward.&lt;br&gt;
We eventually took on more work than we could really handle and we needed to bring on someone for help. This is generally a no-no in project management as it usually takes new people a long time to get ramped up and be productive on a project. In this circumstance though, the ramp up time for bringing on the new person was extremely small for two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The new person needed to build new frontend components but we built components in isolation before putting them on the page so they didn’t need to know the codebase well to add to it.&lt;/li&gt;
&lt;li&gt;Because of Atomic Design and building components using Storybook, the components remained relatively isolated even in production and so even when putting them on the page, you didn’t need to interact with the rest of the codebase outside of the work you needed to do.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A few other people had contributed to the codebase as well with similar results, some of which were much junior in their coding experience but were able to contribute because of how the architecture made the codebase very approachable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools and methodologies that I found beneficial
&lt;/h2&gt;

&lt;p&gt;So I’d like to give you some concrete tools and ideas you can use to accomplish this. Here are some of the things that allowed the codebase in my story to be as resilient as it was:&lt;/p&gt;

&lt;h3&gt;
  
  
  Loose Coupling
&lt;/h3&gt;

&lt;p&gt;A major architectural concept in software engineering. Loose coupling is a concept where the dependencies between different components are low. The benefit of this is if there is a change that needs to be made in a component, few other components would need to be changed as well. This helps isolate your components from each other, allowing changes to components as they need to be expanded upon to be much more frictionless. This also allows you to work on them in parallel without worrying about the implementation details of another developer’s work.&lt;/p&gt;

&lt;p&gt;Every other concept or tool that I talk about will contribute to this and is the main philosophy why they were so effective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Driven Design
&lt;/h3&gt;

&lt;p&gt;An important frontend development concept. Frontend development tends to be top-down where we define the page first and then the elements within it. Component-Driven Design turns that idea on its head by focusing on working on the components (starting with the smallest) first and then putting the page together as the final step. This works particularly well because the smallest component such as buttons and text tends to get repeated when building top down. Building those first allows you to use them throughout the application without redefining them.&lt;/p&gt;

&lt;p&gt;Where loose coupling is a rule we follow in architecture to keep our codebase resilient, Component-Driven Design helps enforce that rule as developing this way naturally leads to less coupled components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atomic Design
&lt;/h3&gt;

&lt;p&gt;Atomic Design is a component design pattern by Brad Frost defined in the early 2010s. The concept is each component falls into the categories of atoms, the smallest components, molecules, made up of multiple atoms, organisms, made up of atoms and molecules and pages which are made up of the 3 previously described categories.&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%2Fyt27irjyxj5ivl1o9tz7.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%2Fyt27irjyxj5ivl1o9tz7.png" alt="Image from Brad Frost's blog post on Atomic Design, illustrating how the different components relate to each other"&gt;&lt;/a&gt;Image from Brad Frost's blog post on Atomic Design, illustrating how the different components relate to each other&lt;/p&gt;

&lt;p&gt;Where Component-Driven Design tells us how we construct pages, Atomic Design tells us how components relate to one another.&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%2F2ylolubir6bzom49vu5q.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%2F2ylolubir6bzom49vu5q.png" alt="Folder Structure of an Atomic Design Project"&gt;&lt;/a&gt;Folder Structure of an Atomic Design Project&lt;/p&gt;

&lt;p&gt;This and Component-Driven Design are what we will mainly use to keep our frontend codebase loosely coupled,making it extremely resilient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storybook
&lt;/h3&gt;

&lt;p&gt;Storybook is a tool used to document Design Systems, each instance of a frontend component and the varying states it can be in being called stories. Storybook focuses mainly on the visual aspect of frontend components, allowing you to see how components are rendered and see their different states and what actions they have.&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%2Ftq9dha8o32qca2pyqvwg.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%2Ftq9dha8o32qca2pyqvwg.png" alt="Screenshot of Storybook"&gt;&lt;/a&gt;Screenshot of Storybook&lt;/p&gt;

&lt;p&gt;The three previous concepts we talk about, the frontend code itself and other tools necessary to run that code will come together to form a Design System which can be documented in Storybook. While documenting the Design System is important and should be done, the power of Storybook for our purposes is that you can develop components in isolation of the rest of the system. This helps enforce the loose coupling throughout the codebase by forcing Developers to put together components that do not need to rely on the rest of the system to run. The second benefit is you are automatically documenting, at minimum, a new component in the Design System as you develop new components.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript
&lt;/h3&gt;

&lt;p&gt;TypeScript is a language built on top of JavaScript, built with the intention of adding static-types to JavaScript. While not 100% necessary, for larger projects or projects you expect to grow large, TypeScript becomes invaluable especially paired with Atomic Design and Component-Driven Design. As you build out components, these components may need specific data. With a large enough set of components of various uses, it's easy to forget something the component needs or accidentally add something the component wasn't expecting.&lt;/p&gt;

&lt;p&gt;TypeScript does a great job of eliminating that particular issue by enforcing what a component expects when properly typed. Secondly, TypeScript also doubles as the first layer of documentation for your components. When leveraging your component, TypeScript will tell your IDE what your component expects which makes using components significantly easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tailwind CSS
&lt;/h3&gt;

&lt;p&gt;Tailwind CSS is a library that allows you to add prebuilt CSS rules by adding Tailwind classes to your markup. With this you no longer have to write CSS yourself, you just use a combination of Tailwind classes to get the styling you want.&lt;/p&gt;

&lt;p&gt;Tailwind is likely the most controversial topic here but allow me to explain. CSS, when written poorly, tends to lead to more tightly coupled components in unexpected ways. It is also quite easy to write CSS poorly and to have that coupling make itself known when you least expect it. This is mainly through the selection of HTML elements to add styling rules to. Tailwind effectively eliminates that by forcing a Developer to leverage predetermined styling rules which are applied by adding classes. Because of this, there is rarely any need to attempt to select HTML elements to apply styling and thus you don’t write poorly written CSS selectors.&lt;/p&gt;

&lt;p&gt;Additionally, this now keeps all your presentation logic in a single file, leading to high cohesion, where related items are packaged together which in this case would be the presentation logic.&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%2Feyxis7c0ylw1xx3v8woa.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%2Feyxis7c0ylw1xx3v8woa.png" alt="Screenshot of code using traditional CSS showing a CSS file in the component folder"&gt;&lt;/a&gt;Screenshot of code using traditional CSS showing a CSS file in the component folder&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%2F6izla6prjxagtgpashrq.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%2F6izla6prjxagtgpashrq.png" alt="Screenshot of CSS file found in above image"&gt;&lt;/a&gt;Screenshot of CSS file found in above image&lt;/p&gt;

&lt;p&gt;Versus...&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%2F23z0qn3o0wx7ztu5k855.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%2F23z0qn3o0wx7ztu5k855.png" alt="Screenshot of code using Tailwind CSS showing component folder without a CSS file"&gt;&lt;/a&gt;Screenshot of code using Tailwind CSS showing component folder without a CSS file&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*Note: If you rather not use Tailwind there are two alternatives that come to mind in terms of this idea. The first is leveraging Styled Components. You get to write CSS rules but you still avoid writing CSS Selectors. This I feel is an acceptable middleground. The second is simply learning to write better CSS and in turn writing better CSS Selectors.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One other thing I want to briefly touch on is keeping your presentation logic and business logic separate. My experience is mainly with React but how this manifested in my work was putting as much of the business logic in React Hooks and separate utils as possible. I’d also try to integrate hooks into the highest level component that needed the data. Such as if the highest level component was an organism, then the hook would output the data there and the organism would be responsible for distributing the data to the relevant components. While important, I feel this deserves its own article to expand on this further. &lt;/p&gt;

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

&lt;p&gt;I have to openly admit that I stumbled across this entirely by accident. All I knew was the pain I suffered throughout previous codebases I worked in and these ideas I came across throughout my Front End Engineering career. Even then, I accidentally implemented them in one project and was self-aware enough to notice these benefits, only really defining how they worked together in writing this article. While all the tools described above will lead to a better codebase and a better developer experience, the main thing I want Engineers to take away from this is the concept of loosely coupled components and directly enforcing that through the choice of tools and development practices you decide to implement. I’m sure there are other ways to achieve this with tools and techniques I haven’t come across.&lt;/p&gt;

&lt;p&gt;This article is inspired from the experience I wrote about here: &lt;a href="https://dev.to/opensauced/built-a-full-feature-in-6-hours-my-experience-on-how-the-right-tooling-can-improve-your-development-velocity-2gbd"&gt;Built a full feature in 6 hours: My experience on how the right tooling can improve your development velocity&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two talks I watched really help inform me on some of the concepts I speak about here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=o8THlN8hgcw" rel="noopener noreferrer"&gt;Frontend Architecture: Front-End Architecture 101 - Nir Kaufman @ ReactNYC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=TqfbAXCCVwE" rel="noopener noreferrer"&gt;Learn to build resilient Front-End Architecture: Learn how to build resilient frontend architecture with Monica Lent - GOTO: Development talks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="//www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="//www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on &lt;a href="//www.twitter.com/techishiring"&gt;Twitter&lt;/a&gt; or &lt;a href="//www.linkedin.com/company/techishiring"&gt;LinkedIn&lt;/a&gt; for posted jobs and other resources!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>frontend</category>
      <category>architecture</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Access to UI Library props or hard-coded options in a Design System?</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Tue, 18 Oct 2022 19:04:06 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/access-to-ui-library-props-or-hard-coded-options-in-a-design-system-267c</link>
      <guid>https://forem.com/chad_r_stewart/access-to-ui-library-props-or-hard-coded-options-in-a-design-system-267c</guid>
      <description>&lt;h2&gt;
  
  
  Quick Question: Would you rather have access to the props of a UI Library or have a dev hard-code options you select from when using components in a Design System?
&lt;/h2&gt;

&lt;p&gt;So recently, I wrote &lt;a href="https://dev.to/opensauced/create-more-maintainable-ui-by-adding-a-wrapper-around-ui-library-elements-3oae"&gt;an article&lt;/a&gt; about adding a wrapper around components from a UI library so you get access to the props from the UI library but you can customize the component before displaying it on the page. At the time, I thought this was the ultimate in component management. The more I think about it though, the more that might not be the best or simply not other Engineers' preference. So I wanted to post the question to everyone.&lt;/p&gt;

&lt;p&gt;Please comment here or in the Twitter thread that this will appear in. Thanks so very much!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>components</category>
      <category>typescript</category>
      <category>react</category>
    </item>
    <item>
      <title>Migrating The TechIsHiring Twitter Bot to Twitter API v2</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Mon, 17 Oct 2022 21:28:04 +0000</pubDate>
      <link>https://forem.com/chad_r_stewart/migrating-the-techishiring-twitter-bot-42fm</link>
      <guid>https://forem.com/chad_r_stewart/migrating-the-techishiring-twitter-bot-42fm</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;TechIsHiring is a pretty lightweight organization and it doesn’t have much infrastructure. It does have one main thing though that is crucial to its operation, the TechIsHiring Twitter bot. The TechIsHiring Twitter bot retweets any tweet containing the string ‘#TechIsHiring’, which in turn makes the TechIsHiring Twitter account the main source of information on the hashtag. Our newsletter is also indirectly powered by the Twitter bot because it allows me to easily go through and find tweets using the Twitter account to put in the newsletter.&lt;/p&gt;

&lt;p&gt;The TechIsHiring Twitter bot is easily the main reason for TechIsHiring going from nothing to over 10,000 followers on Twitter and having over 700 subscribers on our newsletter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why migrate the Twitter bot?&lt;/li&gt;
&lt;li&gt;Updating the Twitter bot&lt;/li&gt;
&lt;li&gt;Migration and Deployment&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why migrate the Twitter bot?
&lt;/h2&gt;

&lt;p&gt;The TechIsHiring Twitter bot was initially deployed on Heroku Dynos on their free tier and has been in production for over a year and a half. In that time, not much has really changed from its original inception, really only needing to be updated as a few new problems came up as more eyes saw the hashtag and the Twitter account.&lt;/p&gt;

&lt;p&gt;Unfortunately, Heroku has decided to end its free tier for Dynos and this pushed me to consider migrating the Twitter bot. Also with the consideration of migration, I felt updating the bot was also a good idea. I had grown significantly as a developer since its original development and there were some features that I wanted to add to handle some minor administration issues with the Twitter account.&lt;/p&gt;

&lt;p&gt;So with that, I set out to update the Twitter bot and move it to a new home.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the Twitter Bot
&lt;/h2&gt;

&lt;p&gt;There are a few main technology changes made to the Twitter bot in it’s update:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding TypeScript&lt;/li&gt;
&lt;li&gt;Moving from &lt;a href="https://www.npmjs.com/package/twit"&gt;twit&lt;/a&gt; to &lt;a href="https://www.npmjs.com/package/twitter-api-v2"&gt;twitter-api-v2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Updating how banning accounts work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The change of updating to TypeScript was one of the major changes the bot went through. At the time I had developed the original Twitter bot, it was written in JavaScript because I grabbed another project (this is the original project I leveraged: &lt;a href="https://github.com/mayeedwin/twitterbot"&gt;https://github.com/mayeedwin/twitterbot&lt;/a&gt;) and I honestly didn’t know any TypeScript at the time. While TypeScript didn’t provide too many advantages over JavaScript for this project, it made the migration from twit to twitter-api-v2 significantly easier.&lt;/p&gt;

&lt;p&gt;The original project I used leveraged twit to bootstrap leveraging the Twitter API. While twit is a pretty good package, my main concern was that it hadn’t been updated in over 4 years as of the time of this writing and I was having a difficulty trying to figure out how to upgrade the bot’s ability to keep certain accounts from being retweeted using it so I felt the need to migrate away. After a bit of searching, I came across twitter-api-v2 which was the second go-to Twitter API package on npm so I felt this would work out. While it didn’t work exactly how I thought it would, it worked in the way I needed and I really appreciate using this package.&lt;/p&gt;

&lt;p&gt;Let’s quickly circle back to a time during the original Twitter’s bot’s deployment. A few months into the bot being brought online, the TechIsHiring hashtag started to gain traction with several notable people starting to use it. The one of the more notable at the time (and whom I am eternally grateful for) is &lt;a href="https://www.twitter.com/Tech__UK"&gt;@Tech__UK&lt;/a&gt;. @Tech__UK was run at the time by &lt;a href="https://www.twitter.com/real_temz"&gt;@real_temz&lt;/a&gt; and &lt;a href="https://www.twitter.com/sham_jab"&gt;@Sham_jab&lt;/a&gt; and they started hosting Twitter Spaces that would last several hours long. They would be so gratuitous to add the hashtag to their Twitter Spaces and several people would tweet the space to share it with their community. At the time, I had set notifications for the TechIsHiring account and for several hours I’d get notifications of people sharing the space, having 20 or 30 notifications by the time their space ended. There were so many people posting to the hashtag that it was trending on Twitter a few times. So you’d think the issue would be the bot tweeting so many notifications and having a problem with that? While there were minor issues there, the main issue and the thing I tried to actively solve for was spam.&lt;/p&gt;

&lt;p&gt;With people seeing #TechIsHiring, a few people decided that it would be a good hashtag to start spamming. There were a few spam accounts that would send tweets about winning or entering a particular contest or something and they’d send that tweet several times, almost 20 or 30 times. This was a problem for a few weeks as I’d sit there and have to painstakingly unlike and unretweet each tweet by hand only to have them send even more a few minutes later. I initially tried to use some Twitter features to either block or report them but nothing seemed to help. They’d just keep on spamming the hashtag. I eventually decided that I’d have to update the bot to ignore these spam accounts. What I ended up doing was hardcoding a list of Twitter IDs that I would ignore to keep the account from being spammed. It's funny because in trying to implement that solution, I actually learned that I had to figure out if the tweet was just a regular tweet or a retweet so that I could properly check each ID and see if they were on the ban list. The implementation wasn’t the best but it worked for now. Its main failing is that to update the list, I would have to manually add a new Twitter ID to the list and redeploy the bot.&lt;/p&gt;

&lt;p&gt;Now coming back to updating the Twitter bot, I wanted to also update the banning mechanism. After poking around, I realized that Twitter had an endpoint that would return a list of Twitter IDs based on accounts that were muted. Originally, I wanted to block the accounts and get a list of IDs from there but this turns out to be a better solution. They can still view the account but when they tweet, it wouldn’t show up. Twitter-api-v2 also made it easy to implement because they had a function that handled sending the request and getting the data back so there wasn’t much work needed from my end. The only other implementation detail that needed to be made was the actual check itself. Originally, I used the includes function in JavaScript arrays to check the IDs before posting. While the list is fairly small, I felt that was slow and could potentially be a performance issue if the list got much larger (though I don’t expect it to). I decided this time around I would put the array in a JavaScript set and use the has function for JavaScript sets which was a much faster lookup.&lt;/p&gt;

&lt;p&gt;And with that I had updated the Twitter bot and had added the functionality of using the mute function of Twitter as a ban list I could leverage from Twitter’s UI. &lt;/p&gt;

&lt;h2&gt;
  
  
  Migration and Deployment
&lt;/h2&gt;

&lt;p&gt;Now with the Twitter bot actually updated, I now needed to find a new place to run the bot. Heroku Dynos was free and I enjoyed not having to pay or really need to think about the bot for a year and a half so my initial requirements was that it was free. I also wanted to keep deployment and maintenance fairly simple as my infrastructure knowledge wasn’t particularly strong so my search started with ‘Heroku alternatives’. There were a few main options I explored:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Render&lt;/li&gt;
&lt;li&gt;DigitalOcean&lt;/li&gt;
&lt;li&gt;Fly.io&lt;/li&gt;
&lt;li&gt;Railway&lt;/li&gt;
&lt;li&gt;Staying on Heroku&lt;/li&gt;
&lt;li&gt;AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I experimented with some of the above options, even getting as far as deploying on them before running into problems. This is when I learned the difference between ‘Web Service’ and ‘Background Worker’. You see I had deployed the bot as a worker on Heroku but didn’t realize what that meant. So several of the free tiers for the above services allowed you to run static sites or web services for free but they wouldn’t allow you to run a background worker for free which is what I needed to run the bot. I learned this fact trying to deploy to Render, seeing the app run and seeing it fail after a few moments of running. After some quick research, I learned the difference and what my needs were. I resigned myself to needing to pay for a service to run a background worker to run the Twitter bot.&lt;/p&gt;

&lt;p&gt;I ultimately decided on DigitalOcean as out of all the options because they were my initial choice before finding out that I couldn’t run a service for free. I figured if I was going to pay for a bot, I’d do it with a more well-known service so it could pump up my resume a bit. I also had some previous experience with them and thought they would be a good fit. After a bit of messing around (the process was surprisingly simple), I deployed the bot and today it’s running on a DigitalOcean Droplet.&lt;/p&gt;

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

&lt;p&gt;And that’s my journey to updating and Migrating the TechIsHiring Twitter bot. If you’re interested in viewing my work, check out the repo here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/TechIsHiring/techishiring-twitter-bot-v2"&gt;https://github.com/TechIsHiring/techishiring-twitter-bot-v2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to critique my work or suggest changes. While the bot is currently meeting my needs, I wouldn’t mind playing around with things to update the bot though I don’t have any ideas. If you want to suggest ideas, please feel free to do so in this article or in the issues of the repo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="https://www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="https://www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re looking for jobs, I’d highly recommend checking out @TechIsHiring on &lt;a href="https://www.twitter.com/techishiring"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/company/techishiring"&gt;LinkedIn&lt;/a&gt; for posted jobs and other resources!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>node</category>
      <category>bot</category>
    </item>
    <item>
      <title>Built a full feature in 6 hours: My experience on how the right tooling can improve your development velocity</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Tue, 20 Sep 2022 00:24:09 +0000</pubDate>
      <link>https://forem.com/opensauced/built-a-full-feature-in-6-hours-my-experience-on-how-the-right-tooling-can-improve-your-development-velocity-2gbd</link>
      <guid>https://forem.com/opensauced/built-a-full-feature-in-6-hours-my-experience-on-how-the-right-tooling-can-improve-your-development-velocity-2gbd</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I’ve been a Front-End Engineer for several years now and have built a wide range of components for a variety of projects. In these various projects, I used different tooling to build components ranging from just having raw HTML, CSS and JavaScript to more modern tooling like React.js and the overall JavaScript ecosystem. Despite this, my development experience remained relatively the same while what mainly grew was the complexity of what I could build. That was until I built onboarding experiences for two different projects in the same year.&lt;/p&gt;

&lt;p&gt;Here’s how tooling vastly changed my development experience and velocity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the app.opensauced.pizza onboarding experience
&lt;/h2&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%2Fv5s56fytd30hsrxic8xv.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%2Fv5s56fytd30hsrxic8xv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the first project’s onboarding experience, I was tasked to build something to replace the previous onboarding. The previous experience felt more disjointed and it was very easy for users to get lost and so another experience was designed and given to me to implement. A lot of the work was developing around the original page as I needed to insert the new experience into the previous page. The hardest part of delivering this project was working with the styling because of how the component was built initially and the general structure of the project. Styles were not packaged together with components and so understanding which style went with which component and adding new styles took a bit of time. It took me a few days and most of the time I spent wrestling with the CSS to get things just right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools used for app.opensauced.pizza project:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Styled Components:
&lt;/h3&gt;

&lt;p&gt;CSS was written in Styled Components. CSS can be tricky to work with including Styled Components because CSS tends to be written in a separate file than the markup you intend to use it in. This increases the cognitive load on the developer by forcing them to understand which CSS rules are applied to which component. If you were writing raw CSS then selecting the correct HTML element would be required and can also be painful but Styled Components allowed us to create the component with the Styles and just leverage it directly so we don’t have to deal with that.&lt;/p&gt;

&lt;h3&gt;
  
  
  React.js:
&lt;/h3&gt;

&lt;p&gt;Want to note that this is a React 17 project. This doesn’t affect the experience directly as the other project I describe also leverages React 17, I wanted to bring this up for full transparency.&lt;/p&gt;

&lt;h2&gt;
  
  
  My overall experience working on app.opensauced.pizza:
&lt;/h2&gt;

&lt;p&gt;This wasn’t that bad of an experience at all, just a standard Front-End development experience. The biggest difficulty was working with the CSS, using Styled Components and the locations of the styling. Outside of that, I’d say the experience was okay but uneventful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the OpenSauced Insights Platform onboarding experience
&lt;/h2&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%2F93izuem70i9abpxeybu6.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%2F93izuem70i9abpxeybu6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the second project, I was building an onboarding feature for a much more greenfield project. In this case, I was implementing an onboarding feature which was brand-new and was independent of any other design for the rest of the project so I had to spin up a new page to build it and so I got to work. Started a new page and quickly got to work styling the page. The interesting part of this onboarding experience was that the page was split into two where one half would track your progress in onboarding and the other half would change based on which step you were on. I remember starting the page at around 12 pm and working through it, quickly solving any problem that came up and progressing. A few hours later the page was completed. A few more hours of tweaking brought the total dev time to around 6 hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools used for OpenSauced Insights Platform project:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Component-Driven Design:
&lt;/h3&gt;

&lt;p&gt;For this project we practiced Component-Driven Design. A quick synopsis would be that instead of building a page from top-level down, we build the components that make up the page first and then put them together like Legos. Component-Driven Design is best paired with a Design System that gives you a selection of components that you can use to put together pages quickly and make changes quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atomic Design Design System
&lt;/h3&gt;

&lt;p&gt;To effectively leverage Component-Driven Design, we used the Atomic Design Design System to break up our components into atoms, molecules and organisms allowing us to get the Lego-feel of building components and ultimately assembling pages brick by brick.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storybook:
&lt;/h3&gt;

&lt;p&gt;To document our design system, we leverage Storybook in our project. This allows us to quickly look at what is available in our design system, assess what we need and put together components and ultimately pages quickly and easily. What we also do with Storybook is that the Storybook environment allows us to build components in isolation. Using Storybook, we can build components without interfering with the rest of the project and potentially introduce bugs or issues. Once we are confident in our components, we place them on the page where we need them and add the necessary data to power them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tailwind CSS:
&lt;/h3&gt;

&lt;p&gt;Tailwind CSS makes styling a page quick and easy. Just apply the css class that you need and Tailwind classes will take care of the rest. Another key part of the benefit of Tailwind CSS is that it keeps your css isolated in the component that relies on it. This relieves one of the biggest pain points of CSS, accurately selecting and styling ONLY the classes YOU WANT. This is especially handy when you are building components in isolation in Storybook and having confidence your CSS won’t mess with the rest of the project once implemented. &lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript:
&lt;/h3&gt;

&lt;p&gt;TypeScript and the intellisense that it gives through the proper use of types is probably the most valuable tools a developer could have when building a project with a very established design system. If a component is properly built, the component effectively documents itself and (depending on your IDE of choice) presents that documentation at the most crucial part of development, when you are actually implementing the component. This saves hours of development time in making sure you’re using the component correctly and reducing errors in implementation before it can get to production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js:
&lt;/h3&gt;

&lt;p&gt;Our project is built with Next.js, which allows us to put together a Single-Page application quickly with all the tooling needed to make that application functional. While this has been invaluable in building the overall project quickly, it wasn’t a direct benefit in building this particular feature. For full transparency, our Next project leveraged React 17.&lt;/p&gt;

&lt;h2&gt;
  
  
  My overall experience working on the Insights Platform:
&lt;/h2&gt;

&lt;p&gt;This was a far better Front-End development experience, from the time it took for me to complete this to its readability and maintainability. While this was a far more complex onboarding experience, the amount of code to make it work was comparable. It was 100 more lines of code than the previous experience but it was to build a completely new web page from scratch! Unlike the previous experience, styling wasn’t a pain point at all and honestly, I can’t think of any real pain points on this project. Probably the reason why I flew through it so quickly&lt;/p&gt;

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

&lt;p&gt;Overall, I love the dev experience with working with the tooling I am working with currently. I do feel I should bring up some caveats that I didn’t not cover in this post. While the new code I wrote was 100 more lines of code than my previous project, there was a lot more knowledge and infrastructure being brought to bear to complete this task that existed previously. Setting up that infrastructure and then getting used to that workflow takes time but let this story be an example of what you can accomplish and how quickly you can accomplish it with the right tools in place.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you found this article interesting, please feel free to heart this article!&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="//www.dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="//www.twitter.com/chad_r_stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about OpenSauced, follow OpenSauced here on &lt;a href="//www.dev.to/opensauced"&gt;Dev.to&lt;/a&gt; and on &lt;a href="//www.twitter.com/saucedopen"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>react</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Set up a Next.js project with TypeScript, Tailwind and Storybook</title>
      <dc:creator>Chad R. Stewart</dc:creator>
      <pubDate>Wed, 07 Sep 2022 19:14:50 +0000</pubDate>
      <link>https://forem.com/opensauced/set-up-a-nextjs-project-with-typescript-tailwind-and-storybook-3j1k</link>
      <guid>https://forem.com/opensauced/set-up-a-nextjs-project-with-typescript-tailwind-and-storybook-3j1k</guid>
      <description>&lt;p&gt;Next.js is a popular framework built on top of React that allows users to build React applications quickly and easily. At OpenSauced, we are working on a new project that leverages Next.js and Tailwind CSS. For this project we also wanted to build a design system to support this project and, potentially in the future, other OpenSauced projects.&lt;/p&gt;

&lt;p&gt;To that end, we also decided to leverage Storybook to document our design system. Unfortunately, setting up Storybook with Next.js and Tailwind is not trivial and it took us some time to get things working properly. This article is for those looking to stand up a similar project and need help setting things up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Setting up the Next Tailwind CSS project&lt;/li&gt;
&lt;li&gt;Installing Storybook&lt;/li&gt;
&lt;li&gt;Configuring Storybook to use Tailwind&lt;/li&gt;
&lt;li&gt;Configuring Storybook to use Next&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up the Next Tailwind CSS project
&lt;/h2&gt;

&lt;p&gt;Thankfully this part is fairly simple. To stand up a new Next.js project with Tailwind, 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;npx create-next-app &lt;span class="nt"&gt;-e&lt;/span&gt; with-tailwindcss next-tailwind-storybook-example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: The last keyword will be the name of your project.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create-next-app will stand up a new Next.js project in TypeScript with Tailwind already pre-installed. Once the setup is completed, you can navigate to the folder where your Next.js project has been set up and run the command &lt;code&gt;npm run dev&lt;/code&gt; to start the Next.js dev server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;next-tailwind-storybook-example
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will let you view the project at &lt;a href="http://localhost:3000"&gt;localhost:3000&lt;/a&gt; which will give you Next.js’s starter screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Storybook
&lt;/h2&gt;

&lt;p&gt;To set up Storybook within the Next.js project, 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;npx &lt;span class="nt"&gt;-y&lt;/span&gt; sb init &lt;span class="nt"&gt;--builder&lt;/span&gt; webpack5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initialize a new Storybook installation. It will automatically detect which type of application you are working on (in this case React) and install the necessary dependencies to get Storybook up and running.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: If you are using a version of npm above npm7, Storybook will ask if you would like to run the npm7 migration. Press ‘y’ to answer yes to run the migration. If you do not do this, you will have issues installing the other packages needed to continue this set up. If you skip this step by accident, run &lt;code&gt;npx storybook@next automigrate&lt;/code&gt; to run the migration.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the installation, you will be able to run Storybook. To run Storybook, use the command &lt;code&gt;npm run storybook&lt;/code&gt; and open &lt;a href="http://localhost:6006"&gt;localhost:6006&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 run storybook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outside of necessary config files, Storybook gives you starter stories to give you an idea of how to use it. Unfortunately, Storybook is not configured to use Tailwind out of the box and so we have to manually set that up ourselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Storybook to use Tailwind
&lt;/h2&gt;

&lt;p&gt;To use Tailwind in Storybook, you’ll need to install an addon so that Storybook knows how to use Tailwind. First, run this command to download the addon to your 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 i &lt;span class="nt"&gt;-D&lt;/span&gt; @storybook/addon-postcss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the download is completed, open &lt;code&gt;.storybook/main.js&lt;/code&gt; in your Next.js project folder. This is a config file for Storybook and where you can install new addons to your project. In the &lt;code&gt;addons&lt;/code&gt; array, add &lt;code&gt;@storybook/addon-postcss&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;// .storybook/main.js&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stories&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="s2"&gt;../stories/**/*.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="s2"&gt;../stories/**/*.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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addons&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="s2"&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="s2"&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="s2"&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="s2"&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="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;framework&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;@storybook/react&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;core&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="s2"&gt;builder&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;@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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will allow Storybook to use this addon. Now open &lt;code&gt;.storybook/preview.js&lt;/code&gt; in your Next.js project folder. At the beginning of the file, add &lt;code&gt;import "../styles/globals.css"&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;// .storybook/preview.js&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;../styles/globals.css&lt;/span&gt;&lt;span class="dl"&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="s2"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: &lt;code&gt;globals.css&lt;/code&gt; is a CSS file for Tailwind. If you have another file or have moved this file to a new location, you’ll need to import that file from the location you’ve moved it to.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you can run Storybook and you’ll be able to render components with Tailwind classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Storybook to use Next
&lt;/h2&gt;

&lt;p&gt;Out of the box, Storybook will not be able to use Next-specific components and features, making the components work incorrectly when you try to view them in Storybook.&lt;/p&gt;

&lt;p&gt;Fortunately, Storybook has provided an addon that allows us to use Next.js features within Storybook. First, you’ll need to download the addon. 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;npm i storybook-addon-next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once it is completed, return to &lt;code&gt;.storybook/main.js&lt;/code&gt; in your Next.js project. In the &lt;code&gt;addons&lt;/code&gt; array, similar to where you installed the previous addon, add &lt;code&gt;storybook-addon-next&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;// .storybook/main.js&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stories&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="s2"&gt;../stories/**/*.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="s2"&gt;../stories/**/*.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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addons&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="s2"&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="s2"&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="s2"&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="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;storybook-addon-next&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="s2"&gt;framework&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;@storybook/react&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;core&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="s2"&gt;builder&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;@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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you were to run Storybook with &lt;code&gt;npm run storybook&lt;/code&gt;, you’d get an error from TypeScript saying that &lt;code&gt;baseUrl&lt;/code&gt; is missing from &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 plaintext"&gt;&lt;code&gt;Found no baseUrl in tsconfig.json, not applying tsconfig-paths-webpack-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line was not automatically added to the &lt;code&gt;tsconfig.json&lt;/code&gt; file when the project was first stood up. Since it needs to be added manually, open &lt;code&gt;tsconfig.json&lt;/code&gt; and add &lt;code&gt;"baseUrl": "./",&lt;/code&gt; under &lt;code&gt;compilerOptions&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;"./"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"es5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lib"&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;"dom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dom.iterable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esnext"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowJs"&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;"skipLibCheck"&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;"strict"&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;"forceConsistentCasingInFileNames"&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;"noEmit"&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;"esModuleInterop"&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;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esnext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"moduleResolution"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resolveJsonModule"&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;"isolatedModules"&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;"jsx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"preserve"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"incremental"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&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-env.d.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"**/*.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"**/*.tsx"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exclude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"node_modules"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="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’s it! You’ve now completed setting up a new Next.js project with Tailwind and Storybook! If you have any trouble, you can check out this repo to see a completed Next.js Tailwind Storybook set up here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chadstewart/next-tailwind-storybook-example"&gt;&lt;code&gt;Completed Next.js TypeScript Tailwind CSS Storybook Example Repo&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you found this article helpful, please feel free to heart this article!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you’re interested in learning more about Front-End Engineering, follow me here on &lt;a href="https://dev.to/chad_r_stewart"&gt;Dev.to&lt;/a&gt; and &lt;a href="https://www.twitter.com/Chad_R_Stewart"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you’re interested in learning more about OpenSauced, follow OpenSauced here on &lt;a href="https://dev.to/opensauced"&gt;Dev.to&lt;/a&gt; and on &lt;a href="https://www.twitter.com/saucedopen"&gt;Twitter&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>tailwindcss</category>
      <category>nextjs</category>
      <category>storybook</category>
    </item>
  </channel>
</rss>
