<?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: Dustin Brett</title>
    <description>The latest articles on DEV Community by Dustin Brett (@dustinbrett).</description>
    <link>https://dev.to/dustinbrett</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%2F210026%2F628bd8a1-1d1c-434c-aabf-516fc241d12e.jpg</url>
      <title>DEV Community: Dustin Brett</title>
      <link>https://dev.to/dustinbrett</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dustinbrett"/>
    <language>en</language>
    <item>
      <title>Day in the Life of a Microsoft Software Engineer | Vancouver 2024</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Fri, 03 May 2024 14:59:40 +0000</pubDate>
      <link>https://dev.to/dustinbrett/day-in-the-life-of-a-microsoft-software-engineer-vancouver-2024-pon</link>
      <guid>https://dev.to/dustinbrett/day-in-the-life-of-a-microsoft-software-engineer-vancouver-2024-pon</guid>
      <description>&lt;p&gt;I love making these Day in the Life videos for myself so that I have something to look back on. That is one reason why I keep these videos very authentic.&lt;/p&gt;

&lt;p&gt;This video is for anyone interested in what the daily routine looks like of a front-end software engineer working at Microsoft. Some days/weeks are more busy than others, but I purposely made this during one of the lighter days so that I had time to record stuff.&lt;/p&gt;

&lt;p&gt;I filmed this on April 30th, 2024 in Vancouver, BC, Canada.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/KNMBqgX-eGg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Thanks for checking it out!&lt;/p&gt;

</description>
      <category>career</category>
      <category>microsoft</category>
      <category>webdev</category>
      <category>developer</category>
    </item>
    <item>
      <title>3 YEARS On My Side Project!</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Sun, 14 Apr 2024 15:33:10 +0000</pubDate>
      <link>https://dev.to/dustinbrett/3-years-on-my-side-project-4o2c</link>
      <guid>https://dev.to/dustinbrett/3-years-on-my-side-project-4o2c</guid>
      <description>&lt;p&gt;I started working on &lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;daedalOS&lt;/a&gt; on January 1st, 2021, and more than 3 years later I still enjoy adding to it and improving it almost daily.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/tGpvcQKaGzs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I've learned so much while making this project into my &lt;a href="https://dustinbrett.com/" rel="noopener noreferrer"&gt;personal website (dustinbrett.com)&lt;/a&gt;. It's made me a much better web developer as I have tried to emulate a desktop environment with pixel perfect accuracy using CSS, HTML &amp;amp; JavaScript.&lt;/p&gt;

&lt;p&gt;Over the years I have live streamed and made videos of my progress. The first year I &lt;a href="https://youtube.com/playlist?list=PLM88opVjBuU7xSRoHhs3hZBz3JmHHBMMN&amp;amp;si=XmhpL-LFWIgrY6iL" rel="noopener noreferrer"&gt;streamed&lt;/a&gt; every single week for 52 weeks. Then as the project evolved I started doing monthly feature reviews, similar to what I had seen done with SerenityOS which was an inspiration of mine.&lt;/p&gt;

&lt;p&gt;Now I am in the 2nd year of being nominated for a Webby, and this time I am hoping I've done enough that the judges pick me in the end. But also if you like my project and want to support me, you can &lt;a href="https://vote.webbyawards.com/PublicVoting#/2024/websites-and-mobile-sites/general-desktop-mobile-sites/personal-blogwebsite" rel="noopener noreferrer"&gt;vote for my site to win the People's Voice award&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/HvuboyIWIIQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Thanks for checking it out!&lt;/p&gt;

</description>
      <category>sideprojects</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>How I got nominated for a Webby Award</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Wed, 03 Apr 2024 15:15:05 +0000</pubDate>
      <link>https://dev.to/dustinbrett/how-i-got-nominated-for-a-webby-award-5g66</link>
      <guid>https://dev.to/dustinbrett/how-i-got-nominated-for-a-webby-award-5g66</guid>
      <description>&lt;p&gt;I'm very happy to announce that my &lt;a href="https://dustinbrett.com/" rel="noopener noreferrer"&gt;personal website&lt;/a&gt; has once again been &lt;a href="https://vote.webbyawards.com/PublicVoting#/2024/websites-and-mobile-sites/general-desktop-mobile-sites/personal-blogwebsite" rel="noopener noreferrer"&gt;nominated for a Webby Award&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;My website is a desktop environment in the browser and I have made a video showing off some of it's features for those interested.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/RRLq3T0Surs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It's been a goal of mine to win a Webby for a few years now, since I started my &lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;side project&lt;/a&gt; over 3 years ago to build my personal website. I have continued to work on and improve my website almost daily now since Jan 2021.&lt;/p&gt;

&lt;p&gt;Since creating my project I have entered it into most awards sites such as &lt;a href="https://www.awwwards.com/sites/daedalos" rel="noopener noreferrer"&gt;Awwwards&lt;/a&gt;, &lt;a href="https://thefwa.com/cases/daedalos" rel="noopener noreferrer"&gt;The FWA&lt;/a&gt; and &lt;a href="https://www.cssdesignawards.com/sites/daedalos/42046/" rel="noopener noreferrer"&gt;CSS Design Awards&lt;/a&gt; and it's done decent, although not well enough to win top awards, but for me personally the Webby award has always been the one I wanted the most, so getting nominated again is exciting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F323i935ez0ob2wiap9nd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F323i935ez0ob2wiap9nd.png" alt="daedalOS Screenshot 2" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One reason I consider it to be the top award is that they have a large judging staff and if you are nominated or win, you get an actual physical award. Also if you win then they have an award show which you can attend in New York City.&lt;/p&gt;

&lt;p&gt;Most award sites now-a-days require an entry fee which I used to think was a pay-to-play system, and in a way it is, but there are real costs involved with having proper judging as well as awards so I do think that some fee is understandable. Luckily for the personal website category it is heavily discounted so I end up paying quite a bit less than most categories.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fxfe96rv49iussuh7jxsv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxfe96rv49iussuh7jxsv.png" alt="daedalOS Screenshot 1" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've spent a lot of time looking at the winners of these sites to try and find what makes them stand apart and to consider how I could add things to my project to be comparable to them. It's been a long journey of self discovery and looking inward to be able to see the flaws in my site and why other sites are picked over mine, and I have worked to try and change where possibly without compromising my vision for my personal website.&lt;/p&gt;

&lt;p&gt;Now that I am nominated I have a chance to win by the judges voting but also I can win what they call the People's Voice Award which comes from votes from the community. So if you like my site and want to support me to win, please take a moment to &lt;a href="https://vote.webbyawards.com/PublicVoting#/2024/websites-and-mobile-sites/general-desktop-mobile-sites/personal-blogwebsite" rel="noopener noreferrer"&gt;vote for my site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/HvuboyIWIIQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Thanks for checking out my project!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>sideprojects</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Running the Latest Safari WebKit on Windows</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Fri, 10 Mar 2023 06:06:09 +0000</pubDate>
      <link>https://dev.to/dustinbrett/running-the-latest-safari-webkit-on-windows-33pb</link>
      <guid>https://dev.to/dustinbrett/running-the-latest-safari-webkit-on-windows-33pb</guid>
      <description>&lt;h2&gt;
  
  
  Safari runs on Windows!?!
&lt;/h2&gt;

&lt;p&gt;I can't believe it took me this long to figure this out, but it's totally possible to run the latest WebKit/Safari on Windows locally and debug issues that would otherwise require emulation, a remote machines or a Mac!&lt;/p&gt;

&lt;p&gt;Not only can it be done but it's extremely easy to do, and in this article I will go over the 2 simplest ways to get up and running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method #1: Playwright CLI
&lt;/h2&gt;

&lt;p&gt;This first method is by far the easiest as it only requires having &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; installed which comes with npm/npx. Once you have Node.js installed you will need to run the &lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt; command to download the browsers.&lt;/p&gt;

&lt;p&gt;Open up the Command Prompt and type &lt;code&gt;npx playwright install&lt;/code&gt;, then once this is done you can open up a url in WebKit by running the follow command &lt;code&gt;npx playwright wk https://dustinbrett.com/&lt;/code&gt;, as described in the docs for &lt;a href="https://playwright.dev/docs/cli#open-pages" rel="noopener noreferrer"&gt;Command line tools -&amp;gt; Open Pages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fi7ln33n3u897ef4lhs4t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fi7ln33n3u897ef4lhs4t.png" alt="MiniBrowser.exe" width="800" height="645"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Method #2: Download Build Artifacts
&lt;/h2&gt;

&lt;p&gt;As described in the &lt;a href="https://trac.webkit.org/wiki/BuildingCairoOnWindows#DownloadbuildartifactsfromBuildbot" rel="noopener noreferrer"&gt;Webkit Wiki&lt;/a&gt;, the files required are built often and can be easily downloaded and combined.&lt;/p&gt;

&lt;p&gt;The first file that is needed comes from the &lt;a href="https://build.webkit.org/#/builders" rel="noopener noreferrer"&gt;Webkit CI Builders&lt;/a&gt;, specifically &lt;code&gt;WinCairo-64-bit-Release-Build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fko9sus4nyvdvsd58bytg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fko9sus4nyvdvsd58bytg.png" alt="Webkit CI Builders" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the latest green build and download the zip file mentioned after &lt;code&gt;S3 URL&lt;/code&gt; on the &lt;code&gt;transfer-to-s3&lt;/code&gt; step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fs0n9h7fn7p4t8m7hd23s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fs0n9h7fn7p4t8m7hd23s.png" alt="Download From S3" width="800" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you will need to download one more zip file from the &lt;a href="https://github.com/WebKitForWindows/WebKitRequirements/releases" rel="noopener noreferrer"&gt;WebKitForWindows Releases&lt;/a&gt; by downloading &lt;code&gt;WebKitRequirementsWin64.zip&lt;/code&gt; from the &lt;code&gt;Assets&lt;/code&gt; section of the most recent release.&lt;/p&gt;

&lt;p&gt;Then extract both files to the same folder so that the &lt;code&gt;bin64&lt;/code&gt; folders become combined. All other folders can be deleted as they are not needed. Go into the combined &lt;code&gt;bin64&lt;/code&gt; folder and launch &lt;code&gt;MiniBrowser.exe&lt;/code&gt; and you are up and running.&lt;/p&gt;

&lt;p&gt;This version has more features compared to the Playwright one and allows turning on and off Experimental &amp;amp; Internal Debug Features.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbiruu85g6h4zvvsbhv04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbiruu85g6h4zvvsbhv04.png" alt="Experimental &amp;amp; Internal Debug Features" width="800" height="1104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both versions have the familiar Web Inspector which is extremely helpful to have locally.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fvfipyma5pr40wghhrp3f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fvfipyma5pr40wghhrp3f.png" alt="Web Inspector" width="800" height="593"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Companion Video
&lt;/h2&gt;

&lt;p&gt;I thought this was such a useful trick that I also made a video showing how to do it, feel free to check it out!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/W3IH7zDR_HQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>productivity</category>
      <category>safari</category>
    </item>
    <item>
      <title>Adding JPEG XL &amp; QOI Support to my Website OS</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Fri, 30 Dec 2022 07:10:31 +0000</pubDate>
      <link>https://dev.to/dustinbrett/adding-jpeg-xl-qoi-support-to-my-website-os-3oni</link>
      <guid>https://dev.to/dustinbrett/adding-jpeg-xl-qoi-support-to-my-website-os-3oni</guid>
      <description>&lt;p&gt;I'm always having fun adding things to my desktop environment in the browser (&lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;daedalOS&lt;/a&gt;), which also powers my personal website &lt;a href="https://dustinbrett.com/" rel="noopener noreferrer"&gt;dustinbrett.com&lt;/a&gt; where everything I show here can be tried out.&lt;/p&gt;

&lt;p&gt;Recently I'd added &lt;a href="https://en.wikipedia.org/wiki/TIFF" rel="noopener noreferrer"&gt;TIFF&lt;/a&gt; support to my project via &lt;a href="https://github.com/photopea/UTIF.js/" rel="noopener noreferrer"&gt;UTIF.js&lt;/a&gt; and now I decided I wanted to add &lt;a href="https://jpeg.org/jpegxl/" rel="noopener noreferrer"&gt;JPEG XL&lt;/a&gt; &amp;amp; &lt;a href="https://qoiformat.org/" rel="noopener noreferrer"&gt;QOI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  JPEG XL Support (&lt;a href="https://jpegxl.info/art/2021-04_jon.html" rel="noopener noreferrer"&gt;Sample Images&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fswzyf7pagd7j4oazu1jk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fswzyf7pagd7j4oazu1jk.png" alt="JPEG XL Images" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://github.com/DustinBrett/daedalOS/commit/21e400671a3f581d13e692fbeac4eeef7a73db6a" rel="noopener noreferrer"&gt;adding JPEG XL support&lt;/a&gt; I went with &lt;a href="https://github.com/niutech/jxl.js" rel="noopener noreferrer"&gt;jxl.js&lt;/a&gt; which I modified for my use case. After looking through the main file, which is also called &lt;a href="https://github.com/niutech/jxl.js/blob/main/jxl.js" rel="noopener noreferrer"&gt;jxl.js&lt;/a&gt;, I decided I only needed 2 relevant code blocks. The one to decode the image and the one to turn the &lt;code&gt;ImageData&lt;/code&gt; into something I could display in my existing codebase (which I already partially had implemented for another use case).&lt;/p&gt;

&lt;p&gt;To decode the image it creates a worker with &lt;a href="https://raw.githubusercontent.com/niutech/jxl.js/main/jxl_dec.js" rel="noopener noreferrer"&gt;jxl_dec.js&lt;/a&gt;, also I updated the path (hardcoded inside &lt;code&gt;jxl_dec.js&lt;/code&gt;) for &lt;a href="https://github.com/niutech/jxl.js/raw/main/jxl_dec.wasm" rel="noopener noreferrer"&gt;jxl_dec.wasm&lt;/a&gt; to point to where I've stored it within my Next.js &lt;code&gt;public&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Then all that is needed is to run &lt;code&gt;decodeJxl&lt;/code&gt; with image data in &lt;code&gt;Buffer&lt;/code&gt;/&lt;code&gt;Uint8Array&lt;/code&gt; form. Once it returns &lt;code&gt;ImageData&lt;/code&gt; I use &lt;code&gt;imgDataToBuffer&lt;/code&gt; to convert it back into a &lt;code&gt;Buffer&lt;/code&gt; which I use for making thumbnails and displaying the picture in the &lt;code&gt;Photos&lt;/code&gt; app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;JxlDecodeResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;imgData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decodeJxl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ImageData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&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;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;System/JXL.js/jxl_dec.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;jxlSrc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image.jxl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JxlDecodeResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;imgData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imgDataToBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageData&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nf"&gt;putImageData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data:image/png;base64,&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base64&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;h2&gt;
  
  
  QOI Support (&lt;a href="https://gist.github.com/nicolaslegland/f0577cb49b1e56b729a2c0fc0aa151ba" rel="noopener noreferrer"&gt;Sample Images&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fl6c6mg6vgcyblyj898i8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fl6c6mg6vgcyblyj898i8.png" alt="QOI Images" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it came to &lt;a href="https://github.com/DustinBrett/daedalOS/commit/e841b2632299e5594b576e115716d7073564e1be#diff-0c7764029c0bd0ee3b532b3ee879a8c328b536e965edf5cd9fceb279e666214d" rel="noopener noreferrer"&gt;adding QOI support&lt;/a&gt;, I used an &lt;a href="https://gist.github.com/nicolaslegland/f0577cb49b1e56b729a2c0fc0aa151ba" rel="noopener noreferrer"&gt;open source "Gist"&lt;/a&gt; example that I basically didn't touch except to turn the &lt;code&gt;qoi.js&lt;/code&gt; file into a &lt;code&gt;.ts&lt;/code&gt; file so I could export a function which wrapped &lt;code&gt;transcode_qoi_to_png&lt;/code&gt; and exported it as a &lt;code&gt;Buffer&lt;/code&gt; for my use cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decodeQoi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imgBuffer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;transcode_qoi_to_png&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;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imgBuffer&lt;/span&gt;&lt;span class="p"&gt;))));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Thanks! (&lt;a href="https://www.youtube.com/@DustinBrett" rel="noopener noreferrer"&gt;@DustinBrett&lt;/a&gt;)
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed my article about adding image formats to my desktop environment in the browser. If you're interested in more stuff about my &lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;side project&lt;/a&gt; which I have been working on for over 2 years, I recently did a video going over 2022's progress.&lt;/p&gt;

&lt;p&gt;Please check it out and leave a comment/like if you enjoy it or have something to say.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/AMnLsUytCRQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>emptystring</category>
    </item>
    <item>
      <title>Chatting with ChatGPT: Make me an article!</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Wed, 07 Dec 2022 02:01:17 +0000</pubDate>
      <link>https://dev.to/dustinbrett/chatting-with-chatgpt-make-me-an-article-2i6a</link>
      <guid>https://dev.to/dustinbrett/chatting-with-chatgpt-make-me-an-article-2i6a</guid>
      <description>&lt;p&gt;As a software engineer, I'm always interested in exploring the latest advancements in AI and natural language processing. Recently, I had the opportunity to spend some time talking to ChatGPT, an AI language model.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/-E7duEo-lQU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I started off by asking ChatGPT to generate some art prompts for DALL-E 2, the AI developed by OpenAI that is capable of generating images based on text prompts. While the results from DALL-E 2 were not as impressive as I had hoped, it was clear that ChatGPT had a deep understanding of language and was able to generate original and interesting prompts.&lt;/p&gt;

&lt;p&gt;Next, I asked ChatGPT to act like a Linux terminal. It responded with a series of commands and responses that were highly realistic, showing its advanced ability to understand and respond to natural language. I was particularly impressed by the level of detail and accuracy in its responses, including when I asked it to ping an address with an unreliable connection and it added in simulated packet loss and latency.&lt;/p&gt;

&lt;p&gt;Later in the conversation, I asked ChatGPT to generate some titles for the video we were making. It came up with several clever and humorous options, showing that it was able to understand the context of the conversation and generate appropriate responses. I was impressed by how well it was able to capture the tone and style of the video in its suggestions.&lt;/p&gt;

&lt;p&gt;Finally, I asked ChatGPT to act like a character from a science fiction novel. Specifically, I asked it to act like Vox from The Time Machine, which itself is an AI character. It responded with a series of responses that were not only in character, but also showed a deep understanding of the personality and motivations of the character. In particular, I was struck by the similarity between ChatGPT's responses as Vox and how Vox itself might behave if it were a real AI. It's interesting to consider the possibility that two AI's designed for similar purposes might exhibit similar behavior and thought processes, even if they were trained by different organizations.&lt;/p&gt;

&lt;p&gt;It's worth noting that this article was also written by ChatGPT. Its ability to understand and write in a variety of styles and contexts is truly impressive, and it's clear that it has made significant strides in the field of natural language processing. While it's not quite ready to replace human conversation entirely, it's clear that it's making impressive strides in this area. As AI technology continues to develop, I'm excited to see what other amazing feats ChatGPT and other AI language models will be capable of in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chat GPT Conversation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fwsrts2e2diqhwwggxhmn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fwsrts2e2diqhwwggxhmn.png" alt="Response 1" width="790" height="854"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ffkvn3cfdqx7sml50vcjj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ffkvn3cfdqx7sml50vcjj.png" alt="Response 2" width="790" height="788"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fiu45d2n92d14q5afikbt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fiu45d2n92d14q5afikbt.png" alt="Response 3" width="800" height="886"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F35xn4osbiwn0fwdqxfms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F35xn4osbiwn0fwdqxfms.png" alt="Response 4" width="800" height="887"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fzjnzwad6sqfgu2nhbn9n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fzjnzwad6sqfgu2nhbn9n.png" alt="Response 5" width="768" height="1044"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F0xholqtvmgx8ablj3uls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0xholqtvmgx8ablj3uls.png" alt="Response  6" width="779" height="986"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fvwgc2ha83256hj4hv2s1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fvwgc2ha83256hj4hv2s1.png" alt="Response 7" width="779" height="959"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fyi2q6c8o4xpjcvpcyer8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fyi2q6c8o4xpjcvpcyer8.png" alt="Response 8" width="791" height="1010"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fg8a93aw1bvof60m7kmhd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fg8a93aw1bvof60m7kmhd.png" alt="Response 9" width="800" height="1187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fp8t6al40wc12a3w0zw8w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fp8t6al40wc12a3w0zw8w.png" alt="Response 10" width="798" height="1353"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>ai</category>
      <category>learning</category>
    </item>
    <item>
      <title>Adding IPFS to my JavaScript OS</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Mon, 26 Sep 2022 20:35:54 +0000</pubDate>
      <link>https://dev.to/dustinbrett/adding-ipfs-to-my-javascript-os-14ag</link>
      <guid>https://dev.to/dustinbrett/adding-ipfs-to-my-javascript-os-14ag</guid>
      <description>&lt;p&gt;I've been wanting to dip my toes into the Web 3.0 verse for a while now, specifically with an integration into my side project, a &lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;Desktop environment in the browser&lt;/a&gt; (&lt;a href="https://dustinbrett.com/" rel="noopener noreferrer"&gt;daedalOS&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I've decided as a first step I would add &lt;a href="https://ipfs.io/" rel="noopener noreferrer"&gt;ipfs&lt;/a&gt; &lt;a href="https://docs.ipfs.tech/how-to/address-ipfs-on-web/#native-urls" rel="noopener noreferrer"&gt;native url&lt;/a&gt; support. I've added this support to the &lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/components/apps/Browser/index.tsx" rel="noopener noreferrer"&gt;Browser&lt;/a&gt; (&lt;a href="https://dustinbrett.com/?app=Browser&amp;amp;url=ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/wiki/Vincent_van_Gogh.html" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;), &lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/components/system/Dialogs/Run/index.tsx" rel="noopener noreferrer"&gt;Run Dialog&lt;/a&gt;, &lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/components/system/Files/FileEntry/useFile.ts" rel="noopener noreferrer"&gt;Shortcuts&lt;/a&gt; &amp;amp; &lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/components/apps/Terminal/useCommandInterpreter.ts" rel="noopener noreferrer"&gt;Terminal&lt;/a&gt;. Most of the main ipfs functions I've migrated to &lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/utils/ipfs.ts" rel="noopener noreferrer"&gt;utils/ipfs.ts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F29xquiyxitakaholtrdj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F29xquiyxitakaholtrdj.png" alt="ipfs://bafkreigh2akiscaildcqabsyg3dfr6chu3fgpregiymsck7e7aqa4s52zy" width="610" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The basic concept for how this works is by taking the ipfs native url and converting it to one that uses an &lt;a href="https://docs.ipfs.tech/concepts/ipfs-gateway/" rel="noopener noreferrer"&gt;ipfs gateway&lt;/a&gt;, in my case I've added the &lt;a href="https://ipfs.github.io/public-gateway-checker/" rel="noopener noreferrer"&gt;official ipfs gateways&lt;/a&gt; as the fallback and the &lt;a href="https://developers.cloudflare.com/web3/ipfs-gateway/" rel="noopener noreferrer"&gt;Cloudflare gateways&lt;/a&gt; as the primary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;IPFS_GATEWAY_URLS&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;https://&amp;lt;CID&amp;gt;.ipfs.cf-ipfs.com/&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;https://&amp;lt;CID&amp;gt;.ipfs.dweb.link/&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;https://cloudflare-ipfs.com/ipfs/&amp;lt;CID&amp;gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://gateway.ipfs.io/ipfs/&amp;lt;CID&amp;gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I make the URL I attempt to use the newer &lt;a href="https://docs.ipfs.tech/concepts/content-addressing/" rel="noopener noreferrer"&gt;CID v1 format&lt;/a&gt;, not to be confused with CID v0 which is less CORS friendly. To convert into this format which uses a case-insensitive base32 format, I used the library &lt;a href="https://www.npmjs.com/package/multiformats" rel="noopener noreferrer"&gt;multiformats&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;IPFS_GATEWAY_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getIpfsGatewayUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;ipfsUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;notCurrent&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;IPFS_GATEWAY_URL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;notCurrent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;urlList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;notCurrent&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;IPFS_GATEWAY_URLS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;url&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;url&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;IPFS_GATEWAY_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IPFS_GATEWAY_URLS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;urlList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;isIpfsGatewayAvailable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;IPFS_GATEWAY_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;IPFS_GATEWAY_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ipfsUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ipfs:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;multiformats/cid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;IPFS_GATEWAY_URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;CID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;CID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cid&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toV1&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;)}${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}${&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.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%2Fnibmb4qpp7xi326vmxns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fnibmb4qpp7xi326vmxns.png" alt="ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/wiki/Vincent_van_Gogh.html" width="659" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When doing the initial check to find the gateway to use, I've based the availability checker on code taken from &lt;a href="https://github.com/ipfs/public-gateway-checker" rel="noopener noreferrer"&gt;public-gateway-checker&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isIpfsGatewayAvailable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gatewayUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTimeout&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="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="mi"&gt;1000&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;img&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;Image&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&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;gatewayUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;CID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// https://github.com/ipfs/public-gateway-checker/blob/master/src/constants.ts&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bafybeibwzifw52ttrkqlikfzext5akxu7lz4xiwjgwzmqcpdzmp3n5vnbe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;?now=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;filename=1x1.png#x-ipfs-companion-no-redirect`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When it comes to actually doing the request, a normal &lt;code&gt;fetch()&lt;/code&gt; command is all that is needed with the new ipfs gateway url.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getIpfsResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ipfsUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;requestOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;omit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;keepalive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;referrerPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-referrer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;RequestInit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getIpfsGatewayUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ipfsUrl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;requestOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to fetch&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getIpfsGatewayUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ipfsUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;requestOptions&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;response&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.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%2Fzerk435338ytjelmts13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fzerk435338ytjelmts13.png" alt="ipfs://QmcniBv7UQ4gGPQQW2BwbD4ZZHzN3o3tPuNLZCbBchd1zh" width="676" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've also added file type detection so it can try to open the url in the correct app. This is done using the library &lt;a href="https://www.npmjs.com/package/file-type" rel="noopener noreferrer"&gt;file-type&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getIpfsFileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;ipfsUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ipfsData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt; &lt;span class="p"&gt;}&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;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ipfsUrl&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;fileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filename&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&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;fileName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fileTypeFromBuffer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file-type&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fileTypeFromBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ipfsData&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}${&lt;/span&gt;
    &lt;span class="nx"&gt;ext&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;ext&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="dl"&gt;""&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;I've found the reliability of the gateway's to be pretty good, but sometimes there was a large amount of lag before a request would begin.&lt;/p&gt;

&lt;p&gt;Thanks for reading my article and feel free to try out some ipfs urls on daedalOS which is also my personal website, &lt;a href="https://dustinbrett.com/" rel="noopener noreferrer"&gt;dustinbrett.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to know more about daedalOS which is the client of all this ipfs magic, feel free to check out my &lt;a href="https://www.youtube.com/c/DustinBrett" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt; video where I go over the various features, including ipfs. Thanks!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CkvKPspIPLs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>web3</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Top 25 Tips for Building an EXTREMELY FAST Website!!!</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Mon, 25 Jul 2022 05:39:25 +0000</pubDate>
      <link>https://dev.to/dustinbrett/top-25-tips-for-building-an-extremely-fast-website-iaf</link>
      <guid>https://dev.to/dustinbrett/top-25-tips-for-building-an-extremely-fast-website-iaf</guid>
      <description>&lt;p&gt;I recently did a live stream explaining what I considered the "Top 25" things I'd done to my website (&lt;a href="https://dustinbrett.com/" rel="noopener noreferrer"&gt;dustinbrett.com&lt;/a&gt;) to make it "&lt;strong&gt;FAST&lt;/strong&gt;". The video is over 2 hours so I was able to get into quite a bit of detail. An embedded video is at the bottom of this article.&lt;/p&gt;

&lt;p&gt;In this article I will try and summarize each tip and add a screenshot/links.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Content Delivery Network (CDN)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F7nyd6ewcwb8l6m9odvnv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F7nyd6ewcwb8l6m9odvnv.png" alt="CDN Stats" width="707" height="535"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This may be the best thing you can do to improve speed on your website. Getting the files to the user faster is something I've found to be the biggest gain in performance in my situation. My web server hosts files at quite a slow speed so it can take the user several seconds to resolve the DNS of my domain and get the initial files. Also my web server is centralized in one location. With the CDN it can serve cached versions of my static files from edge servers that are closer to the user requesting the files.&lt;/p&gt;

&lt;p&gt;In the case of CloudFlare, I use their free plan and route my DNS for dustinbrett.com through them. The it points back to my actual web server which is where CloudFlare goes to get files whenever the cache becomes invalidated/purged. CloudFlare also has a lot of customizations and toggles to make things faster yet. I've linked to information about the free plan and their guide optimizing site speed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cloudflare.com/en-ca/plans/free/" rel="noopener noreferrer"&gt;https://www.cloudflare.com/en-ca/plans/free/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/fundamentals/get-started/task-guides/optimize-site-speed/" rel="noopener noreferrer"&gt;https://developers.cloudflare.com/fundamentals/get-started/task-guides/optimize-site-speed/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. HTTP/2 &amp;amp; HTTP/3
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fdj689lxkjn6wy44rc6u4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdj689lxkjn6wy44rc6u4.png" alt="HTTP 3" width="568" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a simple trick as long as your web server / CDN supports it. Make sure to serve your content on the latest HTTP protocol as it offers performance optimizations in some cases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/HTTP/3#Comparison_with_HTTP/1.1_and_HTTP/2" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/HTTP/3#Comparison_with_HTTP/1.1_and_HTTP/2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Brotli Compression vs GZip
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F8at4ap0i9b4p1zrx6dpj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F8at4ap0i9b4p1zrx6dpj.png" alt="Brotli" width="398" height="267"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Another simple trick on the server side is to enable Brotli compression if it's supported. It's considered the successor to GZip and it does indeed seem to make things smaller, which ideally means faster and in this case it seems to be so.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Brotli" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Brotli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. HTTP Headers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Febpjof16yvvs0bqz14s0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Febpjof16yvvs0bqz14s0.png" alt="Cache Control" width="476" height="198"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This is important and ideally defaults to some sane values, but there are cases where if you don't setup rules you will serve files that are not cached and get requested every time. One place where I had ran into an issue was with &lt;code&gt;.ini&lt;/code&gt; files which the server didn't know were text and so served with a &lt;code&gt;Content-Type&lt;/code&gt; of &lt;code&gt;application/octet-stream&lt;/code&gt; which also seemed to set it's &lt;code&gt;Cache-Control&lt;/code&gt; to &lt;code&gt;max-age=0&lt;/code&gt;. It took me a while to notice this as I was going through my page load request headers in DevTools-&amp;gt;Network. The solution on my server side was to properly associate those extensions with MIME types like &lt;code&gt;text/plain&lt;/code&gt;, which had a sane &lt;code&gt;Cache-Control&lt;/code&gt; value of 1 week. The lesson here is to make sure you are sending proper cache headers to your users so their browsers know not to request things from your server unnecessarily.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/cache/about/cache-control/" rel="noopener noreferrer"&gt;https://developers.cloudflare.com/cache/about/cache-control/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Early Hints
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F6n4t4h3gimpppc13lvzz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F6n4t4h3gimpppc13lvzz.png" alt="Early Hints" width="800" height="207"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I have mixed feelings on this suggestion as I was not able to make it work properly with my responsive images which make use of &lt;code&gt;srcset&lt;/code&gt; (&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;)/&lt;code&gt;imagesrcset&lt;/code&gt; (&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;). In theory though this seems like a very useful feature and if I had other files I care to do this with, I would consider setting it up. But my ideal use case right now for this would only be images and for that I need to wait for a server that supports a responsive &lt;code&gt;Link&lt;/code&gt; header. I'd be happy to be proven wrong on this, but to me it seemed not possible if your images are based on dpi, to have the 103 Early Hints depend on the requesting browsers dpi and only send them the relevant image, instead of all resolutions. For anyone who is using non-responsive &lt;code&gt;link&lt;/code&gt; headers and is on CloudFlare or any other server supporting 103 Early Hints, this seems like a good feature as it will tell your users to get images before they've even seen your HTML with the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; preload tags.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/blog/new-in-chrome-103/#http103" rel="noopener noreferrer"&gt;https://developer.chrome.com/blog/new-in-chrome-103/#http103&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/blog/early-hints/" rel="noopener noreferrer"&gt;https://developer.chrome.com/blog/early-hints/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/cache/about/early-hints/" rel="noopener noreferrer"&gt;https://developers.cloudflare.com/cache/about/early-hints/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Handle Initial CDN MISS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fzi4k5oi14g8j3eubao88.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fzi4k5oi14g8j3eubao88.png" alt="CDN HIT" width="475" height="176"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This is partially a tip, although the more I think on it the more I question it's usefulness. For sites like mine that are under heavy development, to me it makes sense to purge cache often as I change quite a few files on a weekly basis. Because of this, every edge server needs to go to my slow web server before they can cache the file to serve to their nearer users. What I do is visit the site and make sure in the HTTP headers for CloudFlare that instead of a &lt;code&gt;MISS&lt;/code&gt; on cache from the edge server, it shows a &lt;code&gt;HIT&lt;/code&gt;. But when I think about this I realize it just caches it on the edge server that I happened to visit. So for me it's faster as subsequent visits are &lt;code&gt;HIT&lt;/code&gt;'s, but for users around the world they will get that slow initial request if someone on their edge has not already triggered the &lt;code&gt;MISS&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/cache/about/default-cache-behavior/#cloudflare-cache-responses" rel="noopener noreferrer"&gt;https://developers.cloudflare.com/cache/about/default-cache-behavior/#cloudflare-cache-responses&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. HSTS header
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F8fhsva1us667wfx86kbo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F8fhsva1us667wfx86kbo.png" alt="HSTS" width="488" height="291"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I'm not sure on what kind of performance boost this could possibly have, but I do like the idea of my domain being on a browser list somewhere that says, always visit this domain via HTTPS. By doing this you can avoid the minute slowdown from users that may visit your site via HTTP and ideally get redirected to HTTPS.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hstspreload.org/?domain=dustinbrett.com" rel="noopener noreferrer"&gt;https://hstspreload.org/?domain=dustinbrett.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. &lt;code&gt;&amp;lt;link /&amp;gt;&lt;/code&gt; preload &amp;amp; preconnect
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F075do4nnpxyz65bkzpni.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F075do4nnpxyz65bkzpni.png" alt="Link preload" width="764" height="291"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I've found these preload's to be quite useful as I can see in DevTools-&amp;gt;Network that the images begin loading before my dynamic website has decided it needs to show those images. With a site like mine where the content of the homepage is a desktop environment which the user can change, there is a chance that these preload headers may be of less use to users who have already visited my site and deleted the relevant dynamic content that would have shown those images. But to me it's worth it for most users that will do their first visit and see the images quicker because these HTML tags have told their browser to get images that I knew most users would need.&lt;/p&gt;

&lt;p&gt;This is also useful after load and I make use of it when a user hovers their cursor over the menu button. At the time of hover I inject preload link headers into the document head as most users don't click the menu button at the exact millisecond their mouse goes over it, this gives the browser some time to preload the images which are very likely to be in the menu. Again my website being dynamic, it's possible the user could change the content of the menu which would make some preload requests unnecessary. But it's a minute cost for return visitors who want a dynamic experience.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-type" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-type&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. fetchpriority
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqeau4dtszier83rahpjo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqeau4dtszier83rahpjo.png" alt="Priority" width="557" height="274"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This is another new feature only available on Chromium browsers currently, but if your users support it, it seems worth using. The &lt;code&gt;fetchpriority&lt;/code&gt; concept can be used for &lt;code&gt;img&lt;/code&gt;, &lt;code&gt;fetch&lt;/code&gt; &amp;amp; &lt;code&gt;link&lt;/code&gt;. For any requests that I want to happen asap, I specify &lt;code&gt;high&lt;/code&gt; priority.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://wicg.github.io/priority-hints/#link" rel="noopener noreferrer"&gt;https://wicg.github.io/priority-hints/#link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.dev/priority-hints/" rel="noopener noreferrer"&gt;https://web.dev/priority-hints/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. HTML Minify / Tag Removal
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F2pg5bq3pvn82m3ws5zll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F2pg5bq3pvn82m3ws5zll.png" alt="Index HTML" width="800" height="806"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've always liked to have a minimal amount of HTML when possible, so finding html-minifier-terser was quite nice as it removed tags I thought were require but it turns out they are not. Tags like &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;/html&amp;gt;&lt;/code&gt;. Also quotes often are not needed. This minification tool is quite good at removing useless HTML. Then I also run a script which removes other tags I don't care to have like &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; and some of the Next.js JSON data which I do not need.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/terser/html-minifier-terser" rel="noopener noreferrer"&gt;https://github.com/terser/html-minifier-terser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://validator.w3.org/" rel="noopener noreferrer"&gt;https://validator.w3.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/basic-features/pages#static-generation-recommended" rel="noopener noreferrer"&gt;https://nextjs.org/docs/basic-features/pages#static-generation-recommended&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/scripts/minifyHtml.js" rel="noopener noreferrer"&gt;https://github.com/DustinBrett/daedalOS/blob/main/scripts/minifyHtml.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  11. Image Minify / Simplify
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F9dksxuko5h5xog601wwi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F9dksxuko5h5xog601wwi.png" alt="FileOptimizer" width="709" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another thing I usually try and do is have the smallest images possible. I mention it more in other tips on ways I do it, but one useful way is through minification. I use the Windows tool FileOptimizer to do lossless compression on all my images. I also use SVGO to make SVG's smaller as often times the &lt;code&gt;path&lt;/code&gt; value can be simplified without any data/quality loss. Finally another simplification technique that I do which might not be totally ideal for everyone, is to use a minimal favicon setup. I use the absolute bare minimum which is just a favicon.ico file in the root and no supporting HTML to point to high resolution versions. Depending on your use case you may want to have some favicon tags, but keeping it as minimal as possible is still ideal.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nikkhokkho.sourceforge.io/static.php?page=FileOptimizer" rel="noopener noreferrer"&gt;https://nikkhokkho.sourceforge.io/static.php?page=FileOptimizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/scripts/createIcons.bat" rel="noopener noreferrer"&gt;https://github.com/DustinBrett/daedalOS/blob/main/scripts/createIcons.bat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jakearchibald.github.io/svgomg/" rel="noopener noreferrer"&gt;https://jakearchibald.github.io/svgomg/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML#adding_custom_icons_to_your_site" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML#adding_custom_icons_to_your_site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Favicon" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Favicon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12. WEBP vs PNG vs AVIF
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fkicgwqamguma00bt4t2a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fkicgwqamguma00bt4t2a.png" alt="WEBP Images" width="675" height="203"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;When it comes to which image format to use, it will depend a bit what type of image you want to represent. If it's a lossy photo you took on your camera, it's possible AVIF may be ideal. If it's a lossless thumbnail/icon, then WEBP may offer better results, especially if you don't need some of the new features AVIF provides. But as long as your users support it, I think we should happily migrate to the modern AVIF/WEBP image formats over JPG/PNG for most cases as it seems to be the same visual quality in a smaller file in my experience.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://avif.io/blog/comparisons/avif-vs-webp/" rel="noopener noreferrer"&gt;https://avif.io/blog/comparisons/avif-vs-webp/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://caniuse.com/webp" rel="noopener noreferrer"&gt;https://caniuse.com/webp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/speed/webp/docs/cwebp" rel="noopener noreferrer"&gt;https://developers.google.com/speed/webp/docs/cwebp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  13. Lazy Loading / Intersection Observer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbpe0kvearj4b7gzah07z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbpe0kvearj4b7gzah07z.png" alt="Lazy loading" width="644" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use several forms of lazy loading, but the most useful one for my load times has to be dynamic imports. This allows me to avoid bundling most of my app on load. Instead the components/modules are loaded on demand from chunks that Webpack has created.&lt;/p&gt;

&lt;p&gt;Another way I do lazy loading is for all icons that represents files or folders. It does not load the icon until it detects that image has gone into the viewport. In the case of dynamic icons which require grabbing the file itself, for those I use JavaScript and the Intersection Observer to run the &lt;code&gt;getIcon&lt;/code&gt; function when the button of the icon reaches the viewport.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/advanced-features/dynamic-import" rel="noopener noreferrer"&gt;https://nextjs.org/docs/advanced-features/dynamic-import&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  14. Testing Lighthouse / GTMetrix / WebpageTest
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F2klr5tu4lky8luu88g2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F2klr5tu4lky8luu88g2b.png" alt="Lighthouse" width="616" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Testing changes as you make them is the best way to know if what you are doing is going in the right direction. Many of the changes I've done have been based off of findings from tests like these. It's important to remember that these tests offer suggestions but that they don't fully understand your website and they can sometimes offer suggestions for things that are not worth doing and would make basically no impact to your users.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/GoogleChrome/lighthouse" rel="noopener noreferrer"&gt;https://github.com/GoogleChrome/lighthouse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pagespeed.web.dev/" rel="noopener noreferrer"&gt;https://pagespeed.web.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gtmetrix.com/" rel="noopener noreferrer"&gt;https://gtmetrix.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.webpagetest.org/" rel="noopener noreferrer"&gt;https://www.webpagetest.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  15. Web Workers &amp;amp; Offscreen Canvas
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fv43haxqezk3sbbhyxkyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fv43haxqezk3sbbhyxkyl.png" alt="Threads" width="800" height="333"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This to me is a very cool browser technology that I love to try and use whenever possible. Both my clock and wallpaper run in web workers and both of them paint their updates to offscreen canvases. Another advantage of moving my website components to this system is that if the main thread freezes, the clock and wallpaper continue. At the moment most useful things still run on the main thread, but I hope one day to move everything into separate web workers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Main_thread" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Glossary/Main_thread&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://partytown.builder.io/" rel="noopener noreferrer"&gt;https://partytown.builder.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  16. Target Modern Browsers (Avoid Polyfills &amp;amp; ES5)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqcamzrwzdsnq8g91idhb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqcamzrwzdsnq8g91idhb.png" alt="ESNext" width="737" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have the luxury to not need to support very old browsers like IE, then I think it's time to drop as many polyfills as possible and to rely on modern browsers to have the functionality we need without having to give the user more code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://caniuse.com/?search=es6" rel="noopener noreferrer"&gt;https://caniuse.com/?search=es6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/browserslist/browserslist" rel="noopener noreferrer"&gt;https://github.com/browserslist/browserslist&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  17. Advanced Library Settings
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fchvxfzti69mqrf6xp1p3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fchvxfzti69mqrf6xp1p3.png" alt="Next Config" width="461" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is going to be specific to what libraries and frameworks you are using. In my case, 3 places where I was able to add additional optimizations was with Next.js, Framer Motion &amp;amp; Styled Components. In all cases there are advanced configurations which I love to go through to find little tweaks I can add when possible. Whenever I add something from &lt;code&gt;npm&lt;/code&gt; I look for advanced configuration settings, just to know what's possible and if I like the defaults.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/advanced-features/compiler" rel="noopener noreferrer"&gt;https://nextjs.org/docs/advanced-features/compiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.framer.com/docs/guide-reduce-bundle-size/" rel="noopener noreferrer"&gt;https://www.framer.com/docs/guide-reduce-bundle-size/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://styled-components.com/docs/tooling#dead-code-elimination" rel="noopener noreferrer"&gt;https://styled-components.com/docs/tooling#dead-code-elimination&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  18. Prebuild JSON (fs, search, preloads)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fy2q3c03c4g5rlv67bmgj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fy2q3c03c4g5rlv67bmgj.png" alt="Prebuilt JSON's" width="243" height="191"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This is an optimization I like to do whenever I notice I'm making the same JSON structure within my code. That is often a chance to make it once and access it via a static file, which is often faster, but not always, so test it. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/api/fs.html" rel="noopener noreferrer"&gt;https://nodejs.org/api/fs.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/scripts/searchIndex.js" rel="noopener noreferrer"&gt;https://github.com/DustinBrett/daedalOS/blob/main/scripts/searchIndex.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/scripts/preloadIcons.js" rel="noopener noreferrer"&gt;https://github.com/DustinBrett/daedalOS/blob/main/scripts/preloadIcons.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/DustinBrett/daedalOS/blob/main/scripts/fs2json.js" rel="noopener noreferrer"&gt;https://github.com/DustinBrett/daedalOS/blob/main/scripts/fs2json.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  19. Bundle Analyzer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fbs860ruccu9gqp5qaafz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbs860ruccu9gqp5qaafz.png" alt="Client Bundle" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I actually took the time to look at my bundle and what was in it, I realized I had imported a lot of unnecessary things on the main app bundle that users were getting on load. This is a very helpful tool for seeing what is inside your Webpack files and then you can go in and use dynamic &lt;code&gt;import&lt;/code&gt; to split it into it's own chunk which will only be loaded when needed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/webpack-bundle-analyzer" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/webpack-bundle-analyzer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  20. Inline CSS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F8x7dqa8vc1gmfbfb8l6t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F8x7dqa8vc1gmfbfb8l6t.png" alt="Page Load CSS" width="589" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Loading CSS in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element I think is still considered to be one of the fastest ways to get styling to the user. One advantage with using styled components and most CSS-in-JS solutions is that it can inline relevant CSS in the static HTML file so that it's ready to go as soon as possible. I don't personally use any CSS files, but if someone was to go that route, other tips such as the CDN, link preload &amp;amp; Early Hints can improve loading for those files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://styled-components.com/" rel="noopener noreferrer"&gt;https://styled-components.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/callstack/linaria" rel="noopener noreferrer"&gt;https://github.com/callstack/linaria&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  21. Defer JavaScript
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fac14r5lgf64h5thgchpy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fac14r5lgf64h5thgchpy.png" alt="Deferred Scripts" width="695" height="180"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This tip comes for free with some frameworks which already use this attribute, but it's good to keep in mind that if you have &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; that you can use &lt;code&gt;defer&lt;/code&gt; so they aren't parser-blocking and they can execute after &lt;code&gt;DOMContentLoaded&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  22. System Fonts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fxd8nqabcmb2qs55gk0ej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxd8nqabcmb2qs55gk0ej.png" alt="Font family" width="347" height="57"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This may not work for everyone but for me who is making a desktop environment in the browser, it seemed like the perfect fit to just use the operating systems "system" font whenever possible. An important performance advantage of this is that the user doesn't have to download any font as they already have what they need. One issue with this will be consistency between operating systems, but I've found in general the fonts are similar and familiar to the users.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://systemfontstack.com/" rel="noopener noreferrer"&gt;https://systemfontstack.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/font-family" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/font-family&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  23. Async Image Decoding
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fu2jx72ojqrwar795tih7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fu2jx72ojqrwar795tih7.png" alt="Async Decoding" width="800" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't have much to say about this one other than to say that based on the description, if you want to "reduce delay in presenting other content", you should use &lt;code&gt;decoding=async&lt;/code&gt;. It likely makes a very minor difference, but perhaps with larger images this could be a noticeable change.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decoding" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decoding&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  24. Responsive Images
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F577zhj13elvdas3mbfwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F577zhj13elvdas3mbfwb.png" alt="Responsive Image" width="800" height="350"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; gives you a lot more control over images. Being able to load different images depending on what the browser supports and the state of media queries allows loading of the perfect sized image in any situation, so the browser doesn't need to resize something which either means the image was too small or too big, neither being ideal.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://caniuse.com/mdn-html_elements_link_imagesrcset" rel="noopener noreferrer"&gt;https://caniuse.com/mdn-html_elements_link_imagesrcset&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/resolution" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/@media/resolution&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  25. Define Image Dimensions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fw3g9az3poiv6eq7vzpw3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fw3g9az3poiv6eq7vzpw3.png" alt="Defined image" width="599" height="186"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;My final tip and an important one for content layout shift is to define the dimensions of images whenever possible. When you define the height and width the browser is able to allocate space ahead of time instead of moving elements on the page as the image loads and the browser realizes it's height and width which were not provided to it in advance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://caniuse.com/?search=aspect-ratio" rel="noopener noreferrer"&gt;https://caniuse.com/?search=aspect-ratio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.dev/cls/" rel="noopener noreferrer"&gt;https://web.dev/cls/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Thanks for reading!
&lt;/h3&gt;

&lt;p&gt;I appreciate you taking the time to read my article. If you'd like an in depth demonstration of these tips, below I've added my live stream where I spent over 2 hours going over them and showing their functioning within my website (&lt;a href="https://dustinbrett.com/" rel="noopener noreferrer"&gt;dustinbrett.com&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/XZHNqEbuUMI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>Adding Animated Wallpapers to my Personal Website / Desktop Environment</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Sat, 11 Jun 2022 16:39:45 +0000</pubDate>
      <link>https://dev.to/dustinbrett/adding-animated-wallpapers-to-my-personal-website-desktop-environment-11do</link>
      <guid>https://dev.to/dustinbrett/adding-animated-wallpapers-to-my-personal-website-desktop-environment-11do</guid>
      <description>&lt;p&gt;For several years now I've been building my &lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;Desktop environment in the browser (daedalOS)&lt;/a&gt; and have been using the &lt;a href="https://www.vantajs.com/" rel="noopener noreferrer"&gt;Vanta.js&lt;/a&gt; animated wallpaper called &lt;a href="https://www.vantajs.com/?effect=waves" rel="noopener noreferrer"&gt;Waves&lt;/a&gt;. Last month I added my 2nd animated wallpaper called &lt;a href="https://znah.net/hexells/" rel="noopener noreferrer"&gt;Hexells&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then last week I was checking out the website &lt;a href="https://www.shadertoy.com/" rel="noopener noreferrer"&gt;Shadertoy&lt;/a&gt; when I came across &lt;a href="https://www.shadertoy.com/view/fstyD4" rel="noopener noreferrer"&gt;Coastal Landscape&lt;/a&gt;. I thought it looked quite nice and it reminded me of a Windows XP wallpaper mixed with Van Gogh. After some hacking around with their embedded player I was able to get it to run in an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" rel="noopener noreferrer"&gt;Web Worker&lt;/a&gt; using an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas" rel="noopener noreferrer"&gt;OffscreenCanvas&lt;/a&gt; which is also what I did for my other animated wallpapers. This keeps their animation work off of the &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Main_thread" rel="noopener noreferrer"&gt;Main thread&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fv03u346nkpcxyt41ei19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fv03u346nkpcxyt41ei19.png" alt="Coastal Landscape on Shadertoy" width="536" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also last week while inspired by animated wallpapers I decided I'd like to revisit some features I wanted to add to my Winamp player, powered by &lt;a href="https://webamp.org/" rel="noopener noreferrer"&gt;Webamp&lt;/a&gt;. Specially I wanted to add streaming support and then get Milkdrop working which is powered by &lt;a href="https://butterchurnviz.com/" rel="noopener noreferrer"&gt;Butterchurn&lt;/a&gt;. It is easy enough to add Butterchurn as there are already instructions on &lt;a href="https://github.com/captbaritone/webamp" rel="noopener noreferrer"&gt;their repository&lt;/a&gt; on how to do that. But what I wanted was an even lazier version of this code that would only load Butterchurn and it's presets if Milkdrop was open and the music playing. To do this I needed to add some custom handlers/logic which Webamp mostly supported.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fs3kg8vc6w65xl25ghqdz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fs3kg8vc6w65xl25ghqdz.png" alt="Wallpaper Menu" width="394" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I got that working I wanted to add the ability for the "Desktop Mode" feature to work which would allow the music visualizer to become an animated wallpaper. To do this I just had to move the DOM element into my &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; container so that it would properly sit behind the icons/taskbar but above the default animated wallpaper.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fhpiuz1jhih0meqe0cqub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fhpiuz1jhih0meqe0cqub.png" alt="Milkdrop Desktop mode" width="271" height="113"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Then to add streaming support it turned out all that was really missing was the ability to pass those URL's to Webamp. To do this I added handlers for Load Playlist and Load URL which would take a URL such as a direct stream or a playlist file (M3U/PLS/ASX) and load that into Webamp to be played. To do this I used &lt;a href="https://github.com/nickdesaulniers/javascript-playlist-parser" rel="noopener noreferrer"&gt;javascript-playlist-parser&lt;/a&gt; which did exactly what I wanted and supported 3 playlist file types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F09n8w5vzridd6pmb9wgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F09n8w5vzridd6pmb9wgx.png" alt="Webamp Streaming" width="330" height="267"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Once I had this working then it is just a matter of finding a URL that can work over CORS which means you can go to &lt;a href="https://dustinbrett.com" rel="noopener noreferrer"&gt;https://dustinbrett.com&lt;/a&gt; and load a URL that is not from that domain. This ended up being easier than I expected because in my search for classic streams I recalled as a kid that ran on &lt;a href="https://en.wikipedia.org/wiki/Shoutcast" rel="noopener noreferrer"&gt;Shoutcast&lt;/a&gt; servers, I found &lt;a href="https://somafm.com/" rel="noopener noreferrer"&gt;SomaFM&lt;/a&gt; which was exactly what I was looking for. It has the station &lt;a href="https://somafm.com/groovesalad/" rel="noopener noreferrer"&gt;Groove Salad&lt;/a&gt; which is exactly the one I listened to as a kid. Although the one I remember as a kid is now called &lt;a href="https://somafm.com/gsclassic/" rel="noopener noreferrer"&gt;Groove Salad Classic&lt;/a&gt;. SomaFM supports M3U, PLS &amp;amp; ASX playlist files and works over CORS.&lt;/p&gt;

&lt;p&gt;Finally I made a video recently showing these features. Feel free to check it out and throw me a like/subscribe if you enjoyed the video/article. Thanks!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/R1XniLFptEM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A Day in the Life of a Software Engineer at Microsoft in Vancouver</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Fri, 08 Apr 2022 18:25:43 +0000</pubDate>
      <link>https://dev.to/dustinbrett/a-day-in-the-life-of-a-software-engineer-at-microsoft-in-vancouver-52of</link>
      <guid>https://dev.to/dustinbrett/a-day-in-the-life-of-a-software-engineer-at-microsoft-in-vancouver-52of</guid>
      <description>&lt;p&gt;I've been wanting to make a video of my day as a developer for years now. Finally I have taken the time to make it! This is a REAL look at my life with my family, living in Vancouver/Richmond and working at Microsoft. I also work on my &lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;side project&lt;/a&gt; in the evening.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/fLALPAri2oA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>career</category>
      <category>devjournal</category>
      <category>motivation</category>
    </item>
    <item>
      <title>WebAssembly in my Browser Desktop Environment</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Mon, 28 Mar 2022 16:22:01 +0000</pubDate>
      <link>https://dev.to/dustinbrett/webassembly-in-my-browser-desktop-environment-3n06</link>
      <guid>https://dev.to/dustinbrett/webassembly-in-my-browser-desktop-environment-3n06</guid>
      <description>&lt;p&gt;For over a year now I've been working on &lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;daedalOS&lt;/a&gt;, my desktop environment in the browser. At the start of 2022 I published the app as &lt;a href="https://dustinbrett.com/" rel="noopener noreferrer"&gt;my website&lt;/a&gt; for everyone to play with.&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://dustinbrett.com/" rel="noopener noreferrer"&gt;dustinbrett.com&lt;/a&gt;&lt;br&gt;
Source Code: &lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;daedalOS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the WebAssembly audience I wanted to discuss the many features I've integrated into my desktop environment which use WebAssembly. Here is a list in no particular order:&lt;/p&gt;
&lt;h2&gt;
  
  
  x86 Emulation via &lt;a href="https://github.com/copy/v86" rel="noopener noreferrer"&gt;v86&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I support dragging &lt;code&gt;.iso&lt;/code&gt; &amp;amp; &lt;code&gt;.img&lt;/code&gt; files into the app which can be ran on v86. It also comes loaded with &lt;a href="https://dustinbrett.com/?url=/Users/Public/Documents/Disk%20Images/kolibri.img" rel="noopener noreferrer"&gt;Kolibri&lt;/a&gt; and &lt;a href="https://dustinbrett.com/?app=V86&amp;amp;url=/Users/Public/Documents/Disk%20Images/linux4.iso" rel="noopener noreferrer"&gt;Linux&lt;/a&gt;. When an app is closed a snapshot of the current state is saved to &lt;code&gt;/Users/Public/Snapshots&lt;/code&gt; which is automatically loaded the next time the same image is opened.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fzuvx2f2t43fuqr6pba6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fzuvx2f2t43fuqr6pba6j.png" alt="V86 running Kolibri" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  DOS Emulation via &lt;a href="https://github.com/caiiiycuk/js-dos" rel="noopener noreferrer"&gt;js-dos&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;For this app you can open any &lt;code&gt;.zip&lt;/code&gt; or &lt;code&gt;.jsdos&lt;/code&gt; file in it. If you don't provide a jsdos config file it will boot to the command prompt. I have some preloaded DOS shareware games such as &lt;a href="https://dustinbrett.com/?url=/Users/Public/Documents/DOS%20Bundles/doom.jsdos" rel="noopener noreferrer"&gt;Doom&lt;/a&gt; and &lt;a href="https://dustinbrett.com/?url=/Users/Public/Documents/DOS%20Bundles/dn3d.jsdos" rel="noopener noreferrer"&gt;Duke Nukem 3D&lt;/a&gt;. Like v86 it will save snapshots on close and reload them on reopen, but instead of loading the emulator state it just loads the directory contents such as save games.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Ft1x4tiuaofod9z6qm5n9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Ft1x4tiuaofod9z6qm5n9.png" alt="JS-DOS running Duke Nukem 3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  WINE (16/32-bit) via &lt;a href="https://github.com/danoon2/Boxedwine" rel="noopener noreferrer"&gt;Boxedwine&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This also supports &lt;code&gt;.zip&lt;/code&gt; files and will try and run &lt;code&gt;.exe&lt;/code&gt; too. It can run various apps as BoxedWine shows on their &lt;a href="http://www.boxedwine.org/search-apps/?_sft_feature=demo" rel="noopener noreferrer"&gt;Apps and Games&lt;/a&gt; page. As an example I downloaded the latest &lt;code&gt;32-bit x86 Portable (zip)&lt;/code&gt; version of &lt;a href="https://notepad-plus-plus.org/downloads/" rel="noopener noreferrer"&gt;Notepad++&lt;/a&gt;, shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Ffoz48d6eku4fewi36gna.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Ffoz48d6eku4fewi36gna.png" alt="BoxedWine running Notepad++" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Flash Emulation via &lt;a href="https://github.com/ruffle-rs/ruffle" rel="noopener noreferrer"&gt;Ruffle&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This app supports &lt;code&gt;.swf&lt;/code&gt; and &lt;code&gt;.spl&lt;/code&gt; files. I have a few fun demos on my site such as the &lt;a href="https://dustinbrett.com/?url=/Users/Public/Documents/Flash%20Files/badger.swf" rel="noopener noreferrer"&gt;Badger Badger Badger&lt;/a&gt; and &lt;a href="https://dustinbrett.com/?url=/Users/Public/Documents/Flash%20Files/Windows%20RG%20Build%20207.swf" rel="noopener noreferrer"&gt;Windows RG (Really Good Edition)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fopl8h3ulhtfv6niw4lch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fopl8h3ulhtfv6niw4lch.png" alt="Ruffle running Badger" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  7z/RAR/TAR Extraction via &lt;a href="https://github.com/nika-begiashvili/libarchivejs" rel="noopener noreferrer"&gt;Libarchivejs&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I support &lt;code&gt;.zip&lt;/code&gt; &amp;amp; &lt;code&gt;.iso&lt;/code&gt; mounting through non-WebAssembly methods, so to handle &lt;code&gt;.7z&lt;/code&gt;, &lt;code&gt;.rar&lt;/code&gt;, &lt;code&gt;.tar&lt;/code&gt; &amp;amp; &lt;code&gt;.tar.gz&lt;/code&gt; I've added Libarchive.js. Extracting is done from the right click context menu on each file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fx82537apn7bkhx01qgfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fx82537apn7bkhx01qgfl.png" alt="Files extracted via Libarchive.js" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Audio/Video Conversion via &lt;a href="https://github.com/ffmpegwasm/ffmpeg.wasm" rel="noopener noreferrer"&gt;ffmpeg.wasm&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Currently only supporting single thread because of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements" rel="noopener noreferrer"&gt;SharedArrayBuffer limitation&lt;/a&gt; and my desire to not deal with CORS issues. For video you can convert &lt;code&gt;.avi&lt;/code&gt;, &lt;code&gt;.flv&lt;/code&gt;, &lt;code&gt;.m4v&lt;/code&gt;, &lt;code&gt;.mov&lt;/code&gt;, &lt;code&gt;.mp4&lt;/code&gt;, &lt;code&gt;.mpeg&lt;/code&gt;, &lt;code&gt;.ogv&lt;/code&gt;, &lt;code&gt;.webm&lt;/code&gt; &amp;amp; &lt;code&gt;.wmv&lt;/code&gt;. For audio it supports converting &lt;code&gt;.aac&lt;/code&gt;, &lt;code&gt;.aiff&lt;/code&gt;, &lt;code&gt;.ape&lt;/code&gt;, &lt;code&gt;.flac&lt;/code&gt;, &lt;code&gt;.m4a&lt;/code&gt;, &lt;code&gt;.mp3&lt;/code&gt;, &lt;code&gt;.oga&lt;/code&gt;, &lt;code&gt;.ogg&lt;/code&gt; &lt;code&gt;.wav&lt;/code&gt; &amp;amp; &lt;code&gt;.wma&lt;/code&gt;. These conversion options can be access via the context menu on each file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2F5xkk8cvi77pdnrvwtd5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2F5xkk8cvi77pdnrvwtd5a.png" alt="File converted from MP4 to MKV" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Image Conversion via &lt;a href="https://github.com/KnicKnic/WASM-ImageMagick" rel="noopener noreferrer"&gt;WASM-ImageMagick&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Similar to audio/video, I support various formats of images that can be converted. They are &lt;code&gt;.bmp&lt;/code&gt;, &lt;code&gt;.gif&lt;/code&gt;, &lt;code&gt;.ico&lt;/code&gt;, &lt;code&gt;.jpg&lt;/code&gt;, &lt;code&gt;.png&lt;/code&gt;, &lt;code&gt;.psd&lt;/code&gt;, &lt;code&gt;.tiff&lt;/code&gt; &amp;amp; &lt;code&gt;.xcf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2F3kvmgcsy3zcmoz6oqj0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2F3kvmgcsy3zcmoz6oqj0w.png" alt="File converted from JPG to PNG" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Python via &lt;a href="https://github.com/pyodide/pyodide" rel="noopener noreferrer"&gt;Pyodide&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I've added support to run &lt;code&gt;.py&lt;/code&gt; scripts in the terminal. It's also possible to open the &lt;a href="https://dustinbrett.com/?app=Terminal" rel="noopener noreferrer"&gt;Terminal&lt;/a&gt; directly and run a command such as &lt;code&gt;py import sys; sys.version&lt;/code&gt; to see the same result as this example script.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2F4e3qi3pe1azvalzykc5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2F4e3qi3pe1azvalzykc5l.png" alt="Running a Python script" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  WASI Modules via &lt;a href="https://github.com/wasmerio/wasmer-js" rel="noopener noreferrer"&gt;Wasmer JS&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I've added limited support to run &lt;a href="https://wapm.io/" rel="noopener noreferrer"&gt;wapm.io&lt;/a&gt; directly from the &lt;a href="https://dustinbrett.com/?app=Terminal" rel="noopener noreferrer"&gt;Terminal&lt;/a&gt;. Examples of commands that work well are &lt;code&gt;wapm cowsay {Text}&lt;/code&gt; and &lt;code&gt;wapm uuid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fnqs09d4l7qhk372zyzzm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fnqs09d4l7qhk372zyzzm.png" alt="Running wapm commands in Terminal" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Space Cadet via &lt;a href="https://github.com/k4zmu2a/SpaceCadetPinball" rel="noopener noreferrer"&gt;SpaceCadetPinball&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Finally for a blast from the past I've added &lt;a href="https://dustinbrett.com/?app=SpaceCadet" rel="noopener noreferrer"&gt;3D Pinball Space Cadet&lt;/a&gt; which has been ported to many platforms including to WebAssembly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fn75f0uvah78q63lmc2qq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wasm.builders%2Fremoteimages%2Fuploads%2Farticles%2Fn75f0uvah78q63lmc2qq.png" alt="Playing Space Cadet" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Future...
&lt;/h2&gt;

&lt;p&gt;Thanks for checking out my post/app!!! If you'd like to follow my progress as I continue to play with &lt;a href="https://www.youtube.com/c/DustinBrett/videos" rel="noopener noreferrer"&gt;all things web/dev&lt;/a&gt;, please check out my &lt;a href="https://www.youtube.com/c/DustinBrett" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt;. Here is my latest video where I discuss progress on this app:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Jj18hV82FeI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Pushing The Limits Of The Modern Browser</title>
      <dc:creator>Dustin Brett</dc:creator>
      <pubDate>Thu, 24 Feb 2022 07:14:59 +0000</pubDate>
      <link>https://dev.to/dustinbrett/pushing-the-limits-of-the-modern-browser-17bh</link>
      <guid>https://dev.to/dustinbrett/pushing-the-limits-of-the-modern-browser-17bh</guid>
      <description>&lt;p&gt;This last month has been another fun experience in pushing the limits of browsers. As I continue to work on my &lt;a href="https://github.com/DustinBrett/daedalOS" rel="noopener noreferrer"&gt;desktop environment in the browser&lt;/a&gt; I keep finding new ideas for features to add to make it more useful.&lt;/p&gt;

&lt;p&gt;I use my project as a way to try what is basically proof of concepts, either because of low browser support or poor performance. I have a few examples I have been working with that I wanted to share:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API" rel="noopener noreferrer"&gt;File System Access API&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Based on an &lt;a href="https://web.dev/file-system-access/#storing-file-handles-or-directory-handles-in-indexeddb" rel="noopener noreferrer"&gt;article&lt;/a&gt; I had read about storing directory handles and a comment from a Reddit user, I decided my app needed to be able to retain mapped directories.&lt;/p&gt;

&lt;p&gt;It turned out to be quite easy as all I had to do was store the &lt;code&gt;handle&lt;/code&gt; object inside IndexedDb and then get it again on load. The only real challenges were that I needed to re-request permissions if the tab is closed so I added a mechanism to query for permissions and request them on load of a mapped folder. The other challenge was how to easily write to IndexedDb, and for that I went with &lt;a href="https://www.npmjs.com/package/idb-keyval" rel="noopener noreferrer"&gt;idb-keyval&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://ffmpegwasm.netlify.app/" rel="noopener noreferrer"&gt;Audio/Video Conversion&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;For this I have integrated &lt;a href="https://ffmpegwasm.netlify.app/" rel="noopener noreferrer"&gt;FFMpeg&lt;/a&gt; in WebAssembly form and added it to the terminal as a cli command and to the right click context menus of relevant file types. An example would be that I could now convert mp4 into mkv. A large downside of the approach I have had to do in order to avoid SharedArrayBuffer, is that it runs on the main thread and basically locks up everything except the wallpaper until it's done. But I hope to eventually solve this as they make improvements to the browsers ability to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements" rel="noopener noreferrer"&gt;mitigate Spectre&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/KnicKnic/WASM-ImageMagick" rel="noopener noreferrer"&gt;Image Conversion&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I've gone with &lt;a href="https://github.com/KnicKnic/WASM-ImageMagick" rel="noopener noreferrer"&gt;ImageMagick&lt;/a&gt; ported to WebAssembly to do basically the exact same things as with FFMpeg, but with a tiny bit less locking up. In the future I would like to get these things running in multithreaded Web Workers as well as have the ability to easily configure transcode settings to whatever is desired instead of the defaults as it is now.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://lunrjs.com/" rel="noopener noreferrer"&gt;File Search&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I wanted to keep things client side as I only desire to host static files on a web server. To make this work I knew I was going to go with a prebuilt index. I created a script to go through the public directory and grab all indexable content from file names and non-binary files. This turns into a JSON file which I load as soon as the user types into the search box. To achieve this I am using a library called &lt;a href="https://lunrjs.com/" rel="noopener noreferrer"&gt;Lunr&lt;/a&gt;. As additional secret sauce, after the static index is search, results are appended for a dynamic search that is done on any content stored on the writable portion of the file system. This allows searching new content as it's changed/added.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://ircdocs.horse/tools/wstester" rel="noopener noreferrer"&gt;IRC Client&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;And finally the IRC client. I have been wanting to do this for a while and I have to say it is 100% NOT done. Currently it is a proof of concept but I do plan to build a tabbed interface and channel lists so it can function like a proper IRC client. The idea had been going on since I read IRC v3 spec public servers were hosting WebSocket servers now that anyone could connect to. I recently say a great &lt;a href="https://ircdocs.horse/tools/wstester" rel="noopener noreferrer"&gt;POC tester&lt;/a&gt; with code which convinced me to start making it. As it is now I can connect to the 3 public servers (irc.unrealircd.org, testnet.ergo.chat/webirc &amp;amp; testnet.inspircd.org) I know about and communicate directly with them using IRC commands like LIST &amp;amp; JOIN.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://youtu.be/cEsbZtDT8h0" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Thanks for reading my article. If you'd like to check out a demo I did of all these features during my monthly round-up video for my project, please check it out below and like/subscribe if you enjoyed it.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/cEsbZtDT8h0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
