One of my biggest annoyances with TypeScript is that any time you use it on a project with newer web features, you inevitably run into type errors. For example, here’s a screenshot of an error I got just the other day when trying to use element-scoped view transitions: “Property ‘startViewTransition’ does not exist on type ‘HTMLElement’.” Or this error when trying to use the Long Animation Frame API to measure and optimize JavaScript execution performance: “Property ‘scripts’ does not exist on type ‘PerformanceEntry’.” Or yet another one when trying to feature-detect and use fetchLater() to…
In 2017, I wrote an article showing web developers how they could deploy ES6+ code (a.k.a. ES2015) to production, without needing to transpile it to ES5. This technique was liberating for website developers who wanted the freedom to write modern code without having to worry about transpiler or polyfill bloat. Unfortunately, while many website developers were able to use this technique, most JavaScript library authors could not. Library authors face a lot more constraints than website developers, because they don’t control how their code is deployed. Also, since many of the popular build tools…
Earlier this year, Chrome shipped the new Priority Hints API, which lets developers set fetchpriority="high" on <img>, <script>, <link> or other elements that you want to ensure are loaded with a high priority. Personally, I’m a huge fan of this API. And I think that adding it to your site is one of the simplest and most effective ways to improve LCP. There’s just one small problem. In order to be able to use this API, you have to know ahead of time what the LCP element is going to be for every page you want to use it on. For simple sites with mostly static content, that’s not usually a…
Performant A/B testing has sort of been the white whale of the web performance industry for a number of years now. While most teams I talk to would love to be able to run A/B tests to accurately assess the performance impact of certain changes, the problem is pretty much every popular A/B testing tool on the market has such a negative impact on load performance that they’re essentially unusable for this purpose. If you’re just trying to determine which of two marketing headlines converts better, then perhaps this performance difference isn’t so bad. But if you’re wanting to run an A/B test to…
I have noticed a trend in recent years—a trend that I’ve admittedly been part of myself—where performance-minded developers will rebuild a site and then post a screenshot of their Lighthouse score on social media to show off how fast it is. What might come as a surprise to many of the people reading this post is that I kinda want this trend to stop—or at least, I want it to change. Now, let me be perfectly clear: there is absolutely nothing wrong with bragging about your success on social media, and there’s also nothing wrong with using Lighthouse or striving to get a good Lighthouse score.…
Many developers know that you can use service workers to cache web pages (and their sub-resources) in order to serve those pages to users when they’re offline. And while this is true, it’s far from the only thing that service workers can do to improve the performance and reliability of a website. A lesser known capability of service workers is that you can programmatically generate your responses—you aren’t limited to just fetching from the network or reading from the cache. In a traditional client-server setup, the server always needs to send a full HTML page to the client for every request…
For several years now, pretty much every article published on caching best practices has recommended the following two things for deploying JavaScript code in production: Add revision information to the filenames of your assets (usually content hashes) Set far-future expiry or max-age caching headers (so they don’t have to be revalidated for returning visitors) Every bundling tool I know of supports adding content hashes with a simple configuration rule (like the following), and as a result this practice has now become ubiquitous: filename: '[name]-[contenthash].js'; The other thing most…
Two years ago I wrote about a technique—now commonly referred to as the module/nomodule pattern—that allows you to write ES2015+ JavaScript and then use bundlers and transpilers to generate two versions of your codebase, one with modern syntax (loaded via <script type="module">) and one with ES5 syntax (loaded via <script nomodule>). The technique allows you to ship significantly less code to module-supporting browsers, and it’s now supported by most web frameworks and CLIs. But back then, even with the ability to deploy modern JavaScript in production, and even though most browsers supported…
March 11, 2019 Chrome is experimenting with two new features that I firmly believe will completely change how we bundle and deploy JavaScript applications in the future (for the better): Built-in Modules and Import Maps. The first built-in module we’re shipping (behind the experimental web platform features flag) is called KV Storage. It’s an asynchronous key/value storage API built on top of IndexedDB. In this article on developers.google.com I introduce these new APIs and show you how you can use them in your applications. I’ve also built a demo application that shows how you can actually…
A few weeks ago I was looking at some of the performance metrics for my site. Specifically, I wanted to see how I was doing on our newest metric, first input delay (FID). My site is just a blog (and doesn’t run much JavaScript), so I expected to see pretty good results. Input delay that’s less than 100 milliseconds is typically perceived as instant by users, so the performance goal we recommend (and the numbers I was hoping to see in my analytics) is FID < 100ms for 99% of page loads. To my surprise, my site’s FID was 254ms at the 99th percentile. And while that’s not terrible, the…
July 24, 2018 If you’re like me, it’s not uncommon for you to have so many tabs open in your browser that you can’t even read all their titles. The problem with this, of course, is all these tabs consume system resources (memory, battery, and CPU), and if you never end up going back to them again (which, let’s be honest, happens more often than not) those resources were consumed for nothing. The solution to this problem is for browser tabs to behave more like mobile apps, which can be started and stopped at any time by the operating system and gives these platforms the ability to streamline…
May 10, 2018 On the web, a good first impression can make the difference between someone becoming a loyal user and them leaving and never coming back. One of the key ways a site shapes our first impression is what happens when we first try to interact with it. Is it fast and responsive? Is it slow and sluggish? Does it not respond at all (and make us think it’s broken)? To help quantify this, we’ve introduced a new performance metric called First Input Delay. To quote from my article on developers.google.com: First Input Delay (FID) measures the time from when a user first interacts with your…
Container queries is a proposal that would allow web developers to style DOM elements based on the size of a containing element rather than the size of the browser viewport. If you’re a web developer, you’ve probably heard about container queries before. For about as long as we’ve had responsive web design, we’ve had developers asking for them (initially element queries, then changing to container queries). In fact, container queries may well be the most requested CSS feature ever that we still don’t have in browsers. There are already many, many, many posts explaining exactly why container…
Anyone who’s browsed the web on their phone has, at one point or another, experienced this situation: You open a web page and click on something, but nothing happens. You click on it again—still nothing happens. You click on something else—nope, nothing. This is bad enough on its own, but it often doesn’t end there. Here’s what usually happens next: You start clicking everywhere just to get some feedback that your phone isn’t broken—then suddenly a bunch of stuff all happens at the same time, and now you’re on a completely different page and you have no idea how you got there. If this sounds…
Most web developers I talk to these days love writing JavaScript with all the newest language features—async/await, classes, arrow functions, etc. However, despite the fact that all modern browsers can run ES2015+ code and natively support the features I just mentioned, most developers still transpile their code to ES5 and bundle it with polyfills to accommodate the small percentage of users still on older browsers. This kinda sucks. In an ideal world, we wouldn’t be shipping unnecessary code. With new JavaScript and DOM APIs, we can conditionally load polyfills because we can feature detect…
All analytics tools I know of track pageviews in a way that—to put it bluntly—simply doesn’t work for a growing number of websites today and is completely incompatible with the direction the web is heading. For the most part, these tools assume (by default) that each pageview corresponds to a full page load, and that each page load runs some analytics tracking code, and sends a pageview to a back-end server. Anything that deviates from this model requires extra work on the part of the site developer—work most developers don’t have the time or expertise to do. The reality is the web has…
Google Analytics is a powerful yet quite complicated tool. And unfortunately, the truth is most people who use it don’t reap its full benefits. There’s a lot of excellent and free content out there that explains how to use Google Analytics, but most of it is rather narrowly focused on use cases that primarily apply to marketers and advertisers; very little is geared toward web developers who simply want to better understand how people are using the sites they build. For the past three years I’ve worked on Google Analytics (specifically on the web tracking side), and in that time I’ve learned…
Earlier this year I wrote an article for Smashing Magazine about Houdini, and I called it the “most exciting development in CSS you’ve never heard of”. In the article I argue that Houdini APIs will (among other things) make it possible to polyfill CSS features in a way that simply cannot be done today. While the article was generally quite well-received, I did notice the same question popping up over and over again in my inbox and on Twitter. The basic gist of the question was: What’s so hard about polyfilling CSS? I’ve used lots of CSS polyfills, and they worked fine for me. And I…
New JavaScript and HTML features are being introduced all the time that make our lives as developers easier. In many cases, these new features are so helpful we choose to use them on production websites before they’re fully implemented in all browsers. To not break the experience for users on older browsers, we of course include polyfills for any not-fully-supported features. The problem with this approach is it prioritizes developer convenience over user experience, and it unnecessarily penalizes users on modern browsers by forcing them to download a lot of code they don’t need. The solution…
If you’ve been writing JavaScript for a while, you’ve probably heard terms like callback hell or the pyramid of doom. When promises were added to JavaScript a few years ago, I remember reading a lot of blog posts claiming that these problems would be solved; unfortunately, that was a little too optimistic. With more and more web APIs becoming promise-based, we’ve proven that even promises don’t prevent us from writing overly-nested, hard-to-read code. The place I’m seeing this happen a lot these days is in Service Worker scripts that are heavily promise-based. Specifically, blog posts and…
Read at the source
Your visit, your choice.
Optional Google Analytics helps us understand visits. Microsoft Clarity records masked interactions to improve the site. Optional tools stay off unless you choose them. Privacy details.