<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Asa Smith</title>
    <description>The latest articles on DEV Community by Asa Smith (@asasmith).</description>
    <link>https://dev.to/asasmith</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%2F60403%2F606adba6-7222-4ec6-ad55-1a2d45fee37d.jpeg</url>
      <title>DEV Community: Asa Smith</title>
      <link>https://dev.to/asasmith</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/asasmith"/>
    <language>en</language>
    <item>
      <title>Cloud Resume Challenge Week 2</title>
      <dc:creator>Asa Smith</dc:creator>
      <pubDate>Tue, 22 Apr 2025 15:22:00 +0000</pubDate>
      <link>https://dev.to/asasmith/cloud-resume-challenge-week-2-344e</link>
      <guid>https://dev.to/asasmith/cloud-resume-challenge-week-2-344e</guid>
      <description>&lt;p&gt;Since my last update on the Cloud Resume Challenge, I've made several significant changes, resolved some unexpected problems, and refined my overall infrastructure strategy. Here's a detailed overview of my recent progress:&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagnosing a Certificate Issue (Not Just a Validation Problem)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Initial Problem:&lt;/strong&gt;&lt;br&gt;
Initially, I suspected my AWS ACM certificate issue was related to DNS validation delays. However, after deeper investigation, I discovered the actual issue stemmed from changing a resource name in my CDK code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Actually Happened:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I updated the logical name of my ACM certificate resource within my CDK stack. Although this change seemed minor, it led to unforeseen conflicts with CloudFormation, resulting in confusing errors that were not immediately apparent.&lt;/li&gt;
&lt;li&gt;The subtle nature of this issue complicated troubleshooting because CloudFormation events didn't clearly indicate the root cause. This scenario reinforced the importance of careful naming practices when working with infrastructure as code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resolving the Issue by Manual Deletion and Redeployment
&lt;/h2&gt;

&lt;p&gt;After pinpointing the issue as a naming conflict, the fastest and most straightforward resolution was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manually deleting the entire CloudFormation stack to ensure all conflicting resources were fully removed.&lt;/li&gt;
&lt;li&gt;Redeploying the stack using &lt;code&gt;cdk deploy&lt;/code&gt;, which cleanly rebuilt my S3 bucket, CloudFront distribution, and ACM certificate without conflicts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Good Naming Conventions Matter
&lt;/h2&gt;

&lt;p&gt;This experience highlights the critical importance of consistent, clear, and stable naming conventions from the outset:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changing resource names later in development can result in subtle but significant infrastructure conflicts.&lt;/li&gt;
&lt;li&gt;Establishing good naming conventions early significantly simplifies troubleshooting and prevents hard-to-diagnose issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Completing DNS Validation and Attaching the Certificate
&lt;/h2&gt;

&lt;p&gt;Since my domain (&lt;code&gt;asasmith.dev&lt;/code&gt;) is managed externally with Hover, I chose manual DNS validation instead of using Route53:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After I redeployed my stack I used the following cli command to get a list of certificates:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  aws acm list certificates &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Then using the cert's arn and another cli command I was able to get the dns validation info:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  aws acm describe-certificate &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="nt"&gt;--certificate-arn&lt;/span&gt; &amp;lt;CERTIFICATE_ARN&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;I added the required CNAME record in Hover’s DNS settings.&lt;/li&gt;
&lt;li&gt;Verified DNS propagation, and my ACM certificate status quickly transitioned to &lt;code&gt;ISSUED&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have since successfully attached this validated ACM certificate to my CloudFront distribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping a Subdomain to CloudFront
&lt;/h2&gt;

&lt;p&gt;Additionally, I've configured Hover to map the subdomain &lt;code&gt;resume.asasmith.dev&lt;/code&gt; directly to my CloudFront distribution, ensuring visitors can securely access my static resume site using HTTPS. I've confirmed that the subdomain is functioning exactly as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single-Stack Infrastructure Approach
&lt;/h2&gt;

&lt;p&gt;Previously, I organized my CDK project into multiple stacks based on resource types, complicating dependency management and debugging. Now, I've transitioned to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A single, unified stack containing all the necessary resources for my static website.&lt;/li&gt;
&lt;li&gt;Simpler management, clearer resource dependencies, and easier troubleshooting.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Naming conventions:&lt;/strong&gt; Good, stable, and descriptive naming upfront is essential for avoiding subtle infrastructure conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual resource cleanup:&lt;/strong&gt; Sometimes deleting and redeploying resources completely is the most efficient path forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure consolidation:&lt;/strong&gt; Keeping related resources in a single stack simplifies operations and debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;With my static website fully operational, the next phase includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defining and deploying a DynamoDB table to store visitor data.&lt;/li&gt;
&lt;li&gt;Creating a Lambda function to interact with DynamoDB (I'm currently considering which programming language to use).&lt;/li&gt;
&lt;li&gt;Setting up API Gateway to provide an endpoint to my Lambda function—this will be a learning experience as I haven't worked with API Gateway before.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned for further updates as I continue building out and enhancing my Cloud Resume project!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>typescirpt</category>
    </item>
    <item>
      <title>Cloud Resume Challenge Week 1</title>
      <dc:creator>Asa Smith</dc:creator>
      <pubDate>Tue, 22 Apr 2025 15:06:00 +0000</pubDate>
      <link>https://dev.to/asasmith/cloud-resume-challenge-week-1-58a0</link>
      <guid>https://dev.to/asasmith/cloud-resume-challenge-week-1-58a0</guid>
      <description>&lt;p&gt;Recently I across the &lt;a href="https://cloudresumechallenge.dev/docs/the-challenge/aws/" rel="noopener noreferrer"&gt;Cloud Resume Challenge&lt;/a&gt;, and it immediately caught my attention. I’ve been looking for opportunities to get more hands-on experience with AWS, but I haven’t had a structured way to approach it. This challenge seemed like the perfect opportunity—a real-world, end-to-end cloud project that touches multiple AWS services. So, I decided to jump in.&lt;/p&gt;

&lt;p&gt;This post is a brain dump of why I’m doing this, what I hope to get out of it, and my progress so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm Doing the Cloud Resume Challenge
&lt;/h2&gt;

&lt;p&gt;For majority of my career I've focused solely on front end development. I've done some backend work with node/express and one time I built a data collection tool in Go. But AWS has, for the most part, been a total black box to me. I know what an s3 bucket is and I have a grasp of iam roles. I can even dig through logs in cloudwatch to try to find errors but that's been the extent of my exposure. but I’ve never actually built something from the ground up using AWS infrastructure as code, IAM roles, API Gateway, Lambda, and DynamoDB.&lt;br&gt;&lt;br&gt;
So I'm doing this challenge for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To get hands-on AWS experience—I learn best by doing, and this is as close to a real-world project as it gets.&lt;/li&gt;
&lt;li&gt;To force myself out of my comfort zone—I know enough AWS to be dangerous, but I'd like to actually understand it.&lt;/li&gt;
&lt;li&gt;To document my progress and mistakes—I want to write about this experience as I go, partly to help others, partly to remind future me what I did when I inevitably forget.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Week 1: What I've Done So far
&lt;/h2&gt;

&lt;p&gt;Even though this project is relatively simple I want to be mindful of creating an architecture that is representative of real world applications. So while it might be overkill for this I knew I wanted to create three repos for code organization.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cloud-resume-infra&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cloud-resume-frontend&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cloud-resume-backend&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the requirements is to not use the AWS console to create any of the necessary resources. I have completed a Frontend Masters course that used AWS CDK (cloud deployment kit) with GO so I already had some exposure to the tool. I chose to use typescript for this project. AWS SAM (serverless application model) templates are another route you could go but since I've never used these before I decided to not use them here. Documentation for CDK can be found &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/home.html" rel="noopener noreferrer"&gt;here&lt;/a&gt; along with a guide for install/setup &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;br&gt;
CDK, as I understand it so far, allows you to write code to define different aws resources. Initializing a project is simple. Just run the following commands in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// create a new empty directory &lt;span class="k"&gt;for &lt;/span&gt;the project
&lt;span class="nb"&gt;mkdir &lt;/span&gt;cloud-resume-infra &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;cloud-resume-infra 

// initialize new cdk app specifying typescript as the language
cdk init app &lt;span class="nt"&gt;--language&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A CDK app is composed of several differnt units. The smallest units are constructs. Constructs are pieced together to create Stacks. Stacks are pieced together to create Apps. The CDK cli tool takes your code an converts it into CloudFormation templates that are deployed from the command line.&lt;/p&gt;

&lt;p&gt;The first thing I did was create my &lt;code&gt;S3Stack&lt;/code&gt;. All I've done is create an s3 bucket to store my static website files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&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;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;constructs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;s3&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;aws-cdk-lib/aws-s3&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;class&lt;/span&gt; &lt;span class="nc"&gt;S3Stack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CloudResumeInfraBucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`cloud-resume-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;blockPublicAccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BlockPublicAccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BLOCK_ALL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;removalPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RemovalPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DESTROY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I've updated the &lt;code&gt;bin/cloud-resume-infra.ts&lt;/code&gt; file to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cp"&gt;#!/usr/bin/env node
&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source-map-support/register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;S3Stack&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../lib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&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;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cloud-resume&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;S3Stack&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-s3-stack`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

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

&lt;/div&gt;



&lt;p&gt;Once I've saved both files I need to run &lt;code&gt;npm run build&lt;/code&gt; to build out the javascript files and then run &lt;code&gt;cdk deploy&lt;/code&gt; to deploy my s3 bucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Steps
&lt;/h2&gt;

&lt;p&gt;Now that I have the initial CDK setup and an S3 bucket, my next steps are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up IAM roles and policies – I need to make sure my GitHub Actions workflow has the right permissions to deploy site updates.&lt;/li&gt;
&lt;li&gt;Automate frontend deployments – I’ll configure GitHub Actions to upload new frontend files to S3 whenever I push to main.&lt;/li&gt;
&lt;li&gt;Start planning the backend – I’ll be working on API Gateway, Lambda, and DynamoDB next.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For future posts, I’ll break things down further—IAM setup, GitHub Actions workflows, API design, and more. But for now, this is a solid start.&lt;/p&gt;

&lt;p&gt;Here is my &lt;code&gt;cloud-resume-infra&lt;/code&gt; &lt;a href="https://github.com/asasmith/cloud-resume-infra" rel="noopener noreferrer"&gt;repo&lt;/a&gt; for reference.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>typescirpt</category>
    </item>
    <item>
      <title>Technical Interview Questions I Wish I Could Do Over #1</title>
      <dc:creator>Asa Smith</dc:creator>
      <pubDate>Tue, 22 Apr 2025 14:48:00 +0000</pubDate>
      <link>https://dev.to/asasmith/technical-interview-questions-i-wish-i-could-do-over-1-l88</link>
      <guid>https://dev.to/asasmith/technical-interview-questions-i-wish-i-could-do-over-1-l88</guid>
      <description>&lt;p&gt;Technical interviews are the adult equivalent of those big test days we had in&lt;br&gt;
grade school that would determine our academic future. They’re challenging to&lt;br&gt;
prepare for because sometimes I know ahead of time what the topic will be&lt;br&gt;
(system design lite) and other times it’s a surprise I learn once I’m in the&lt;br&gt;
interview (build an infinite scroll in react), and there’s almost always&lt;br&gt;
something I wish I could do over after I finish.&lt;/p&gt;

&lt;p&gt;This series is intended to be part therapeutic, part knowledge share: a place to&lt;br&gt;
break down questions I wish I could do over. Whether you're prepping for&lt;br&gt;
interviews, brushing up on fundamentals, or just enjoy a bit of technical&lt;br&gt;
storytelling, I hope these posts are useful and maybe even a little cathartic.&lt;br&gt;
Who knows, maybe I'll write about technical interviews I do well in too.&lt;/p&gt;
&lt;h2&gt;
  
  
  What will be the output of the following code and why?
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setTimeoutFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;firstPromiseFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;promise 1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;asyncFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;async start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;async end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;asyncFunc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After taking a minute to read through the code this was my response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;start, timeout, promise 1, async start, end, async end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual output is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;start, async start, end, promise 1, async end, timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I misunderstood two big parts of the execution model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how &lt;code&gt;setTimeout&lt;/code&gt; and &lt;code&gt;setInterval&lt;/code&gt; are handled, even when passed &lt;code&gt;0&lt;/code&gt; to their
delay argument&lt;/li&gt;
&lt;li&gt;the microtask queue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are three key parts to the JavaScript execution model: the &lt;code&gt;Call Stack&lt;/code&gt;,&lt;br&gt;
the &lt;code&gt;Microtask Queue&lt;/code&gt;, and the &lt;code&gt;Task Queue&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;| Call Stack | Microtask Queue | Task Queue |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the program runs the first line it evaluates is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This operation is added to the &lt;code&gt;Call Stack&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;|    Call Stack      | Microtask Queue | Task Queue |
|       ---          |     ---         |    ---     |
|console.log('start')|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this operation is synchronous it is executed immediately and removed from&lt;br&gt;
the stack. So we see &lt;code&gt;start&lt;/code&gt; logged and the &lt;code&gt;Call Stack&lt;/code&gt; returns to its previous&lt;br&gt;
state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|    Call Stack      | Microtask Queue | Task Queue |
|       ---          |     ---         |    ---     |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty simple so far.&lt;/p&gt;

&lt;p&gt;The next line evaluated is the &lt;code&gt;setTimeout&lt;/code&gt;. Here I assumed the &lt;code&gt;setTimeout&lt;/code&gt;&lt;br&gt;
would be added to the &lt;code&gt;Call Stack&lt;/code&gt;, the timer started, and since it was &lt;code&gt;0&lt;/code&gt;, the&lt;br&gt;
callback function would be executed immediately. But what really happens is the&lt;br&gt;
callback function (&lt;code&gt;setTimeoutFunc()&lt;/code&gt;) is added to the &lt;code&gt;Task Queue&lt;/code&gt; and the&lt;br&gt;
program moves to the next line to evaluate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|    Call Stack   | Microtask Queue |     Task Queue  |
|       ---       |     ---         |        ---      |
|                 |                 | setTimeoutFunc()|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next block of code that is evaluated is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Promise.resolve().then(function firstPromiseFunc() {
    console.log('promise 1');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this is an asynchronous function it is added to the &lt;code&gt;Microtask Queue&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;|    Call Stack   | Microtask Queue |     Task Queue  |
|       ---       |     ---         |        ---      |
|                 |firstPromisFunc()| setTimeoutFunc()|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the program moves to the next lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function asyncFunc() {
    console.log('async start');
    await Promise.resolve();
    console.log('async end');
}

asyncFunc();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;asyncFunc()&lt;/code&gt; is added to the call stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|    Call Stack   | Microtask Queue |     Task Queue  |
|       ---       |     ---         |        ---      |
|    asyncFunc()  |firstPromisFunc()| setTimeoutFunc()|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first &lt;code&gt;console.log&lt;/code&gt; statement is synchronous so it is executed logging&lt;br&gt;
&lt;code&gt;async start&lt;/code&gt; and then the program gets to the &lt;code&gt;await&lt;/code&gt; keyword. &lt;code&gt;await&lt;/code&gt; is&lt;br&gt;
syntactic sugar for native Promises so the event loop treats this the same way&lt;br&gt;
it did the previous &lt;code&gt;Promise&lt;/code&gt;, the &lt;code&gt;console.log('async end')&lt;/code&gt; is scheduled in&lt;br&gt;
the Microtask Queue, and at that point, &lt;code&gt;asyncFunc()&lt;/code&gt; is paused and removed from&lt;br&gt;
the call stack. Its remaining execution (everything after the await) will resume&lt;br&gt;
in the microtask phase of the event loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|    Call Stack   |     Microtask Queue    |     Task Queue  |
|       ---       |          ---           |        ---      |
|                 |firstPromisFunc()       | setTimeoutFunc()|
|                 |console.log('async end')|                 |                 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program then moves on to the last line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log('end');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and since this is a synchronous operation it is added to the stack and executed&lt;br&gt;
immediately.&lt;/p&gt;

&lt;p&gt;The end of the program has been reached so the event loop moves to the&lt;br&gt;
&lt;code&gt;Microtask Queue&lt;/code&gt;. The &lt;code&gt;Task Queue&lt;/code&gt; and the &lt;code&gt;Microtask Queue&lt;/code&gt; both operate on a&lt;br&gt;
First in, First out basis. For my example, &lt;code&gt;firstPromiseFunc()&lt;/code&gt; was added to the&lt;br&gt;
queue first so it is executed first and &lt;code&gt;promise 1&lt;/code&gt; is logged. Then&lt;br&gt;
&lt;code&gt;firstPromiseFunc()&lt;/code&gt; is removed from the queue. The event loop checks to see if&lt;br&gt;
there are any tasks left in the &lt;code&gt;Microtask Queue&lt;/code&gt; and since there is it is&lt;br&gt;
executed next and we see &lt;code&gt;async end&lt;/code&gt; logged.&lt;/p&gt;

&lt;p&gt;Now that the &lt;code&gt;Microtask Queue&lt;/code&gt; is empty the event loop moves to the &lt;code&gt;Task Queue&lt;/code&gt;&lt;br&gt;
and executes tasks on the same First in, First out basis. For this example we&lt;br&gt;
now see &lt;code&gt;timeout&lt;/code&gt; logged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Timer functions, &lt;code&gt;setTimeout&lt;/code&gt; and &lt;code&gt;setInterval&lt;/code&gt;, never run immediately. Even
if the delay argument is &lt;code&gt;0&lt;/code&gt;. The callbacks are added to the &lt;code&gt;Task Queue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;All async code, anything wrapped in a &lt;code&gt;Promise&lt;/code&gt; or that comes after &lt;code&gt;await&lt;/code&gt;,
is added to the &lt;code&gt;Microtask Queue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The tasks in the &lt;code&gt;Microtask Queue&lt;/code&gt; will be executed before the event loop
moves to the &lt;code&gt;Task Queue&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This question reminded me how important it is to understand not just what&lt;br&gt;
JavaScript does, but when it does it. Before this technical interview I would've&lt;br&gt;
said I had a good mental model of how async code works but realizing how the&lt;br&gt;
microtask and task queues work helped me connect a few lingering gaps. Now that&lt;br&gt;
I’ve internalized the way the event loop processes Promises, async/await, and&lt;br&gt;
setTimeout/setInterval, I’ll be more confident when questions like this come up.&lt;/p&gt;

&lt;p&gt;Next up: a question I actually nailed and how I approached it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model" rel="noopener noreferrer"&gt;MDN JavaScript execution model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide/In_depth" rel="noopener noreferrer"&gt;MDN In Depth: Microtasks and the JavaScript runtime environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jsv9000.app/?code=Y29uc29sZS5sb2coJ3N0YXJ0JykKCnNldFRpbWVvdXQoZnVuY3Rpb24gdGltb3V0RnVuYygpIHsKICBjb25zb2xlLmxvZygndGltZW91dCcpCn0sIDApCgpQcm9taXNlLnJlc29sdmUoKS50aGVuKGZ1bmN0aW9uIGZpcnN0UHJvbWlzZUZ1bmMoKSB7CiAgY29uc29sZS5sb2coJ3Byb21pc2UgMScpCn0pCgpmdW5jdGlvbiB0ZXN0KCkgewogIGNvbnNvbGUubG9nKCdhc3luYyBzdGFydCcpCiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oZnVuY3Rpb24gc2Vjb25kUHJvbWlzZUZ1bmMoKSB7CiAgICBjb25zb2xlLmxvZygnYXN5bmMgZW5kJykgIAogIH0pCn0KCnRlc3QoKTsKCmNvbnNvbGUubG9nKCdlbmQnKQ%3D%3D" rel="noopener noreferrer"&gt;JavaScript Visualizer 9000&lt;/a&gt;
(There seems to be an issue with the &lt;code&gt;await&lt;/code&gt; keyword in the JavaScript)
visualizer so I've rewritten that code using &lt;code&gt;Promise&lt;/code&gt;. I've also added a
&lt;code&gt;log&lt;/code&gt; function to help with the visualization)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>technicalinterview</category>
    </item>
    <item>
      <title>Using Tailwind CSS v3 with Ember JS</title>
      <dc:creator>Asa Smith</dc:creator>
      <pubDate>Tue, 11 Jan 2022 15:36:17 +0000</pubDate>
      <link>https://dev.to/asasmith/using-tailwind-css-v3-with-ember-js-37j9</link>
      <guid>https://dev.to/asasmith/using-tailwind-css-v3-with-ember-js-37j9</guid>
      <description>&lt;p&gt;Tailwind CSS v3 has been released and there is a bunch of cool new features available (I'm mostly interested in the "just in time" engine being standard now). The standard setup for an ember project has changed a little and there doesn't seem to be a lot of good resources available for this setup.&lt;/p&gt;

&lt;p&gt;Create a new ember project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx ember-cli new tailwindcss-demo &lt;span class="nt"&gt;--no-welcome&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;tailwindcss-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install tailwind and related packages.&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;tailwindcss autoprefixer &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;span class="c"&gt;# no need for purgecss anymore&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install postcss add on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ember &lt;span class="nb"&gt;install &lt;/span&gt;ember-cli-postcss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create tailwind config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# I create a tailwind dir in styles and add the config file there&lt;/span&gt;
&lt;span class="c"&gt;# this is a personal organizational choice, the config file could live anywhere&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;app/styles/tailwind

&lt;span class="c"&gt;# create tailwind config file&lt;/span&gt;
&lt;span class="c"&gt;# last arg is path to config file&lt;/span&gt;
&lt;span class="c"&gt;# if no arg is provided it will be created at the root of your project&lt;/span&gt;
&lt;span class="c"&gt;# this path will be needed when updating ember-cli-build.js&lt;/span&gt;
npx tailwind init app/styles/tailwind/config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There isn't a &lt;code&gt;purge&lt;/code&gt; key in the config file anymore. Update the &lt;code&gt;content&lt;/code&gt; key with paths to all template files. The config docs are &lt;a href="https://tailwindcss.com/docs/content-configuration" rel="noopener noreferrer"&gt;here&lt;/a&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;// app/styles/tailwind/config.js&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app/**/*.hbs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update &lt;code&gt;app/styles/app.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* app/styles/app.css */&lt;/span&gt;

&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update &lt;code&gt;ember-build-cli.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ember-build-cli.js&lt;/span&gt;

&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&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;EmberApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember-cli/lib/broccoli/ember-app&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;autoprefixer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;autoprefixer&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;tailwind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmberApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;postcssOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// track changes in template, css, scss, and tailwind config files&lt;/span&gt;
        &lt;span class="na"&gt;cacheInclude&lt;/span&gt;&lt;span class="p"&gt;:&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;css|scss|hbs&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sr"&gt;/.tailwind&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;config&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;js$/&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;autoprefixer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tailwind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app/styles/tailwind/config.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toTree&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;That's it. You should be up and running with Ember and Tailwind now!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/asasmith/tailwindcss-v3-ember" rel="noopener noreferrer"&gt;Repo&lt;/a&gt; for this demo.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ember</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>How to use ember-cli to generate components using pod structure</title>
      <dc:creator>Asa Smith</dc:creator>
      <pubDate>Thu, 03 Dec 2020 23:59:11 +0000</pubDate>
      <link>https://dev.to/asasmith/how-to-use-ember-cli-to-generate-components-using-pod-structure-1i6l</link>
      <guid>https://dev.to/asasmith/how-to-use-ember-cli-to-generate-components-using-pod-structure-1i6l</guid>
      <description>&lt;p&gt;The answer to the question above is &lt;code&gt;ember generate component component-name --pods --no-path&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Maybe I should back up a bit.&lt;/p&gt;

&lt;p&gt;I've been working on an ember project full time for about a year now. I definitely prefer the &lt;em&gt;pods&lt;/em&gt; style file layout to the &lt;em&gt;classic&lt;/em&gt; style.&lt;/p&gt;

&lt;p&gt;If you're unfamiliar, &lt;em&gt;classic&lt;/em&gt; style file structure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/
|-- components/
    |-- tags.js
    |-- tags.hbs
|-- controllers/
    |-- post.js
|-- models/
    |-- post.js
|-- routes/
    |-- post.js
|-- templates/
    |-- post.js
|-- app.js
|-- index.html
|-- router.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;while &lt;em&gt;pods&lt;/em&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/
|-- components/
    |-- tags.js
    |-- tags.hbs
|-- post/
    |--controller.js
    |--route.js
    |--template.js
|-- app.js
|-- index.html
|-- router.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;pod&lt;/em&gt; structure organizes the file system by feature instead of by entity type which I think is much easier to reason about and navigate.&lt;/p&gt;

&lt;p&gt;You can use the &lt;code&gt;ember-cli&lt;/code&gt; to scaffold out files for: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;routes&lt;/li&gt;
&lt;li&gt;controllers&lt;/li&gt;
&lt;li&gt;templates&lt;/li&gt;
&lt;li&gt;ember-data files &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The command &lt;code&gt;ember generate entity-type feature-name&lt;/code&gt; would scaffold out the correct file in the correct directory. If you want to use the &lt;em&gt;pod&lt;/em&gt; structure you have to pass the &lt;code&gt;--pods&lt;/code&gt; option to the &lt;code&gt;ember generate&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ember generate route feature-name&lt;/code&gt; would generate a new &lt;code&gt;route.js&lt;/code&gt; file inside the &lt;code&gt;feature-name&lt;/code&gt; directory. If the directory didn't exist it would be created. This command will also generate a test file at &lt;code&gt;tests/unit/feature-name/route-test.js&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;You can also update the &lt;code&gt;.ember-cli&lt;/code&gt; config file like so&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.ember-cli&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;"usePods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try to pass the &lt;code&gt;--pods&lt;/code&gt; arg with a &lt;code&gt;"usePods": true&lt;/code&gt; config ember-cli will throw a warning that using both is deprecated. The rest of my examples will use the &lt;code&gt;--pods&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;The problem I had was trying to create a component but I didn't want the &lt;code&gt;component.js&lt;/code&gt; file or its &lt;code&gt;template.hbs&lt;/code&gt; file to be generated inside of a &lt;code&gt;/components&lt;/code&gt; directory. Maybe this is a bad idea. If it is I'm sure the internet will tell me.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--path&lt;/code&gt; option accepts a string as its argument. You can use it to pass a file path. The file path passed must be relative to the &lt;code&gt;/app&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/
|-- post/
    |-- controller.js
    |-- route.js
    |-- template.js
|-- app.js
|-- index.html
|-- router.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to create an &lt;code&gt;author-info&lt;/code&gt; component inside our post directory the &lt;code&gt;ember-cli&lt;/code&gt; command would be&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ember g component author-info --pods --path="post"&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;app/
|-- post/
    |-- author-info/
        |-- component.js
        |-- template.hbs
    |-- controller.js
    |-- route.js
    |-- template.js
|-- app.js
|-- index.html
|-- router.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if I want to create a component at the same level as &lt;code&gt;/post&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ember generate component my-component --pods --path=""&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Just pass an empty string as the argument. That creates the file structure below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/
|-- my-component/
    |-- component.js
    |-- template.js
|-- post/
    |-- author-info/
        |-- component.js
        |-- template.hbs
    |-- controller.js
    |-- route.js
    |-- template.js
|-- app.js
|-- index.html
|-- router.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's also an alias for &lt;code&gt;--path=""&lt;/code&gt;. It's &lt;code&gt;--no-path&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ember generate component my-component --pods --no-path&lt;/code&gt;&lt;/p&gt;

</description>
      <category>ember</category>
      <category>embercli</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
