<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Greg, The JavaScript Whisperer</title>
    <description>The latest articles on Forem by Greg, The JavaScript Whisperer (@jswhisperer).</description>
    <link>https://forem.com/jswhisperer</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%2F18890%2F44d4a03c-52c2-4e92-ab52-5927fab3ca71.jpg</url>
      <title>Forem: Greg, The JavaScript Whisperer</title>
      <link>https://forem.com/jswhisperer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jswhisperer"/>
    <language>en</language>
    <item>
      <title>apple macos time-machine</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Mon, 15 Sep 2025 17:25:53 +0000</pubDate>
      <link>https://forem.com/jswhisperer/apple-macos-time-machine-5f39</link>
      <guid>https://forem.com/jswhisperer/apple-macos-time-machine-5f39</guid>
      <description>&lt;p&gt;Quick tip: disable throttling to quickly create a backup&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo sysctl debug.lowpri_throttle_enabled=0&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://eclecticlight.co/2024/12/18/is-it-worth-storing-time-machine-backups-on-a-faster-drive/#:~:text=Results%20from%20the%20three%20first,write%20speed%20of%20the%20SSD." rel="noopener noreferrer"&gt;otherwise you get around 300/mbps &lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>performance</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Let's GET perfy</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Sat, 07 Jun 2025 02:57:06 +0000</pubDate>
      <link>https://forem.com/jswhisperer/lets-get-perfy-33ac</link>
      <guid>https://forem.com/jswhisperer/lets-get-perfy-33ac</guid>
      <description>&lt;h2&gt;
  
  
  Oh hello again, been a minute, howzit?
&lt;/h2&gt;

&lt;p&gt;So I thought I'd write a post about performance; I been kinda weirdly obsessed for at least 15 years; I think I got hooked by legends like &lt;a href="https://www.paulirish.com/" rel="noopener noreferrer"&gt;Paul Irish&lt;/a&gt; and &lt;a href="https://addyosmani.com/" rel="noopener noreferrer"&gt;Addy&lt;/a&gt; and &lt;a href="https://brucelawson.co.uk/2013/hello-blink/#:~:text=Its%20architecture%20allows%20for%20greater,%C2%A32%2C%20on%20Bandcamp." rel="noopener noreferrer"&gt;Bruce L&lt;/a&gt; back in the day.&lt;/p&gt;

&lt;p&gt;Anyway I previously &lt;a href="https://www.slideshare.net/slideshow/web-optimisation-finished-19978192/19978192" rel="noopener noreferrer"&gt;shared my first perf talk &lt;/a&gt;in Cape Town, from 15 years ago... and my &lt;a href="https://jswhisperer.uk/post/revisiting-my-first-homepage/" rel="noopener noreferrer"&gt;original website&lt;/a&gt; which somehow still scores 100s across the board in lighthouse.&lt;/p&gt;

&lt;p&gt;I thought I'd share some ideas and tools I've tried more recently and some blueprints for next level performance. I really love solving 'unsolvable' issues with creative, wild, out the box thinking.&lt;/p&gt;

&lt;p&gt;So basics first easy wins, thing like http/2/3 speedy protocol, this is easily achievable with a reverse proxy tool like Caddy covered here, slick, modern, concise and performant &lt;a href="https://jswhisperer.uk/post/caddy-2/" rel="noopener noreferrer"&gt;https://jswhisperer.uk/post/caddy-2/&lt;/a&gt; or something excessively verbose, and old like nginx (kinda like comparing Vue to React I've heard ...kidding)&lt;/p&gt;

&lt;p&gt;Along with the basics like cache headers and compression headers brotli, gzip&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/jswhisperer/browser-compression-options-2025-4gc9"&gt;read more&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/pieroxy/lz-string" rel="noopener noreferrer"&gt;lz-string&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;\&lt;br&gt;
Probably many cases would be covered by good server compression, brotli, gzip, etc, and proper headers. something like &lt;a href="https://github.com/ueffel/caddy-brotli" rel="noopener noreferrer"&gt;this&lt;/a&gt; However there are some great cases where the server can't help you, or maybe you don't control it.&lt;/p&gt;

&lt;p&gt;What about HTML Web Storage API's especially on mobile? Why not be a good Samaritan and compress before storing in localStorage, indexedDB etc; hell even cookies. Added benefit much less friendly to tamper with for your average joe.&lt;/p&gt;

&lt;p&gt;Next hidden gem that I think will become mainstream soon Protocol Buffers! (I only use things before they become cool) Often called Protobuf. It's been but on a pedestal &lt;a href="https://auth0.com/blog/beating-json-performance-with-protobuf/" rel="noopener noreferrer"&gt;for over a decade &lt;/a&gt; Actual results have and real world usage at least in the javascript world have been a bit dismal ...like slower than built in JSON.parse.&lt;/p&gt;

&lt;p&gt;However the last couple years show some promise. There is  which is &lt;a href="https://github.com/bufbuild/protobuf-es" rel="noopener noreferrer"&gt;this&lt;/a&gt; very compliant, and runs in the browser; but probably if youre looking to implement protobufs you are focused on speed?&lt;/p&gt;

&lt;p&gt;Some fast research revealed some libs that might help like &lt;a href="https://github.com/mapbox/pbf" rel="noopener noreferrer"&gt;pbf&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A low-level, lightweight protocol buffers implementation in JavaScript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Server side some tricks might include streaming responses; including &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events" rel="noopener noreferrer"&gt;Server Sent Events&lt;/a&gt; with something like &lt;a href="https://hono.dev/docs/helpers/streaming#streamsse" rel="noopener noreferrer"&gt;Hono&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/jswhisperer/sse-cool-starter-with-cloudflare-workers-and-hono-server-1ml"&gt;read more&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another trick would be to proxy/intercept  static assests with a reverse proxy like Caddy that is quicker at serving files than node.js&lt;/p&gt;
&lt;h1&gt;
  
  
  Images
&lt;/h1&gt;

&lt;p&gt;so there’s been a lot of improvements in image performance since my last post. There are new formats that knock traditional jpg, png, and gif out the park with savings. Mainly the widely adopted webp and the very cool avif.&lt;/p&gt;

&lt;p&gt;The other amazing available optimisation is properly or responsively sized image sources with the &amp;lt;Picture&amp;gt; element&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;picture&amp;gt;
  &amp;lt;source srcset="mdn-logo-wide.png" media="(min-width: 600px)" /&amp;gt;
  &amp;lt;img src="mdn-logo-narrow.png" alt="MDN" /&amp;gt;
&amp;lt;/picture&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and there is #ServiceWorkers#&lt;a href="https://dev.to/jswhisperer/serviceworkers-cache-everything-2487"&gt; of course &lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>test</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Sat, 31 May 2025 19:39:04 +0000</pubDate>
      <link>https://forem.com/jswhisperer/test-4617</link>
      <guid>https://forem.com/jswhisperer/test-4617</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://gist-hub.pages.dev/gist/9bd761223a76e148af576546cd1e3e93" rel="noopener noreferrer"&gt;
      gist-hub.pages.dev
    &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>ServiceWorkers Cache everything!!!</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Fri, 09 May 2025 20:13:51 +0000</pubDate>
      <link>https://forem.com/jswhisperer/serviceworkers-cache-everything-2487</link>
      <guid>https://forem.com/jswhisperer/serviceworkers-cache-everything-2487</guid>
      <description>&lt;p&gt;As a performance addict, I went all in on ServiceWorkers for better or worse.&lt;/p&gt;

&lt;p&gt;I've been digging &lt;a href="https://astro.build/" rel="noopener noreferrer"&gt;Astro&lt;/a&gt; lately, I keep eyes on Nuxt, VitePress and similar though.&lt;/p&gt;

&lt;p&gt;This article will actually target any vite based project including all the above ones.&lt;/p&gt;

&lt;p&gt;So ServiceWorkers have more API's and capabilities than any one man could cover, but our interest now is the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage" rel="noopener noreferrer"&gt;CacheStorage API&lt;/a&gt; It's similar to storage APIs you might be familar with like localStorage etc, with one caveat; It can and will intercept http requests.&lt;/p&gt;

&lt;p&gt;This, used correctly, is super cool! So say we request a large image or file "/largeImage.png" even with the best CacheHeaders there can be a delay in the response, not so with the CacheStorage API.&lt;/p&gt;

&lt;p&gt;We will intercept the request and respond with a locally browser stored version and depending on our ServiceWorker strategy possibly check for a fresher Network (external) version. This also immediately enables Offline support. Because we intercept these requests, we do not need to be online at all.&lt;/p&gt;

&lt;p&gt;Neat!&lt;/p&gt;

&lt;p&gt;So using VitePWA you might have a config like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;AstroPWA(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;srcDir:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;includeManifestIcons:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;includeAssets:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"**/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="err"&gt;pwaAssets:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;config:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;maxEntries:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;workbox:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;globPatterns:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'**/*.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;js&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;png&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;jpg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;jpeg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;webp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;avif&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;js&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;woff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;woff&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ttf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;runtimeCaching:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;

            &lt;/span&gt;&lt;span class="err"&gt;urlPattern:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/\.(?:png|jpg|jpeg|svg|html|js|avif|webp|woff&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;|woff|webp|js|txt|ttf)$/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;handler:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CacheFirst"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;options:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="err"&gt;cacheName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'main'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="err"&gt;expiration:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="err"&gt;maxAgeSeconds:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;365&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="err"&gt;maxEntries:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

        &lt;/span&gt;&lt;span class="err"&gt;cleanupOutdatedCaches:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;maximumFileSizeToCacheInBytes:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;devOptions:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;enabled:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;navigateFallbackAllowlist:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;/^\//&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is probably not optimal at all, in-fact it definitely isn't, but I'll explain it. So the top-level &lt;code&gt;includeAssets&lt;/code&gt; is AFAIK a pre-cache of resources, it might be pointing at your /public folder framework depending. It's better to actually specify resources then my wild cache it all &lt;code&gt;**/*&lt;/code&gt;. Why, because the first page load will be slow, and cache things not even related to the page the user is viewing. (As a crazy person, I use this, and no amount of therapy will change me.)&lt;/p&gt;

&lt;p&gt;Now &lt;code&gt;runtimeCaching&lt;/code&gt; this is pretty cool, it's basically grabbing resources as they are requested "at runtime"; basically anything external and not in your "/public" folder. This is probably one should lean on more then the includedAssets. This has some powerful options like strategy,  &lt;code&gt;handler: "CacheFirst"&lt;/code&gt; is probably the best IMO. Find many more &lt;a href="https://developer.chrome.com/docs/workbox/modules/workbox-strategies" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ok let's move on to a side-note more about PWA capabilities generating PWA Assets, so basically the webmanifest and appropriate icons. This makes your App/Website installable to a Desktop/Android/iOS. &lt;/p&gt;

&lt;p&gt;So you might include &lt;a href="https://vite-pwa-org.netlify.app/assets-generator/" rel="noopener noreferrer"&gt;PWA-assets-generator&lt;/a&gt; &lt;code&gt;pnpm add -D @vite-pwa/assets-generator&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can now use it like&lt;br&gt;
&lt;code&gt;pwa-assets-generator --preset minimal-2023 public/logo.svg&lt;/code&gt;&lt;br&gt;
or add as an npm script like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"generate-pwa-assets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pwa-assets-generator --preset minimal-2023 public/logo.svg"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or many framework integrations will have an option like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;AstroPWA(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="err"&gt;pwaAssets:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;config:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;nuxt would be similarly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vite-pwa/nuxt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;pwa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;pwaAssets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="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;Which will read a &lt;a href="https://github.com/vite-pwa/astro/blob/main/examples/pwa-simple-assets-generator/pwa-assets.config.ts" rel="noopener noreferrer"&gt;config file&lt;/a&gt; and automatically generate on build.&lt;/p&gt;

&lt;p&gt;Let me know any questions or thought! or critiques!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/jswhisperer/cachestorage-list-all-3h26"&gt;And how do we quickly see all our Cache Storage entries&lt;/a&gt;? &lt;/p&gt;

&lt;p&gt;an example of all responses from my blog:&lt;br&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%2Fpy9gc2opmpr26dgns9uy.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%2Fpy9gc2opmpr26dgns9uy.png" alt="Image description" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Browser Compression Options 2025</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Fri, 09 May 2025 16:02:24 +0000</pubDate>
      <link>https://forem.com/jswhisperer/browser-compression-options-2025-4gc9</link>
      <guid>https://forem.com/jswhisperer/browser-compression-options-2025-4gc9</guid>
      <description>&lt;p&gt;I was exploring the MDN docs and stumbled onto the newer &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Compression_Streams_API" rel="noopener noreferrer"&gt;CompressionStream API&lt;/a&gt; which enables a couple encodings to compress data streams; namely the popular classic GZIP, and a basic Deflate.&lt;/p&gt;

&lt;p&gt;This is a neat first step for the client, but better newer compression encodings exist; these may be forth-coming to the native api one day; Brotli and ZSTD come to mind as the top current ones.&lt;/p&gt;

&lt;p&gt;I wanted to test out all the available options I could find to see for myself. So first I searched and was able to find these libs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/bokuweb/zstd-wasm" rel="noopener noreferrer"&gt;zstd-wasm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/OneIdentity/zstd-js" rel="noopener noreferrer"&gt;zstd-js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pieroxy.net/blog/pages/lz-string/index.html" rel="noopener noreferrer"&gt;lz-string&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dominikhlbg/brotlijs" rel="noopener noreferrer"&gt;brotlijs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;High level I reckon ZSTDjs, ZSTDwasm, and then Brotli are top performers... here a screenshot of my findings&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%2Fbt11ls7xwkz38mf2zpyl.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%2Fbt11ls7xwkz38mf2zpyl.png" alt="Image description" width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and the repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jswhisperer/compression-compare" rel="noopener noreferrer"&gt;https://github.com/jswhisperer/compression-compare&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Future Work for CompressionStreams API, seems like ZSTD and Brotli are green-lit, but how long for browsers to implement is unknown&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/whatwg/compression/issues/34#issuecomment-2824968380" rel="noopener noreferrer"&gt;src&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>Invoker Commands API</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Wed, 07 May 2025 20:06:29 +0000</pubDate>
      <link>https://forem.com/jswhisperer/invoker-commands-api-1hm5</link>
      <guid>https://forem.com/jswhisperer/invoker-commands-api-1hm5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Invoker Commands API&lt;br&gt;
The Invoker Commands API provides a way to declaratively assign behaviours to buttons, allowing control of interactive elements when the button is enacted (clicked or invoked via a keypress, such as the spacebar or return key).&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API#examples" rel="noopener noreferrer"&gt;src&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What does that mean though? Basically we have a possibly growing amount of declarative HTML that can add interactivity, without javascript 🤯&lt;/p&gt;

&lt;p&gt;If you're a old and kind of clever like me this might trigger happy memories of the &lt;code&gt;&amp;lt;marquee&amp;gt;Do you believe in love after love&amp;lt;/marquee&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/marquee" rel="noopener noreferrer"&gt;element&lt;/a&gt;&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;commandfor&lt;br&gt;
Turns a  element into a button, controlling the given interactive element; takes the ID of the element to control as its value.&lt;/p&gt;

&lt;p&gt;command&lt;br&gt;
Specifies the action to be performed on an element being controlled by a control , specified via the commandfor attribute.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API#html_attributes" rel="noopener noreferrer"&gt;src&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and an example from MDN&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;commandfor=&lt;/span&gt;&lt;span class="s"&gt;"mydialog"&lt;/span&gt; &lt;span class="na"&gt;command=&lt;/span&gt;&lt;span class="s"&gt;"show-modal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Show modal dialog&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dialog&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"mydialog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;commandfor=&lt;/span&gt;&lt;span class="s"&gt;"mydialog"&lt;/span&gt; &lt;span class="na"&gt;command=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Close&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  Dialog Content
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what's interesting about the above example, at least to me is it actually runs with javascript disabled!?! So only built in the browser commands will work, but I think this is cool. Really primitive elements that add a better UX to the user can now run in environments without javascript. Also this pattern has better Accessibility out of the box.&lt;/p&gt;

&lt;p&gt;You can also write your own custom js events and handlers...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API#creating_custom_commands" rel="noopener noreferrer"&gt;Creating custom commands&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button commandfor="my-img" command="--rotate-left"&amp;gt;Rotate left&amp;lt;/button&amp;gt;
&amp;lt;button commandfor="my-img" command="--rotate-right"&amp;gt;Rotate right&amp;lt;/button&amp;gt;
&amp;lt;img id="my-img" src="photo.jpg" alt="[add appropriate alt text here]" /&amp;gt;
js
Copy to Clipboard
const myImg = document.getElementById("my-img");

myImg.addEventListener("command", (event) =&amp;gt; {
  if (event.command == "--rotate-left") {
    myImg.style.rotate = "-90deg";
  } else if (event.command == "--rotate-right") {
    myImg.style.rotate = "90deg";
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thought I'd fork this &lt;a href="https://dev.to/maxprilutskiy/creating-modal-windows-with-pure-css-no-javascript-required-1ja"&gt;article&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/play?id=9DNWJ4V%2BETIDh9fEgbQwTvbID98M6ExXg3%2B2u02w5IQ920QmKJwLldPopYbLfU%2FXHOdFVbWSmvIMp2rn" rel="noopener noreferrer"&gt;DEMO&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;commandfor=&lt;/span&gt;&lt;span class="s"&gt;"modalexample"&lt;/span&gt; &lt;span class="na"&gt;command=&lt;/span&gt;&lt;span class="s"&gt;"show-modal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Open modal dialog
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dialog&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-content"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"modalexample"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Welcome to the Modal!&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This modal window is created using only HTML and CSS!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;commandfor=&lt;/span&gt;&lt;span class="s"&gt;"modalexample"&lt;/span&gt; &lt;span class="na"&gt;command=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Close Modal&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Modal container - hidden by default */&lt;/span&gt;
&lt;span class="nc"&gt;.modal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;opacity&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;/* Center the modal content */&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* When the modal is targeted via URL hash, make it visible */&lt;/span&gt;
&lt;span class="nc"&gt;.modal&lt;/span&gt;&lt;span class="nd"&gt;:target&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Modal content box */&lt;/span&gt;
&lt;span class="nc"&gt;.modal-content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow-y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="m"&gt;30px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Backdrop close link - covers the entire screen */&lt;/span&gt;
&lt;span class="nc"&gt;.modal-backdrop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* Place behind modal content */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;dialog&lt;/span&gt;&lt;span class="nd"&gt;:modal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;1s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;overlay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;/* Keyframes for dialog and popover elements */&lt;/span&gt;
&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;fadeIn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;from&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&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;@keyframes&lt;/span&gt; &lt;span class="n"&gt;fadeOut&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;from&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Keyframes for the backdrop pseudo-element */&lt;/span&gt;
&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;backdropFadeIn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;from&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;50%&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;@keyframes&lt;/span&gt; &lt;span class="n"&gt;backdropFadeOut&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;from&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;to&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;dialog&lt;/span&gt;&lt;span class="nd"&gt;::backdrop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;1s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;dialog&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;/* Final state of the exit animation */&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;opacity&lt;/span&gt; &lt;span class="m"&gt;0.7s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.7s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;overlay&lt;/span&gt; &lt;span class="m"&gt;0.7s&lt;/span&gt; &lt;span class="n"&gt;allow-discrete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt; &lt;span class="m"&gt;0.7s&lt;/span&gt; &lt;span class="n"&gt;allow-discrete&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c"&gt;/* Equivalent to
    transition: all 0.7s allow-discrete; */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Needs to be included after the previous [popover]:popover-open
     rule to take effect, as the specificity is the same */&lt;/span&gt;
&lt;span class="k"&gt;@starting-style&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;popover&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:popover-open&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scaleX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Transition for the popover's backdrop */&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;popover&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;::backdrop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt; &lt;span class="m"&gt;0.7s&lt;/span&gt; &lt;span class="n"&gt;allow-discrete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;overlay&lt;/span&gt; &lt;span class="m"&gt;0.7s&lt;/span&gt; &lt;span class="n"&gt;allow-discrete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;background-color&lt;/span&gt; &lt;span class="m"&gt;0.7s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c"&gt;/* Equivalent to
    transition: all 0.7s allow-discrete; */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;popover&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:popover-open::backdrop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;25%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Nesting selectors (&amp;amp;) cannot represent pseudo-elements, so this 
     starting-style rule cannot be nested. */&lt;/span&gt;

&lt;span class="k"&gt;@starting-style&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;popover&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:popover-open::backdrop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#modalexample&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fadeOut&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt; &lt;span class="n"&gt;forwards&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="err"&gt;&amp;amp;::backdrop&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;backdropFadeOut&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt; &lt;span class="n"&gt;forwards&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;amp;[&lt;/span&gt;&lt;span class="nt"&gt;open&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fadeIn&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt; &lt;span class="n"&gt;forwards&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="err"&gt;&amp;amp;::backdrop&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;backdropFadeIn&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt; &lt;span class="n"&gt;forwards&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/jswhisperer/re-modals" rel="noopener noreferrer"&gt;https://github.com/jswhisperer/re-modals&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm not 100% overall on how I feel about that though, maybe it helps lower level with creating interactive elements... Maybe it feels like too little too late, time will tell.&lt;/p&gt;

</description>
      <category>invokercommands</category>
      <category>html</category>
    </item>
    <item>
      <title>QuickTip: CacheStorage list all</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Wed, 07 May 2025 01:43:59 +0000</pubDate>
      <link>https://forem.com/jswhisperer/cachestorage-list-all-3h26</link>
      <guid>https://forem.com/jswhisperer/cachestorage-list-all-3h26</guid>
      <description>&lt;p&gt;I really like one liners, especially for shell or console commands.&lt;/p&gt;

&lt;p&gt;Anyway I couldn't find how to view all entries in CacheStorage [so I made one]&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>cache</category>
    </item>
    <item>
      <title>SSE cool starter with CloudFlare Workers and Hono server</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Wed, 07 May 2025 01:42:01 +0000</pubDate>
      <link>https://forem.com/jswhisperer/sse-cool-starter-with-cloudflare-workers-and-hono-server-1ml</link>
      <guid>https://forem.com/jswhisperer/sse-cool-starter-with-cloudflare-workers-and-hono-server-1ml</guid>
      <description>&lt;p&gt;SSE or Server Side Events is a cool newer web tech to efficently send data in a push / subscribe pattern.&lt;/p&gt;

&lt;p&gt;Here's a &lt;strong&gt;cool starter with CloudFlare Workers and Hono server&lt;/strong&gt; I made for a quick start in the most performant way possible 😊&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jswhisperer/SSE-full-honojs-example" rel="noopener noreferrer"&gt;https://github.com/jswhisperer/SSE-full-honojs-example&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sse</category>
      <category>hono</category>
      <category>cloudflare</category>
    </item>
    <item>
      <title>MacOS Apps I use</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Mon, 28 Apr 2025 21:24:38 +0000</pubDate>
      <link>https://forem.com/jswhisperer/macos-apps-i-use-1b6b</link>
      <guid>https://forem.com/jswhisperer/macos-apps-i-use-1b6b</guid>
      <description>&lt;p&gt;Draft-y but will keep adding&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/AppPolice/AppPolice" rel="noopener noreferrer"&gt;https://github.com/AppPolice/AppPolice&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.caffeine-app.net/" rel="noopener noreferrer"&gt;https://www.caffeine-app.net/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://brave.com/" rel="noopener noreferrer"&gt;https://brave.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://iina.io/" rel="noopener noreferrer"&gt;https://iina.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.raycast.com/" rel="noopener noreferrer"&gt;https://www.raycast.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/waydabber/BetterDisplay" rel="noopener noreferrer"&gt;https://github.com/waydabber/BetterDisplay&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;https://brew.sh/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;https://code.visualstudio.com/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://vscodium.com/" rel="noopener noreferrer"&gt;https://vscodium.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.getmailspring.com/" rel="noopener noreferrer"&gt;https://www.getmailspring.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.apple.com/us/app/say-no-to-notch/id1639306886?mt=12" rel="noopener noreferrer"&gt;https://apps.apple.com/us/app/say-no-to-notch/id1639306886?mt=12&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://iterm2.com/" rel="noopener noreferrer"&gt;https://iterm2.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>macos</category>
      <category>opensource</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Webmentions Revisted</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Thu, 13 Mar 2025 01:54:45 +0000</pubDate>
      <link>https://forem.com/jswhisperer/webmentions-revisited-5yrs-later-cdn</link>
      <guid>https://forem.com/jswhisperer/webmentions-revisited-5yrs-later-cdn</guid>
      <description>&lt;p&gt;When writing your blog, many, like myself,f would like comments from our readers. Comments, likes, reposts and similar let the author know what readers think and cultivate great new conversations or provide invaluable feedback and even criticism on which we can learn from and grow.&lt;/p&gt;

&lt;p&gt;I first wrote a very light article on the implementation of Webmentions 5 years ago &lt;a href="https://dev.to/jswhisperer/you-dont-mention-webmentions-20be"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'd say, to my knowledge, there haven't been huge strides or adaptation of them in the mainstream web. There does seem to be traction in the FED web.&lt;/p&gt;

&lt;p&gt;What is the FED web? from &lt;a href="https://fed.brid.gy/docs#web-get-started" rel="noopener noreferrer"&gt;brid.gy fed&lt;/a&gt; and here &lt;a href="https://en.wikipedia.org/wiki/Fediverse" rel="noopener noreferrer"&gt;fediverse&lt;/a&gt; and &lt;a href="https://www.theverge.com/24063290/fediverse-explained-activitypub-social-media-open-protocol" rel="noopener noreferrer"&gt;here  on the verge&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;Bridgy Fed is a decentralized social network bridge. It connects the Fediverse, the web, and [bluesky]("https://bsky.app/profile/jswhisperer.bsky.social") . If you're on one of these networks, you can use Bridgy Fed to follow people on other networks, see their posts, and reply, like and repost them. Likewise, they'll be able to see you and your posts, too.

Click here to get started, or read on for more information and setup details.&lt;/blockquote&gt;

&lt;p&gt;So last time I wrote about integrating with &lt;a href="https://github.com/gridsome/gridsome" rel="noopener noreferrer"&gt;Gridsome&lt;/a&gt; "The Jamstack framework for Vue.js" and a GrapQL solution; I've since moved my blog to &lt;a href="https://astro.build/" rel="noopener noreferrer"&gt;Astro&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Astro is pretty cool, but this article isn't about it right now. It is another important Static Site generation tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webmentionsUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://webmention.io/api/mentions.jf2?domain=example.uk&amp;amp;token=token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;webmentionsUrl&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;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webmentions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&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;mention&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;URL&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="nx"&gt;mention&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wm-target&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might then render the results in your framework of choice as below. I've added rich data or &lt;a href="https://validator.schema.org/#url=https%3A%2F%2Fjswhisperer.uk%2Fpost%2Fcaddy-2%2F" rel="noopener noreferrer"&gt;microformats2&lt;/a&gt; &lt;a href="https://en.wikipedia.org/wiki/Microformat" rel="noopener noreferrer"&gt;Microformat&lt;/a&gt; Microdata&lt;a href="https://html.spec.whatwg.org/multipage/microdata.html#microdata" rel="noopener noreferrer"&gt;&lt;/a&gt; covered in my &lt;a href="https://dev.to/jswhisperer/seo-starter-kit-1n2c"&gt;SEO starter article&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;itemscope=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;itemtype=&lt;/span&gt;&lt;span class="s"&gt;"http://schema.org/UserComments"&lt;/span&gt; &lt;span class="na"&gt;data-astro-cid-qesbhxo5=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;small&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;time&lt;/span&gt; &lt;span class="na"&gt;itemprop=&lt;/span&gt;&lt;span class="s"&gt;"commentTime"&lt;/span&gt; &lt;span class="na"&gt;datetime=&lt;/span&gt;&lt;span class="s"&gt;"2025-01-24T10:15:16Z"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;January 24, 2025&lt;span class="nt"&gt;&amp;lt;/time&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;itemprop=&lt;/span&gt;&lt;span class="s"&gt;"creator"&lt;/span&gt; &lt;span class="na"&gt;itemscope=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;itemtype=&lt;/span&gt;&lt;span class="s"&gt;"https://schema.org/Person"&lt;/span&gt;
            &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"u-author h-card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;itemprop=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Gregory&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;itemprop=&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://jswhisperer.uk/author/greg"&lt;/span&gt;
                &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"author url"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"greg.CZmlD_1D.jpeg"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/webp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"greg.CZmlD_1D.jpeg"&lt;/span&gt;
                        &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Gmoney"&lt;/span&gt; &lt;span class="na"&gt;data-astro-cid-qesbhxo5=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt; &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
                        &lt;span class="na"&gt;decoding=&lt;/span&gt;&lt;span class="s"&gt;"async"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"information"&lt;/span&gt; &lt;span class="na"&gt;data-astro-cid-qesbhxo5=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
                    replied on: &lt;span class="nt"&gt;&amp;lt;time&lt;/span&gt; &lt;span class="na"&gt;datetime=&lt;/span&gt;&lt;span class="s"&gt;"2025-01-24T10:15:16Z"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;January 24, 2025&lt;span class="nt"&gt;&amp;lt;/time&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;blockquote&lt;/span&gt; &lt;span class="na"&gt;itemprop=&lt;/span&gt;&lt;span class="s"&gt;"commentText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Wicked cool&lt;span class="nt"&gt;&amp;lt;/blockquote&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step for me is having my static blog trigger a build for new Webmentions. I'm using Cloudflare Workers, but it's the same process for Github Pages / Workers, Vercel etc. &lt;/p&gt;

&lt;p&gt;Take your webmention.io webhook&lt;br&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%2Fve19f86hcdrbtdv5n5zo.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%2Fve19f86hcdrbtdv5n5zo.png" alt="Image description" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;plug it into your static host&lt;br&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%2Fbyx4vvc3kgmbg40q36xa.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%2Fbyx4vvc3kgmbg40q36xa.png" alt="Image description" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and Enjoy&lt;/p&gt;

</description>
      <category>webmentions</category>
      <category>cloudflare</category>
      <category>astro</category>
    </item>
    <item>
      <title>code-server by coder</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Tue, 05 Nov 2024 20:30:17 +0000</pubDate>
      <link>https://forem.com/jswhisperer/code-server-by-coder-1268</link>
      <guid>https://forem.com/jswhisperer/code-server-by-coder-1268</guid>
      <description>&lt;h1&gt;
  
  
  code-server by coder
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;This project provides a version of VS Code that runs a server on a remote machine and allows access through a modern web browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Find the project repo &lt;a href="https://github.com/coder/code-server" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What is it in my humble simple language? It’s been called a “&lt;a href="https://docs.gitlab.com/ee/ci/runners/" rel="noopener noreferrer"&gt;runner&lt;/a&gt;” in GitLab; but essentially it running the code and terminal command on a remote machine. That can be in the cloud, on &lt;a href="https://github.com/coder/deploy-code-server/blob/main/Dockerfile" rel="noopener noreferrer"&gt;docker&lt;/a&gt; or &lt;a href="https://github.com/coder/code-server/blob/main/install.sh" rel="noopener noreferrer"&gt;natively install on your own machine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Many people will not need this functionality, the costs of cloud hosting and processing might not be appealing. My use-case is I like to code on really underpowered machines. One of those is my beloved 2012 macbook air 11” with 2 cores. It light as a feather sits on my lap nice and looks like some sort of knife.&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%2Figkeok4vjbecp4jszcme.jpg" 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%2Figkeok4vjbecp4jszcme.jpg" alt="The Apple MacBook Air 11-inch (Mid-2012) gets a third-generation Intel processor and USB 3.0. But ultrabooks have caught up, and surpassed the MacBook on some features (like screens) and price points. - Apple MacBook Air 11-inch (Mid 2012)" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*Sidebar:&lt;/em&gt; this has to be the thinest apple product to date, I don’t care what they say about the iPad! 05.3cm vs 1.7cm-0.3cm with keyboard and monitor 🕵️‍♀️  ….and my other goto coding machine is a Raspberry Pi.&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%2F3gslyx0ppvfj19njhbq1.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%2F3gslyx0ppvfj19njhbq1.png" width="732" height="355"&gt;&lt;/a&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%2Fmjjopj7ilg2z0t76vlmb.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%2Fmjjopj7ilg2z0t76vlmb.png" width="800" height="177"&gt;&lt;/a&gt;## Running code-server on your host machine&lt;/p&gt;

&lt;p&gt;So however you get it installed start the server, I'll be quoting macos and homebrew but see all the example setups on the same page. With &lt;a href="https://coder.com/docs/code-server/install#macos" rel="noopener noreferrer"&gt;homebrew&lt;/a&gt; it would be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install code-server
brew services start code-server
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and opening the config.yaml would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bind-addr: localhost:8080
auth: password
password: password
cert: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you could navigate to &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; and see a vscode instance in your browser! you will be prompted for the password.&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%2F8tvds5brbaeagvggjo9b.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%2F8tvds5brbaeagvggjo9b.png" alt="Image description" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's missing so far, is the SSL cert and https:// hosting, this is important / cool because firstly you shouldn't have a tunnel to your local machine unencrypted and cool because they provide a PWA &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%2Flbm4cyd008ryln4ore15.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%2Flbm4cyd008ryln4ore15.png" alt="Image description" width="360" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even better and what I opted for is a &lt;a href="https://caddyserver.com/docs/quick-starts/reverse-proxy" rel="noopener noreferrer"&gt;reverse proxy with Caddy&lt;/a&gt; if you are on the homebrew path you can \&lt;br&gt;
&lt;code&gt;brew install caddy&lt;/code&gt; then you will find the config here on macos &lt;code&gt;/opt/homebrew/etc/Caddyfile&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For a quick start you can edit your hosts file &lt;code&gt;sudo nano /etc/hosts/&lt;/code&gt; and append a url you would like such as \&lt;br&gt;
&lt;code&gt;127.0.0.1 coder.localhost&lt;/code&gt;  the .&lt;a href="http://localhost" rel="noopener noreferrer"&gt;localhost&lt;/a&gt; holds special meaning to caddy and certs. &lt;/p&gt;

&lt;p&gt;Now to the reverse proxy we can create one in the Caddyfile like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;coder.localhost, mbp.local {
    reverse_proxy 0.0.0.0:8080
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've added my mac host name also to be served on my LAN with https. Repeat this proxy and /hosts setup on your remote machine (minus mbp.local) you can now access and run you host instance on your remote machines.&lt;/p&gt;

&lt;p&gt;You can even code on you mobile phone or ipad etc through "&lt;a href="https://mbp.local" rel="noopener noreferrer"&gt;https://mbp.local&lt;/a&gt;" or your hostname.&lt;/p&gt;

&lt;p&gt;You can take this one step further and access from anywhere in the world with something like &lt;a href="https://www.duckdns.org/" rel="noopener noreferrer"&gt;ducksdns&lt;/a&gt; if you go down this route, you should implement some security, Caddy has all you need JWT protection IP allowlisting and more.&lt;/p&gt;

</description>
      <category>vscode</category>
    </item>
    <item>
      <title>Hacking WKWebview and WebContainers // or WebContainers are we there yet?</title>
      <dc:creator>Greg, The JavaScript Whisperer</dc:creator>
      <pubDate>Fri, 01 Nov 2024 18:21:17 +0000</pubDate>
      <link>https://forem.com/jswhisperer/hacking-wkwebview-and-webcontainers-1727</link>
      <guid>https://forem.com/jswhisperer/hacking-wkwebview-and-webcontainers-1727</guid>
      <description>&lt;p&gt;I started writing about the shiny new wasm-y not quite open source tech called &lt;a href="https://webcontainers.io/" rel="noopener noreferrer"&gt;webcontainers&lt;/a&gt; by stackblitz, but having hacked the crap out them I reckon right now they aren't quite mature enough for production use.&lt;/p&gt;

&lt;p&gt;Here's some of the rough edges you might hit... &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are on a private server, your project, firewall or company might block this hard depencie *.webcontainers.io and &lt;a href="https://nr.staticblitz.com" rel="noopener noreferrer"&gt;https://nr.staticblitz.com&lt;/a&gt; to name a couple I see.&lt;/li&gt;
&lt;li&gt;For all the hype they do not seem able to actually listen to any request outside the webpage like a POST (more in a sec)&lt;/li&gt;
&lt;li&gt;They are behind AWS Cloudfront (fine) but you can't edit the headers or CORs policies at all&lt;/li&gt;
&lt;li&gt;they work around iframes which can be a basket of worms with permissions and policies like CSP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and lastly I think it's worth having a look at the open issues of any library or project; that alone isn't the end all and be all of decision making. It is expected a new library get a surge of issues that need to be triaged.&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%2F7rsqoij80cqgq7bhaejt.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%2F7rsqoij80cqgq7bhaejt.png" alt="Image description" width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last indicator this isn't ready for prime time is if they are ignoring or don't have capacity to review PRs they might not be fully invested. Of course it's my duty to open PR's and contribute where I can. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/stackblitz/webcontainer-docs/pull/89" rel="noopener noreferrer"&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%2Fkegx1yhaomc8k0p04zgd.png" alt="Image description" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had a whole doc around embedded webview in a Rust lang context and my coo workaround. To summarise it was how WKWebview does not at all support &lt;code&gt;navigator.credentials&lt;/code&gt; web api or the shiny new "Passkeys" not so quick read if you got a weekend to play here&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>rust</category>
      <category>macos</category>
      <category>webassembly</category>
    </item>
  </channel>
</rss>
