<?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: Sarah Harrington</title>
    <description>The latest articles on DEV Community by Sarah Harrington (@sarahdoestech).</description>
    <link>https://dev.to/sarahdoestech</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%2F407691%2Fe76e2fe2-5950-49ee-9997-dca75e42aa20.jpeg</url>
      <title>DEV Community: Sarah Harrington</title>
      <link>https://dev.to/sarahdoestech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sarahdoestech"/>
    <language>en</language>
    <item>
      <title>Operator Mono, Ligatures &amp; Italics</title>
      <dc:creator>Sarah Harrington</dc:creator>
      <pubDate>Wed, 27 Sep 2023 18:03:32 +0000</pubDate>
      <link>https://dev.to/sarahdoestech/operator-mono-ligatures-italics-43j4</link>
      <guid>https://dev.to/sarahdoestech/operator-mono-ligatures-italics-43j4</guid>
      <description>&lt;p&gt;At the beginning of my coding journey, I was watching a video by Wes Boss and fell in love with the Operator Mono font. I loved it so much but couldn't justify $200 on it at the time. &lt;/p&gt;

&lt;p&gt;This year, I finally splurged on it since I stare at my code editor every single day. I had done this set up once and got it working but recently forgot how I did it. So here's a recap now that I've got it working again.&lt;/p&gt;

&lt;p&gt;You need to purchase the &lt;a href="https://www.typography.com/fonts/operator/styles"&gt;Operator Mono&lt;/a&gt; font. &lt;/p&gt;

&lt;p&gt;I used this &lt;a href="https://gist.github.com/junagao/f785ed77589246a3d063273b3a56f114"&gt;gist&lt;/a&gt; for getting italics to show as cursive. There are so many different customizations for what you want this to look like so if you're not digging this particular one, definitely do some research.&lt;/p&gt;

&lt;p&gt;I really love ligatures, they make my brain happy. To get ligatures working with Operator Mono, I used &lt;a href="https://github.com/kiliman/operator-mono-lig"&gt;operator-mono-lig&lt;/a&gt;. They have instructions for how to get this to work for Windows, Mac and Linux so hopefully your bases would be covered. &lt;/p&gt;

&lt;p&gt;Both times I've done this I've gone and updated my VS Code settings before remember install the font, so don't be like me and remember to grab those from the build folder first.&lt;/p&gt;

&lt;p&gt;One thing I found that differs from the &lt;code&gt;operator-mono-lig&lt;/code&gt; documentation is that I needed to add my font as &lt;code&gt;Operator Mono Lig&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;settings.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;"workbench.colorTheme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"In Bed by 7pm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"workbench.sideBar.location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"security.workspace.trust.untrustedFiles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"open"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.fontFamily"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Operator Mono Lig, Menlo, Monaco, 'Courier New', monospace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.tabSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"files.autoSave"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"afterDelay"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.minimap.enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.fontLigatures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.tokenColorCustomizations"&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;"textMateRules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="err"&gt;//following&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;italic&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"comment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"entity.name.type.class"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;names&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"constant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Boolean…&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;super&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"storage.modifier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;keyword&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"storage.type.class.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;keyword&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"keyword"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//import&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;export&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;return…&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;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"fontStyle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"italic"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="err"&gt;//following&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;excluded&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;italics&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(VSCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;some&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;defaults&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;italics)&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"invalid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"keyword.operator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"constant.numeric.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"keyword.other.unit.px.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"constant.numeric.decimal.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"constant.numeric.json"&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;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"fontStyle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"editor.fontSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&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;Which gives me this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4RGNlQWV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4c4nitehjop4jlics5ul.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4RGNlQWV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4c4nitehjop4jlics5ul.png" alt="Image description" width="759" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ku18HvSD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o948ak1gn8ayuqrz5zbj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ku18HvSD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o948ak1gn8ayuqrz5zbj.png" alt="Image description" width="277" height="99"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
    </item>
    <item>
      <title>Canvas Playground, deployment woes</title>
      <dc:creator>Sarah Harrington</dc:creator>
      <pubDate>Fri, 15 Sep 2023 14:47:47 +0000</pubDate>
      <link>https://dev.to/sarahdoestech/canvas-playground-deployment-o41</link>
      <guid>https://dev.to/sarahdoestech/canvas-playground-deployment-o41</guid>
      <description>&lt;p&gt;When I was looking up info on how to deploy my socket.io server to AWS I ran across a post about using API Gateway sockets which was released back in 2018 after I initially created my project. About 30 tabs later and a mushy brain I got back to my original plan of using EC2, S3 and CloudFront (which also lead to a very mushy brain, more to come on that).&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up AWS CLI
&lt;/h3&gt;

&lt;p&gt;I recently switched over to a new Macbook and decided to set up a fresh dev environment which meant I needed to set up the AWS CLI again. I installed the AWS CLI using &lt;a href="https://formulae.brew.sh/formula/awscli"&gt;Homebrew&lt;/a&gt;. After installing the AWS CLI you can &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html"&gt;configure&lt;/a&gt; your settings for your needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  EC2
&lt;/h3&gt;

&lt;p&gt;I started out with creating a Debian Linux server on EC2 that I logged in to using SSH. I am very fortunate that my partner is a Dev Ops Engineer and walked me through setting up a &lt;a href="https://wiki.debian.org/SshAliases"&gt;SSH Alias&lt;/a&gt;. Does it get any better than having a literal in house expert?&lt;/p&gt;

&lt;p&gt;Once I was in, I was able to install Node and upload the server for my project. To get things up and running I'm using &lt;code&gt;scp&lt;/code&gt; to upload my files with a goal to make a more automated process once I've got things working.&lt;/p&gt;

&lt;h3&gt;
  
  
  S3
&lt;/h3&gt;

&lt;p&gt;I created a bucket for my project and synced the files using the &lt;a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/sync.html"&gt;AWS CLI S3 sync command&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CloudFront
&lt;/h3&gt;

&lt;p&gt;I created a new CloudFront distribution for this project that has two origins, one pointed at the EC2 instance for my backend and one pointed at the S3 bucket for my project. I set up a behavior for the EC2 instance for the path pattern &lt;code&gt;/socket.io/&lt;/code&gt; since that is amended to all of the outgoing requests from the socket.io client side code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VMuINN7f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xar4huomlxcyxju33so.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VMuINN7f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xar4huomlxcyxju33so.png" alt="Image description" width="800" height="175"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Route53
&lt;/h3&gt;

&lt;p&gt;I use Route53 for DNS on my &lt;a href="https://sarahdoes.tech"&gt;portfolio&lt;/a&gt; site. I created an A record for canvasplayground.sarahdoes.tech so the site could have it's own unique URL.&lt;/p&gt;

&lt;p&gt;I pulled up the site and was super excited until I noticed that it didn't show any connected users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AUajeNWu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kmvq9jikmll1eum5ul6o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AUajeNWu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kmvq9jikmll1eum5ul6o.png" alt="Image description" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I looked in the console and see 400 errors&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DVGXPVB1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93kads8oklvjipmsx86d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DVGXPVB1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93kads8oklvjipmsx86d.png" alt="Image description" width="597" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After consulting with the in-house expert and Google, I have not been able to find a solution for the 400 from the server. CloudFront is acting as a reverse proxy and there are some specific callouts for using Socket.io with reverse proxies in the Socket.io documentation but nothing specific to CloudFront. I ran across some other inquiries from others on how to make this work but no solutions.&lt;/p&gt;

&lt;p&gt;I'm exploring what other options I have for getting this project up and running.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Gateway sockets&lt;/li&gt;
&lt;li&gt;Using standard websockets since they should be compatible with CloudFront&lt;/li&gt;
&lt;li&gt;Sticking with socket.io and hosting the front end on my EC2 instance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was looking forward to being able to using socket.io to implement some features I think could be fun so I'm debating the decision to keep going with that against switching to a different websocket strategy.&lt;/p&gt;

</description>
      <category>socketio</category>
      <category>aws</category>
    </item>
    <item>
      <title>Canvas Playground: broadcasting &amp; pens</title>
      <dc:creator>Sarah Harrington</dc:creator>
      <pubDate>Tue, 05 Sep 2023 19:42:47 +0000</pubDate>
      <link>https://dev.to/sarahdoestech/canvas-playground-broadcasting-pens-3ali</link>
      <guid>https://dev.to/sarahdoestech/canvas-playground-broadcasting-pens-3ali</guid>
      <description>&lt;p&gt;One thing I struggle with when learning something new is feeling like I don't have progress to show. Today I've spent time looking at DynamoDB and EC2 so I can start determining how I want to deploy the server and potentially store the drawing actions but that would leave me without a visible progression. &lt;/p&gt;

&lt;h2&gt;
  
  
  Pens
&lt;/h2&gt;

&lt;p&gt;To do something on that front, I decided to tackle making it possible to change color schemes for the pens and fixed a bug where the pen color was getting stuck.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JC432iRm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7rcbwtujessgf87pj2pi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JC432iRm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7rcbwtujessgf87pj2pi.png" alt="Image description" width="800" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first step was moving the pens in to their own component.&lt;/p&gt;

&lt;p&gt;Pen.tsx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PenProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nl"&gt;changeColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEventHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Pen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;PenProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; 
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'paint-button'&lt;/span&gt; 
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;changeColor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; 
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'material-symbols-outlined'&lt;/span&gt; 
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;color&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;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        brush
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component is receiving the pen color object and the &lt;code&gt;changeColor&lt;/code&gt; function from the parent.&lt;/p&gt;

&lt;p&gt;I wanted to make it so once the pen was selected it would maintain a class on &lt;code&gt;:active&lt;/code&gt;. To do that, I passed in the currently selected color and updated the class on the pen to include the class &lt;code&gt;selected&lt;/code&gt; if the pen color value and the &lt;code&gt;activeColor&lt;/code&gt; matched.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PenProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;activeColor&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="nl"&gt;changeColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEventHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Pen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;activeColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;changeColor&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;PenProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; 
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`paint-button &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;activeColor&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;selected&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="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;changeColor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; 
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'material-symbols-outlined'&lt;/span&gt; 
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;color&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;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          brush
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Broadcasting
&lt;/h2&gt;

&lt;p&gt;When I was setting up the server, I was sending back out the drawing events from the server, I just did a generic emit on the server so it would send the event back to all connected sockets. That worked, but I don't need the original socket sending info to get it back. To do this, I updated the server to use the &lt;a href="https://socket.io/docs/v4/server-api/#flag-broadcast"&gt;broadcast flag&lt;/a&gt; after it receives the &lt;code&gt;userIsDrawing&lt;/code&gt; event to broadcast that back out to the other attached sockets.&lt;/p&gt;

&lt;p&gt;original:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  socket.on('userIsDrawing', (e) =&amp;gt; {
    io.emit('userDrawing', e)
  })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;broadcasting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  socket.on('userIsDrawing', (e) =&amp;gt; {
    socket.broadcast.emit('userDrawing', e)
  })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tiny changes felt like some nice progress today:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_shABVy3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rtvioezv9350ioqpypzp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_shABVy3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rtvioezv9350ioqpypzp.gif" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>socketio</category>
    </item>
    <item>
      <title>Canvas Playground, Starting Again</title>
      <dc:creator>Sarah Harrington</dc:creator>
      <pubDate>Mon, 04 Sep 2023 23:54:39 +0000</pubDate>
      <link>https://dev.to/sarahdoestech/canvas-playground-starting-again-29gj</link>
      <guid>https://dev.to/sarahdoestech/canvas-playground-starting-again-29gj</guid>
      <description>&lt;p&gt;After completing my full stack software engineering bootcamp, JavaScript frameworks felt like ✨magic✨ and I wanted to understand &lt;em&gt;how&lt;/em&gt; they worked. This began my journey with Vanilla JavaScript where I made a series of projects for my portfolio (including the site itself) using Vanilla JS. One of the things I love about the these projects is that they still work great today. I've been able to move them from different hosting providers and once they're loaded and I've got my DNS set up we're off and running.&lt;/p&gt;

&lt;p&gt;With the potential to start job hunting looming, I thought it would be a good time to dig back in to React since it's been over a year since I used it last. It seemed like remaking some of these former projects in React with TypeScript would be a fun challenge where I didn't have to come up with an idea for a whole new project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Canvas Playground
&lt;/h2&gt;

&lt;p&gt;Canvas playground was a project I put together during the summer of 2018. It used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vanilla JS&lt;/li&gt;
&lt;li&gt;Socket.io&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had this running on a server in Linode for quite a long time but have since decided to move away from Linode in favor of AWS. It's not currently working since I need to do some work to get the server running on an AWS EC2 instance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SarahHarrington/canvas-app" rel="noopener noreferrer"&gt;Github Rep&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  New project goals
&lt;/h2&gt;

&lt;p&gt;As I'm starting again, I'd like to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use React with TypeScript&lt;/li&gt;
&lt;li&gt;host everything on AWS&lt;/li&gt;
&lt;li&gt;use socket.io&lt;/li&gt;
&lt;li&gt;add some sort of permanent storage solution for drawings&lt;/li&gt;
&lt;li&gt;ask users to enter their name &amp;amp; display who is drawing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stretch goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;incorporate canvas rooms&lt;/li&gt;
&lt;li&gt;user tokens so users can come back and see their drawings&lt;/li&gt;
&lt;li&gt;push my UI instincts out of my normal box&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Deciding to write as I work through this process was made after I started, so I've already made some progress on the project and we'll be playing some generalized catch up here. I'm planning for future posts to go in to more detail about what I'm doing.&lt;/p&gt;

&lt;p&gt;I typically love to wireframe if I'm starting on something new, but since this is something I previously made, I'm starting with a general idea in mind with things I know I wanted to change/improve from last time.&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%2Fkd13ke4p4h3hi0jhi71h.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%2Fkd13ke4p4h3hi0jhi71h.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Progress so far
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Front End
&lt;/h4&gt;

&lt;p&gt;The React app is up and running using TypeScript. I've started with creating the general layout and minimal styling so far.&lt;/p&gt;

&lt;p&gt;To get Socket.io working with React, Socket.io docs have a &lt;a href="https://socket.io/how-to/use-with-react#docusaurus_skipToContent_fallback" rel="noopener noreferrer"&gt;really helpful guide&lt;/a&gt;. I leaned on this pretty heavily to get the sockets working.&lt;/p&gt;

&lt;p&gt;On the UI side of things, I was struggling with getting the mouse events for &lt;code&gt;mouseup&lt;/code&gt;, &lt;code&gt;mousedown&lt;/code&gt;, &lt;code&gt;mousemove&lt;/code&gt; working quite right with the canvas and React. I knew I needed to be using hooks, but wasn't sure what would be the best method for them. After some googling I ran across &lt;a href="https://www.ankursheel.com/blog/react-component-draw-page-hooks-typescript" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt; which was exactly what I needed. I had not previously used &lt;code&gt;useCallback&lt;/code&gt; or &lt;code&gt;useRef&lt;/code&gt; and this was a great way to learn more about these two hooks.&lt;/p&gt;

&lt;p&gt;Once I got the canvas events drawing the way I wanted, it was time to send the events to the server so they could be broadcast. &lt;/p&gt;

&lt;h4&gt;
  
  
  Back End
&lt;/h4&gt;

&lt;p&gt;Getting the server going took me longer than I thought it would, I hadn't realized how long it had been since I've started a server from scratch!&lt;/p&gt;

&lt;p&gt;As a user is drawing it's sending an event to the socket server which is then emitting that back out to all of the connected sockets. I'd like to update this so it's using the broadcast feature since it doesn't need to go back to the original connection.&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%2Fa6g7chot8ilertu7jelt.gif" 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%2Fa6g7chot8ilertu7jelt.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Up Next
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;updating the server to use Node with TypeScript&lt;/li&gt;
&lt;li&gt;user tokens and storage options (Maybe DynamoDB?)&lt;/li&gt;
&lt;li&gt;hosting the socket server on AWS&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
