<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Zach Leatherman</title>
  <subtitle>A web development blog written by @zachleat.</subtitle>
  <link href="https://www.zachleat.com/web/feed/atom.xml" rel="self" />
  <link href="https://www.zachleat.com/" />
  <updated>2026-04-16T05:00:00Z</updated>
  <id>https://www.zachleat.com/</id>
  <author>
    <name>Zach Leatherman</name>
  </author>
  <entry>
    <title>State of the Browser (2026) It’s 10PM: Do You Know Where Your JavaScript Is?</title>
    <link href="https://www.zachleat.com/web/its-10pm/" />
    <updated>2026-04-16T05:00:00Z</updated>
    <id>https://www.zachleat.com/web/its-10pm/</id>
    <content type="html">&lt;p&gt;This talk was given at &lt;a href=&quot;https://2026.stateofthebrowser.com/&quot;&gt;State of the Browser (2026)&lt;/a&gt;. Check out &lt;a href=&quot;https://2026.stateofthebrowser.com/speaker/zach-leatherman/&quot;&gt;the event talk page&lt;/a&gt; (which includes a talk transcript, too).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We’ll talk about best practices to either reduce (or increase!) the JavaScript footprint on your web site to a sweet and very practical spot for best results. It’s far more common to have too much JavaScript on your web site, but can you go too far? Is zero JavaScript a worthwhile goal? Let’s talk about it!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;video&quot;&gt;Video&lt;/h2&gt;
&lt;div&gt;&lt;youtube-lite-player&gt;
&lt;script type=&quot;module&quot; src=&quot;https://www.zachleat.com/static/browser-window.js&quot;&gt;&lt;/script&gt;
&lt;browser-window mode=&quot;dark&quot; flush icon url=&quot;https://youtube.com/watch?v=qIMFhkDTYRM&quot; shadow&gt;
	&lt;is-land on:visible class=&quot;fluid-width-video-wrapper&quot;&gt;
		&lt;lite-youtube videoid=&quot;qIMFhkDTYRM&quot; js-api playlabel=&quot;Play: State of the Browser (2026) It’s 10PM: Do You Know Where Your JavaScript Is?&quot; style=&quot;background-image: var(--yt-poster-img-url); --yt-poster-img-url-lazy: url(&#39;https://v1.opengraph.11ty.dev/https%3A%2F%2Fyoutube.com%2Fwatch%3Fv%3DqIMFhkDTYRM/auto/jpeg/&#39;)&quot;&gt;&lt;/lite-youtube&gt;
		&lt;template data-island=&quot;once&quot;&gt;
			&lt;style&gt;
			lite-youtube {
				max-width: 100% !important;
				background-size: cover;
			}
			/* Plugin bug: clicking the red youtube play icon in the center would navigate to youtube.com */
			lite-youtube:defined .lty-playbtn {
				pointer-events: none;
			}
			&lt;/style&gt;
			&lt;link rel=&quot;stylesheet&quot; href=&quot;https://www.zachleat.com/static/lite-yt-embed.css&quot;&gt;
			&lt;script type=&quot;module&quot; src=&quot;https://www.zachleat.com/static/lite-yt-embed.js&quot;&gt;&lt;/script&gt;
		&lt;/template&gt;
	&lt;/is-land&gt;
&lt;/browser-window&gt;
&lt;youtube-link label=&quot;State of the Browser (2026) It’s 10PM: Do You Know Where Your JavaScript Is?&quot; href=&quot;https://youtube.com/watch?v=qIMFhkDTYRM&quot;&gt;
&lt;a href=&quot;https://youtube.com/watch?v=qIMFhkDTYRM&quot; class=&quot;lite-youtube-link text-ellipsis-multi&quot;&gt;Watch on YouTube: &lt;em&gt;State of the Browser (2026) It’s 10PM: Do You Know Where Your JavaScript Is?&lt;/em&gt;&lt;/a&gt;&lt;/youtube-link&gt;&lt;/youtube-lite-player&gt;&lt;/div&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/History/19921103-hypertext/hypertext/WWW/MarkUp/Tags.html&quot;&gt;HTML Tags 1992&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cl.cam.ac.uk/coffee/coffee.html&quot;&gt;The Trojan Room Coffee Machine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/CSS1/&quot;&gt;Cascading Style Sheets, level 1 - 17 Dec 1996&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20141108064903/http://hesketh.com/publications/inclusive_web_design_for_the_future/&quot;&gt;Inclusive Web Design For the Future with Progressive Enhancement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/speed/libraries&quot;&gt;Google Hosted Libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://andydavies.me/blog/2018/09/06/safari-caching-and-3rd-party-resources/&quot;&gt;Andy Davies - Safari, Caching and Third-Party Resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://addyosmani.com/blog/double-keyed-caching/&quot;&gt;Double-keyed Caching: How Browser Cache Partitioning Changed the Web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/http-cache-partitioning&quot;&gt;Gaining security and privacy by partitioning the cache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fossa.com/blog/polyfill-supply-chain-attack-details-fixes/&quot;&gt;Polyfill Supply Chain Attack: Details and Fixes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity&quot;&gt;Subresource Integrity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.aaronsw.com/weblog/000404&quot;&gt;Bake, Don’t Fry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/People/howcome/p/cascade.html&quot;&gt;Cascading HTML style sheets -- a proposal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/2001/WD-css3-mediaqueries-20010404/Overview.html&quot;&gt;Media queries W3C Working Draft, 4 Apr 2001&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alistapart.com/article/responsive-web-design/&quot;&gt;Responsive Web Design by Ethan Marcotte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scottjehl.com/posts/responsive-video/&quot;&gt;We&#39;re Bringing Responsive Video Back!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://solar.lowtechmagazine.com/&quot;&gt;Low←Tech Magazine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://styled-components.com/&quot;&gt;Styled Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.zachleat.com/web/ssr-overloaded/&quot;&gt;The many definitions of Server-Side Rendering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://linaria.dev/&quot;&gt;Linaria - Zero-Runtime CSS in JS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vanilla-extract.style/&quot;&gt;Zero-runtime Stylesheets in TypeScript.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/reactwg/react-18/discussions/110&quot;&gt;Library Upgrade Guide: &amp;lt;style&amp;gt; (most CSS-in-JS libs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webawesome.com/docs/components/comparison/&quot;&gt;Web Awesome Comparison component&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>AMA about Build Awesome, an Open Town Hall at the 11ty Meetup</title>
    <link href="https://www.zachleat.com/web/ama-build-awesome-town-hall/" />
    <updated>2026-03-12T05:00:00Z</updated>
    <id>https://www.zachleat.com/web/ama-build-awesome-town-hall/</id>
    <content type="html">&lt;p&gt;Here I field any and all community questions about the Eleventy rebrand to Build Awesome.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=lA-wD89m6jM&quot;&gt;Watch on YouTube&lt;/a&gt; or below:&lt;/p&gt;
&lt;div&gt;&lt;youtube-lite-player&gt;
&lt;script type=&quot;module&quot; src=&quot;https://www.zachleat.com/static/browser-window.js&quot;&gt;&lt;/script&gt;
&lt;browser-window mode=&quot;dark&quot; flush icon url=&quot;https://youtube.com/watch?v=lA-wD89m6jM&quot; shadow&gt;
	&lt;is-land on:visible class=&quot;fluid-width-video-wrapper&quot;&gt;
		&lt;lite-youtube videoid=&quot;lA-wD89m6jM&quot; js-api playlabel=&quot;Play: AMA about Build Awesome, an Open Town Hall at the 11ty Meetup&quot; style=&quot;background-image: var(--yt-poster-img-url); --yt-poster-img-url-lazy: url(&#39;https://v1.opengraph.11ty.dev/https%3A%2F%2Fyoutube.com%2Fwatch%3Fv%3DlA-wD89m6jM/auto/jpeg/&#39;)&quot;&gt;&lt;/lite-youtube&gt;
		&lt;template data-island=&quot;once&quot;&gt;
			&lt;style&gt;
			lite-youtube {
				max-width: 100% !important;
				background-size: cover;
			}
			/* Plugin bug: clicking the red youtube play icon in the center would navigate to youtube.com */
			lite-youtube:defined .lty-playbtn {
				pointer-events: none;
			}
			&lt;/style&gt;
			&lt;link rel=&quot;stylesheet&quot; href=&quot;https://www.zachleat.com/static/lite-yt-embed.css&quot;&gt;
			&lt;script type=&quot;module&quot; src=&quot;https://www.zachleat.com/static/lite-yt-embed.js&quot;&gt;&lt;/script&gt;
		&lt;/template&gt;
	&lt;/is-land&gt;
&lt;/browser-window&gt;
&lt;youtube-link label=&quot;AMA about Build Awesome, an Open Town Hall at the 11ty Meetup&quot; href=&quot;https://youtube.com/watch?v=lA-wD89m6jM&quot;&gt;
&lt;a href=&quot;https://youtube.com/watch?v=lA-wD89m6jM&quot; class=&quot;lite-youtube-link text-ellipsis-multi&quot;&gt;Watch on YouTube: &lt;em&gt;AMA about Build Awesome, an Open Town Hall at the 11ty Meetup&lt;/em&gt;&lt;/a&gt;&lt;/youtube-link&gt;&lt;/youtube-lite-player&gt;&lt;/div&gt;
&lt;h2 id=&quot;related&quot;&gt;Related:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/blog/build-awesome/&quot;&gt;Eleventy is now Build Awesome (11ty Blog)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://11tymeetup.dev/events/ep-30-rapid-prototyping-helpers/&quot;&gt;Event page on 11tymeetup.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Eleventy is now Build Awesome</title>
    <link href="https://www.zachleat.com/web/build-awesome/" />
    <updated>2026-03-06T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/build-awesome/</id>
    <content type="html">&lt;p&gt;The Eleventy project is taking up the Awesome banner. To support the project, please sign up to &lt;a href=&quot;https://www.kickstarter.com/projects/fontawesome/build-awesome-pro&quot;&gt;get notified when our Kickstarter campaign launches&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Speaking at: State of the Browser (2026)</title>
    <link href="https://www.zachleat.com/web/state-of-the-browser/" />
    <updated>2026-02-28T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/state-of-the-browser/</id>
    <content type="html">&lt;p&gt;This is an event post. Also check out &lt;a href=&quot;https://2026.stateofthebrowser.com/speaker/zach-leatherman/&quot;&gt;my individual talk page&lt;/a&gt;.&lt;/p&gt;
&lt;script type=&quot;module&quot; src=&quot;https://www.zachleat.com/static/browser-window.js&quot;&gt;&lt;/script&gt;
&lt;div&gt;&lt;browser-window mode=&quot;light&quot; icon url=&quot;https://2026.stateofthebrowser.com/speaker/zach-leatherman/&quot; shadow flush style=&quot;--bw-background: oklch(76.202% 0.1562 84.861)&quot;&gt;&lt;a href=&quot;https://2026.stateofthebrowser.com/speaker/zach-leatherman/&quot; class=&quot;favicon-optout&quot;&gt;&lt;img alt=&quot;Screenshot image for https://2026.stateofthebrowser.com/speaker/zach-leatherman/&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; class=&quot;&quot; src=&quot;https://screenshot.11ty.app/https%3A%2F%2F2026.stateofthebrowser.com%2Fspeaker%2Fzach-leatherman%2F/opengraph/&quot; width=&quot;1200&quot; height=&quot;630&quot;&gt;&lt;/a&gt;&lt;/browser-window&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: As the talk has already been given, you can find &lt;a href=&quot;https://www.zachleat.com/web/its-10pm/&quot;&gt;the talk content published on my web site&lt;/a&gt;.&lt;/p&gt;
&lt;script type=&quot;module&quot; src=&quot;https://www.zachleat.com/static/browser-window.js&quot;&gt;&lt;/script&gt;
&lt;div&gt;&lt;browser-window mode=&quot;light&quot; icon url=&quot;https://www.zachleat.com/web/its-10pm/&quot; shadow flush style=&quot;--bw-background: oklch(82.691% 0.09444 136.65)&quot;&gt;&lt;a href=&quot;https://www.zachleat.com/web/its-10pm/&quot; class=&quot;favicon-optout&quot;&gt;&lt;img alt=&quot;Screenshot image for https://www.zachleat.com/web/its-10pm/&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; class=&quot;&quot; src=&quot;https://screenshot.11ty.app/https%3A%2F%2Fwww.zachleat.com%2Fweb%2Fits-10pm%2F/opengraph/&quot; width=&quot;1200&quot; height=&quot;630&quot;&gt;&lt;/a&gt;&lt;/browser-window&gt;&lt;/div&gt;</content>
  </entry>
  <entry>
    <title>An Official* Logo for HTML</title>
    <link href="https://www.zachleat.com/web/html-logo/" />
    <updated>2026-02-19T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/html-logo/</id>
    <content type="html">&lt;p&gt;*&lt;em&gt;Not official.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I was working on my slide deck for the &lt;a href=&quot;https://2026.stateofthebrowser.com/&quot;&gt;upcoming State of the Browser conference&lt;/a&gt; and ran into what I would classify as a recurring issue: HTML needs a logo. There isn’t a broadly accepted official logo for (version-independent) HTML. There &lt;em&gt;is&lt;/em&gt; a logo for HTML 5, but that versioned marketing term has long fallen out of regular use (and was introduced 18 years ago).&lt;/p&gt;
&lt;p&gt;This is a community solved problem in both the CSS and JavaScript spaces!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSS: &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fab-fa-css&quot; xlink:href=&quot;#fab-fa-css&quot;&gt;&lt;/use&gt;&lt;/svg&gt;, &lt;a href=&quot;https://github.com/CSS-Next/css-next/issues/105&quot;&gt;relevant discussion on &lt;code&gt;CSS-Next&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;JS: &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fab-fa-js&quot; xlink:href=&quot;#fab-fa-js&quot;&gt;&lt;/use&gt;&lt;/svg&gt;, &lt;a href=&quot;https://github.com/voodootikigod/logo.js&quot;&gt;relevant discussion on &lt;code&gt;voodootikigod/logo.js&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;HTML 5: &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fab-fa-html5&quot; xlink:href=&quot;#fab-fa-html5&quot;&gt;&lt;/use&gt;&lt;/svg&gt;, &lt;a href=&quot;https://www.w3.org/html/logo/&quot;&gt;more info on w3.org&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wish the classic orange badge hadn’t included a version number, but alas.&lt;/p&gt;
&lt;p&gt;Anyway, I very quickly &lt;a href=&quot;https://fediverse.zachleat.com/@zachleat/116093900452223373&quot;&gt;threw my hat into the ring&lt;/a&gt; and immediately recognized a &lt;a href=&quot;https://indieweb.social/@sstephenson/116098428280403793&quot;&gt;much better option from Sam Stephenson&lt;/a&gt; &lt;a href=&quot;https://sls.name/&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-user&quot; xlink:href=&quot;#fas-fa-user&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;code&gt;sls.name&lt;/code&gt;&lt;/a&gt; that I’ll be considering canon moving forward (and hopefully this blog post puts some weight behind it for others too).&lt;/p&gt;
&lt;p&gt;Here’s what it looks like rendered in your web browser:&lt;/p&gt;
&lt;div class=&quot;flex flex-center&quot;&gt;&lt;a href=&quot;https://indieweb.social/@sstephenson/116098428280403793&quot; style=&quot;all:initial;cursor:pointer;font-size:2rem;width:4em;height:4em;color:blue;text-decoration:underline;display:flex;align-items:center;justify-content:center;background:#ccc;border:.5em outset #aaa;font-weight:900;&quot;&gt;HTML&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I love the nod to the classic unvisited link color and the heavy outset border that doubles as angle brackets with the right head tilt.&lt;/p&gt;
&lt;p&gt;If you’re interested in the source code, the HTML-only (copy-paste friendly) source code is included below &lt;a href=&quot;https://codepen.io/zachleat/pen/azZggqZ&quot;&gt;&lt;em&gt;(and also on Codepen)&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://indieweb.social/@sstephenson/116098428280403793&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;initial&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;4em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;4em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;underline&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;#ccc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;.5em outset #aaa&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;900&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;HTML&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>How Eleventy Survived: Funding, Growth, and Open Source Reality</title>
    <link href="https://www.zachleat.com/web/podcast-awesome-eleventy-open-source/" />
    <updated>2026-02-03T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/podcast-awesome-eleventy-open-source/</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Eleventy started as a side project. Now it’s a critical infrastructure for thousands of websites.&lt;/p&gt;
&lt;p&gt;TL;DR: Open source isn’t broken. But the way we fund it often is. Let’s talk about what actually works.&lt;/p&gt;
&lt;p&gt;In this episode, we sit down with Zach Leatherman, creator of Eleventy (11ty), to talk honestly about what happens after open source succeeds. From nap-time coding and nights-and-weekends maintenance to venture capital pressure, burnout risk, and the reality of funding long-lived developer tools, this conversation digs into the cultural and financial tradeoffs behind modern open source.&lt;/p&gt;
&lt;p&gt;We cover sustainability, community expectations, funding models that don’t rely on hockey-stick growth, and why “free forever” only works if the people behind the project can stay whole humans.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Listen in: &lt;a href=&quot;https://www.podcastawesome.com/2092855/episodes/18615318-how-eleventy-survived-funding-growth-and-open-source-reality&quot;&gt;How Eleventy Survived: Funding, Growth, and Open Source Reality&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Also on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=GrLHE5djtPA&quot;&gt;YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://overcast.fm/+AA-SZeh8B8A&quot;&gt;Overcast.fm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/us/podcast/how-eleventy-survived-funding-growth-and-open-source/id1660959088?i=1000747878278&quot;&gt;Apple Podcasts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Eleventy, 2025 in Review</title>
    <link href="https://www.zachleat.com/web/eleventy-2025-review/" />
    <updated>2026-01-12T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/eleventy-2025-review/</id>
    <content type="html">&lt;p&gt;A look back at the &lt;a href=&quot;https://www.11ty.dev/blog/review-2025/&quot;&gt;2025 highlights for the 11ty org and the Eleventy project&lt;/a&gt;!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It was another huge year for 11ty. We shipped 177 releases (73% more than 2024) across the full 11ty/* suite. We closed 804 issues (15% more than 2024). We reduced core’s dependency count by 28% and weight by 22%. More folks are building with Eleventy than ever: our year-over-year npm downloads (for only core) are up by 51%!&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <title>No more tokens! Locking down npm Publish Workflows</title>
    <link href="https://www.zachleat.com/web/npm-security/" />
    <updated>2025-12-04T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/npm-security/</id>
    <content type="html">&lt;p&gt;With the recent spate of high profile npm security incidents involving compromised deployment workflows, I decided that it would be prudent to do a full inventory of my npm security footprint (especially for &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Just in the last few months:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;November 2025&lt;/code&gt;: &lt;a href=&quot;https://socket.dev/blog/shai-hulud-strikes-again-v2&quot;&gt;Shai Halud v2 (PostHog)&lt;/a&gt; (and &lt;a href=&quot;https://posthog.com/blog/nov-24-shai-hulud-attack-post-mortem&quot;&gt;PostHog post-mortem&lt;/a&gt;): Worm infected ×834 packages. Propagated via &lt;code&gt;preinstall&lt;/code&gt; npm script.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;September 2025&lt;/code&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/tinycolor-supply-chain-attack-affects-40-packages&quot;&gt;Shai Halud (&lt;code&gt;@ctrl/tinycolor&lt;/code&gt;, CrowdStrike)&lt;/a&gt;: Worm infected ×526 packages. Propagated via &lt;code&gt;postinstall&lt;/code&gt; npm script.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/duckdb-npm-account-compromised-in-continuing-supply-chain-attack&quot;&gt;DuckDB&lt;/a&gt;: targeted phishing email (&lt;em&gt;with&lt;/em&gt; 2FA) pointed to fake domain &lt;code&gt;npmjs.help&lt;/code&gt;. Compromised packages were published with token created by attacker.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/npm-author-qix-compromised-in-major-supply-chain-attack&quot;&gt;&lt;code&gt;debug&lt;/code&gt; and &lt;code&gt;chalk&lt;/code&gt;&lt;/a&gt;: same as above: targeted phishing email (&lt;em&gt;with&lt;/em&gt; 2FA).&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;August 2025&lt;/code&gt;: &lt;a href=&quot;https://socket.dev/blog/nx-packages-compromised&quot;&gt;S1ngularity (Nx)&lt;/a&gt; (and &lt;a href=&quot;https://nx.dev/blog/s1ngularity-postmortem&quot;&gt;Nx post-mortem&lt;/a&gt;): well-meaning but insecure code (from approved authors) was merged which allowed arbitrary commands to be executed via content in Pull Requests to the repo. Compromised packages were published via a stolen NPM token.&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;Expand to see the insecure YAML from the S1ngularity attack &lt;!-- https://github.com/nrwl/nx/pull/32458/files --&gt;&lt;/summary&gt;
&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Some content omitted for brevity&lt;/span&gt;
on:
  pull_request:
    types: &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;opened, edited, synchronize, reopened&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# …&lt;/span&gt;
jobs:
  validate-pr-title:
    &lt;span class=&quot;token comment&quot;&gt;# …&lt;/span&gt;
    steps:
      &lt;span class=&quot;token comment&quot;&gt;# …&lt;/span&gt;
      - name: Create PR message &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;
        run: &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; /tmp
          &lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /tmp/pr-message.txt &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;&lt;/span&gt;
          &lt;span class=&quot;token variable&quot;&gt;${{ github.event.pull_request.title }&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

          &lt;span class=&quot;token variable&quot;&gt;${{ github.event.pull_request.body }&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          EOF

      - name: Validate PR title
        run: &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Validating PR title: &lt;span class=&quot;token variable&quot;&gt;${{ github.event.pull_request.title }&lt;/span&gt;}&quot;&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; ./scripts/commit-lint.js /tmp/pr-message.txt&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;Given the attack vectors of recent incidents, any packages using GitHub Actions (or other CI) to publish should be considered to have an elevated risk (and this was very common across &lt;a href=&quot;https://github.com/orgs/11ty/repositories&quot;&gt;&lt;code&gt;11ty&lt;/code&gt;’s &lt;em&gt;numerous&lt;/em&gt; packages&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I’ve been pretty cautious about npm tokens. I have each repository set up (painstakingly) to use &lt;em&gt;extremely&lt;/em&gt; granular tokens (access to publish one package and one package &lt;em&gt;only&lt;/em&gt;). This limits the blast radius of any compromise to a single package and has helped manage my blood pressure (I accidentally &lt;a href=&quot;https://github.com/11ty/eleventy-plugin-syntaxhighlight/issues/93&quot;&gt;leaked&lt;/a&gt; a token earlier this year).&lt;/p&gt;
&lt;h2 id=&quot;security-checklist&quot;&gt;Security Checklist&lt;/h2&gt;
&lt;p&gt;I’ve completed my review and made a bunch of changes to improve my security footprint on GitHub and npm, noted below. The suggestions below avoid introducing additional third-party tooling that may decrease your footprint short-term (while actually increasing it long-term).&lt;/p&gt;
&lt;p&gt;Caveat: my current workflow uses GitHub Releases to trigger a GitHub Action workflow to publish packages to npm (and this advice may vary a bit if you’re using different tools like GitLab or pnpm or yarn, sorry).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-check-double&quot; xlink:href=&quot;#fas-fa-check-double&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;Two-Factor Authentication&lt;/strong&gt; (2FA) for both GitHub AND npm, for &lt;em&gt;every&lt;/em&gt; person that has access to publish. This is table-stakes. No compromises. Require 2FA everywhere.
&lt;ul&gt;
&lt;li&gt;On GitHub, go to your organization’s Settings page and navigate to Authentication Security. Check the &lt;em&gt;Require Two-factor authentication for everyone&lt;/em&gt; and &lt;em&gt;Only allow secure two-factor methods&lt;/em&gt; checkboxes.&lt;/li&gt;
&lt;li&gt;npm requires you to specify this on a per-package basis that I describe in the &lt;em&gt;Restrict Publishing Access&lt;/em&gt; section below.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When logging into npm and GitHub, use your &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-key&quot; xlink:href=&quot;#fas-fa-key&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;password manager exclusively&lt;/strong&gt;! Never type in a password or a 2FA code manually. Your password manager will help ensure that you don’t put in your credentials on a compromised (but realistic looking) domain.
&lt;ul&gt;
&lt;li&gt;Would you know that &lt;code&gt;npmjs.help&lt;/code&gt; was a spoofed domain? Maybe on your average day, but on your worst day? When you didn’t sleep well the night before? 😴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Review GitHub users that have the &lt;a href=&quot;https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/managing-repository-roles/repository-roles-for-an-organization#permissions-for-each-role&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-pencil&quot; xlink:href=&quot;#fas-fa-pencil&quot;&gt;&lt;/use&gt;&lt;/svg&gt;Write role&lt;/a&gt; in your repositories (Write can create releases).&lt;/li&gt;
&lt;li&gt;Find any repositories using NPM tokens and &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-skull&quot; xlink:href=&quot;#fas-fa-skull&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;delete the tokens&lt;/strong&gt; in the settings for &lt;em&gt;both&lt;/em&gt; GitHub and npm. We’re moving to a post-token world.
&lt;ul&gt;
&lt;li&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-trophy&quot; xlink:href=&quot;#fas-fa-trophy&quot;&gt;&lt;/use&gt;&lt;/svg&gt;Success criteria is having &lt;a href=&quot;https://fediverse.zachleat.com/@zachleat/115652337081660540&quot;&gt;0 Access Tokens listed in your npm Settings&lt;/a&gt; (granular or otherwise).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Switch to use &lt;a href=&quot;https://docs.npmjs.com/trusted-publishers&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-plug&quot; xlink:href=&quot;#fas-fa-plug&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;Trusted Publishers&lt;/strong&gt;&lt;/a&gt; (OIDC) in the Settings tab for each npm package. This will also setup the release to include provenance as well (which is great).
&lt;ul&gt;
&lt;li&gt;This scopes your credentials to one specific GitHub Action (you specify which file to point to in &lt;code&gt;.github/workflows/&lt;/code&gt;) and allows you to remove any references to tokens in the GitHub Actions YAML configuration file.&lt;/li&gt;
&lt;li&gt;The big goal here for me was to completely separate my publish workflow and credentials and disallow any access to those credentials from other workflows in the repository (usually unit tests that run on every commit to the repo). You &lt;em&gt;could&lt;/em&gt; also use GitHub Environments to achieve this. This limits the blast radius from worm propagation (via &lt;code&gt;postinstall&lt;/code&gt; or &lt;code&gt;preinstall&lt;/code&gt;) to publish events only (not every commit), which is far more infrequent.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restrict npm Publishing Access&lt;/strong&gt; in the Settings tab for each npm package. Use the &lt;em&gt;Require two-factor authentication and disallow tokens (recommended)&lt;/em&gt; option. Death to tokens!&lt;/li&gt;
&lt;li&gt;Check in your &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-lock&quot; xlink:href=&quot;#fas-fa-lock&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;lock file&lt;/strong&gt; (e.g. &lt;code&gt;package-lock.json&lt;/code&gt; for npm). This is especially important when using a release script that uses npm packages to generate release artifacts. Use &lt;a href=&quot;https://docs.npmjs.com/cli/v10/commands/npm-ci&quot;&gt;&lt;code&gt;npm ci&lt;/code&gt;&lt;/a&gt; instead of &lt;code&gt;npm install&lt;/code&gt; in your release script.&lt;/li&gt;
&lt;li&gt;GitHub Actions configuration files should &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-thumbtack&quot; xlink:href=&quot;#fas-fa-thumbtack&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;pin the full SHA&lt;/strong&gt; for &lt;code&gt;uses&lt;/code&gt; dependencies (e.g. &lt;a href=&quot;https://github.com/11ty/eleventy-plugin-vite/blob/c04e9630b8c89a9ca8896eb0ab35328323d99ee1/.github/workflows/release.yml#L14-L15&quot;&gt;&lt;code&gt;eleventy-plugin-vite&lt;/code&gt;&lt;/a&gt;). I learned that &lt;a href=&quot;https://github.com/11ty/eleventy-plugin-vite/blob/c04e9630b8c89a9ca8896eb0ab35328323d99ee1/.github/dependabot.yml#L9&quot;&gt;Dependabot can update and manage these&lt;/a&gt; too!&lt;!-- I’m reminded of my [`setup-node` dependency failing on Node 22](https://fediverse.zachleat.com/@zachleat/112814100573630319) last year (though I couldn’t say conclusively whether or not this would have avoided that issue). --&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;other-good-ideas&quot;&gt;Other good ideas&lt;/h3&gt;
&lt;p&gt;Given the above changes, I would consider the following items to not to be of immediate urgency (though still recommended).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub: Enable &lt;a href=&quot;https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/immutable-releases&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-house-lock&quot; xlink:href=&quot;#fas-fa-house-lock&quot;&gt;&lt;/use&gt;&lt;/svg&gt;Immutable Releases&lt;/a&gt; preferably at the organization level. This will ensure no one can change tags and release contents after a release has been shipped.&lt;/li&gt;
&lt;li&gt;Use a package manager &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-snowflake&quot; xlink:href=&quot;#fas-fa-snowflake&quot;&gt;&lt;/use&gt;&lt;/svg&gt;cooldown.
&lt;ul&gt;
&lt;li&gt;Added the &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#cooldown-&quot;&gt;&lt;code&gt;cooldown&lt;/code&gt; option to my Dependabot configuration&lt;/a&gt; (direct &lt;a href=&quot;https://github.com/11ty/eleventy/blob/bcd75f56524a3874aeb3dfb49569ffd5ac745ca5/.github/dependabot.yml#L12-L13&quot;&gt;link to &lt;code&gt;dependabot.yml&lt;/code&gt;&lt;/a&gt;). This updates production dependencies weekly, now with a 7 day cooldown.&lt;/li&gt;
&lt;li&gt;I usually use &lt;code&gt;npm-check-updates&lt;/code&gt; for local package.json file maintenance. It has a &lt;a href=&quot;https://github.com/raineorshine/npm-check-updates?tab=readme-ov-file#cooldown&quot;&gt;&lt;code&gt;cooldown&lt;/code&gt; option too&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm install&lt;/code&gt; does have a &lt;a href=&quot;https://docs.npmjs.com/cli/v11/commands/npm-install#before&quot;&gt;&lt;code&gt;--before&lt;/code&gt;&lt;/a&gt; option to pass a Date that can be used similarly (though isn’t &lt;a href=&quot;https://github.com/npm/cli/pull/8802&quot;&gt;relative&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;More on &lt;a href=&quot;https://socket.dev/blog/pnpm-10-16-adds-new-setting-for-delayed-dependency-updates&quot;&gt;socket.dev: pnpm 10.16 Adds New Setting for Delayed Dependency Updates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Reduce &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-arrow-down&quot; xlink:href=&quot;#fas-fa-arrow-down&quot;&gt;&lt;/use&gt;&lt;/svg&gt;dependencies! Every third party dependency has some risk associated with it, as you’re inheriting a bit of those developers’ security footprint too. It’s worth noting that the work being done by the folks at &lt;a href=&quot;https://e18e.dev/&quot;&gt;e18e&lt;/a&gt; to reduce dependency counts is making great headway to improve the ecosystem at large. You can do this in your own projects! I’m proud of the work we’ve done on &lt;code&gt;@11ty/eleventy&lt;/code&gt; over the years (source: &lt;a href=&quot;https://github.com/11ty/eleventy/releases/tag/v3.1.0&quot;&gt;v3.1.0 release notes&lt;/a&gt;): &lt;table&gt;&lt;thead&gt;
  &lt;tr&gt;
    &lt;th&gt;Version&lt;/th&gt;
    &lt;th&gt;Production Dep Count&lt;/th&gt;
    &lt;th&gt;Production Size&lt;/th&gt;
  &lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
  &lt;tr&gt;
    &lt;td&gt;v3.1.0&lt;/td&gt;
    &lt;td&gt;×142&lt;/td&gt;
    &lt;td&gt;21.4 MB&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;v3.0.0&lt;/td&gt;
    &lt;td&gt;×187&lt;/td&gt;
    &lt;td&gt;27.4 MB&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;v2.0.1&lt;/td&gt;
    &lt;td&gt;×215&lt;/td&gt;
    &lt;td&gt;36.4 MB&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;v1.0.2&lt;/td&gt;
    &lt;td&gt;×356&lt;/td&gt;
    &lt;td&gt;73.3 MB&lt;/td&gt;
  &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;Some folks recommend disabling scripts when installing (via &lt;code&gt;npm config set ignore-scripts true&lt;/code&gt; or via stock use of &lt;a href=&quot;https://pnpm.io/&quot;&gt;pnpm&lt;/a&gt;). This might be marginally useful in some cases but in my opinion is just a short term solution in response to common attack patterns that we’ve already seen. Importing (or requiring) a compromised or malicious package can execute arbitrary commands without using a &lt;code&gt;preinstall&lt;/code&gt; or &lt;code&gt;postinstall&lt;/code&gt; script just fine. If you really need to lock down your environment, you might consider running a &lt;a href=&quot;https://www.virtualbox.org/&quot;&gt;Virtual Machine&lt;/a&gt;, &lt;a href=&quot;https://code.visualstudio.com/docs/devcontainers/create-dev-container&quot;&gt;Dev Container&lt;/a&gt;, and/or using &lt;a href=&quot;https://nodejs.org/docs/latest/api/permissions.html&quot;&gt;Node.js’ Permissions model&lt;/a&gt; or &lt;a href=&quot;https://docs.deno.com/runtime/fundamentals/security/&quot;&gt;stock Deno&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stay safe out there, y’all!&lt;/p&gt;
&lt;h2 id=&quot;additional-reading&quot;&gt;Additional Reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://snyk.io/articles/npm-security-best-practices-shai-hulud-attack/&quot;&gt;snyk NPM Security Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openjsf.org/blog/publishing-securely-on-npm&quot;&gt;Publishing More Securely on npm: Guidance from the OpenJS Security Collaboration Space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/npm-pub-2025/ci-publish&quot;&gt;Publishing from CI with 2FA (GitHub Tutorial)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>How to Hallucinate using Web Components</title>
    <link href="https://www.zachleat.com/web/hallucinate/" />
    <updated>2025-11-21T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/hallucinate/</id>
    <content type="html">&lt;p&gt;Say, you want the smooth convenience of consuming content that &lt;em&gt;feels&lt;/em&gt; like it’s generated in real time &lt;em&gt;without&lt;/em&gt; having to deal with the tradeoffs of a Large Language Model née Artificial Intelligence.&lt;/p&gt;
&lt;p&gt;Why not use animation? It’s the perfect metaphor for a Hollywood-esque veneer of complexity without substance, in no way similar to how an entire industry is currently being oversold and at no risk of imminent collapse.&lt;/p&gt;
&lt;p&gt;This approach animates each blog post’s content (already generated by a human, manually) progressively to emulate existing chatbox user experience patterns for hallucinating text. You can try it out right now by hitting the &lt;em&gt;Hallucinate&lt;/em&gt; toggle below:&lt;is-land on:media=&quot;(prefers-reduced-motion: no-preference)&quot;&gt;
&lt;template data-island&gt;
&lt;is-land on:visible class=&quot;toggle-island&quot;&gt;&lt;/is-land&gt;&lt;/template&gt;&lt;/is-land&gt;&lt;/p&gt;
&lt;p&gt;&lt;button id=&quot;ai-mode-inline&quot; type=&quot;button&quot; aria-pressed=&quot;false&quot; class=&quot;toggle&quot;&gt;
&lt;span class=&quot;toggle-control&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;toggle-text&quot;&gt;Hallucinate&lt;/span&gt;
&lt;/button&gt;
&lt;template data-island=&quot;once&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://www.zachleat.com/static/toggle-button.css&quot;&gt;
&lt;script src=&quot;https://www.zachleat.com/static/toggle-button.js&quot;&gt;&lt;/script&gt;
&lt;/template&gt;


&lt;/p&gt;
&lt;h2 id=&quot;how-does-it-work&quot;&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;This makes use of the &lt;a href=&quot;https://www.zachleat.com/web/squirminal/&quot;&gt;&lt;code&gt;&amp;lt;squirm-inal&amp;gt;&lt;/code&gt; Web Component&lt;/a&gt;, originally for &lt;a href=&quot;https://your-year-on.netlify.com/&quot;&gt;Netlify’s Your Year on Netlify&lt;/a&gt; microsite and using lessons learned from &lt;a href=&quot;https://www.zachleat.com/web/queue-code/&quot;&gt;Queue Code (a way to live code without live coding)&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// It works with any arbitrary HTML content&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// including this syntax highlighted code block&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&quot;use AI&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To implement this yourself, just wrap any arbitrary content (say &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;) in a newly created &lt;code&gt;&amp;lt;squirm-inal autoplay speed=&amp;quot;0.6&amp;quot;&amp;gt;&lt;/code&gt; element and you’re off to the races.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://unpkg.com/@zachleat/squirminal@3.0.1/squirminal.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;integrity&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;sha384-m+pplzdzdfZuwjyxmM9pOkp/ALfMMjZll/b2g2mR6mhurvj1ZZAe8xXNj7BSp4XM&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;crossorigin&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;anonymous&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; main &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; squirm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;squirm-inal&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
squirm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;speed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.6&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
squirm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;autoplay&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
squirm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;squirm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;You could swap the &lt;code&gt;&amp;lt;script src&amp;gt;&lt;/code&gt; above to use &lt;code&gt;import()&lt;/code&gt; instead but that would remove the option for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity&quot;&gt;subresource &lt;code&gt;integrity&lt;/code&gt;&lt;/a&gt; (always important for CDN use).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That’s it!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How we use GitHub Issues (on 11ty) and how that’s Changing</title>
    <link href="https://www.zachleat.com/web/11ty-github-issues/" />
    <updated>2025-11-03T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/11ty-github-issues/</id>
    <content type="html"></content>
  </entry>
</feed>