How to Make Websites That Will Require Lots of Your Time and Energy - Jim Nielsen’s Blog
- Install Stuff Indiscriminately From npm
- Pick a Framework Before You Know You Need One
- Always, Always Require a Compilation Step
- Install Stuff Indiscriminately From npm
- Pick a Framework Before You Know You Need One
- Always, Always Require a Compilation Step
An enjoyable guided tour of album artwork starting at the beginning of the twentieth century.
We’re at a point in the most ecosystems where pulling in libraries is not just the default action, it’s seen positively: “Look how modular and composable my code is!” Actually, it might just be a symptom of never wanting to type out more than a few lines.
It always amazes me when people don’t view dependencies as liabilities. To me it feels like the coding equivalent of going to a loan shark. You are asking for technical debt.
There are entire companies who are making a living of supplying you with the tools needed to deal with your dependency mess. In the name of security, we’re pushed to having dependencies and keeping them up to date, despite most of those dependencies being the primary source of security problems.
But there is a simpler path. You write code yourself. Sure, it’s more work up front, but once it’s written, it’s done.
I like the look of this proposal that would allow authors to have more control over network priorities for third-party iframes—I’ve already documented how I had to use a third-party library to fix this problem on the Salter Cane site.
The tech bros advocating for generative AI to take over art are at the same level of cultural refinement as the characters in Severance. They’re creating apps to summarize books to people, tweeting from accounts with Greek statue profile pictures.
GenAI would automate Lumon’s cultural mission, allowing humans to sever themselves from the production of art and culture.
In which Rich nails Clearleft’s superpower:
“Clearleft is a relatively small team, but we can achieve big results because we are nimble and extremely experienced. As strategic design partners, we have a privileged position where we can work around a large company’s politics,” Rutter said. “We need to understand those politics — and help the client staff navigate them — but we don’t need to be bound by them. We bring a thoroughly user-centered approach to our design partnership, and that can be something novel to companies. By showing them what good design looks like (not so much the interface, as the actual process of getting to really well-designed products and services), we can be disruptive within the organization and leave them in a much better place.”
We wonder often if what is created by AI has any value, and at what cost to artists and creators. These are important considerations. But we need to also wonder what AI is taking from what has already been created.
Another handy list of where you can get works published by A Book Apart authors.
Yesterday when I mentioned my paranoia of third-party dependencies on The Session, I said:
I’ve built in the option to switch between multiple geocoding providers. When one of them inevitably starts enshittifying their service, I can quickly move on to another. It’s like having a “go bag” for geocoding.
(Geocoding, by the way, is when you provide a human-readable address and get back latitude and longitude coordinates.)
My paranoia is well-founded. I’ve been using Google’s geocoding API, which is changing its pricing model from next March.
You wouldn’t know it from the breathlessly excited emails they’ve been sending about it, but this is not a good change for me. I don’t do that much geocoding on The Session—around 13,000 or 14,000 requests a month. With the new pricing model that’ll be around $15 to $20 a month. Currently I slip by under the radar with the free tier.
So it might be time for me to flip that switch in my code. But which geocoding provider should I use?
There are plenty of slop-like listicles out there enumerating the various providers, but they’re mostly just regurgitating the marketing blurbs from the provider websites. What I need is more like a test kitchen.
Here’s what I did…
I took a representative sample of six recent additions to the sessions section of thesession.org. These examples represent places in the USA, Ireland, England, Scotland, Northern Ireland, and Spain, so a reasonable spread.
For each one of those sessions, I’m taking:
I’m deliberately not including the street address. Quite often people don’t bother including this information so I want to see how well the geocoding APIs cope without it.
I’ve scored the results on a simple scale of good, so-so, and just plain wrong.
Then I tot up those results for an overall score for each provider.
When I tried my six examples with twelve different geocoding providers, these were the results:
Provider | USA | England | Ireland | Spain | Scotland | Northern Ireland | Total |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 7 | |
Mapquest | 1 | 1 | 1 | 1 | 1 | 1 | 7 |
Geoapify | 0 | 1 | 1 | 0 | 1 | 0 | 3 |
Here | 1 | 1 | 0 | 1 | 0 | 0 | 3 |
Mapbox | 1 | 1 | 0 | 1 | 1 | -1 | 3 |
Bing | 1 | 0 | 0 | 0 | 0 | 0 | 1 |
Nominatim | 0 | 0 | 0 | 0 | -1 | 1 | 0 |
OpenCage | -1 | 1 | 0 | 0 | 0 | -1 | -1 |
Tom Tom | -1 | -1 | 0 | 0 | -1 | 1 | -2 |
Positionstack | 0 | -1 | 0 | -1 | 1 | -1 | -2 |
Locationiq | -1 | 0 | -1 | 0 | 0 | -1 | -3 |
Map Maker | -1 | 0 | -1 | -1 | -1 | -1 | -5 |
Some interesting results there. I was surprised by how crap Bing is. I was also expecting better results from Mapbox.
Most interesting for me, Mapquest is right up there with Google.
So now that I’ve got a good scoring system, my next question is around pricing. If Google and Mapquest are roughly comparable in terms of accuracy, how would the pricing work out for each of them?
Let’s say I make 15,000 API requests a month. Under Google’s new pricing plan, that works out at $25. Not bad.
But if I’ve understood Mapquest’s pricing correctly, I reckon I’ll just squeek in under the free tier.
Looks like I’m flipping the switch to Mapquest.
If you’re shopping around for geocoding providers, I hope this is useful to you. But I don’t think you should just look at my results; they’re very specific to my needs. Come up with your own representative sample of tests and try putting the providers through their paces with your data.
If, for some reason, you want to see the terrible PHP code I’m using for geocoding on The Session, here it is.
The Session has been online for over 20 years. When you maintain a site for that long, you don’t want to be relying on third parties—it’s only a matter of time until they’re no longer around.
Some third party APIs are unavoidable. The Session has maps for sessions and other events. When people add a new entry, they provide the address but then I need to get the latitude and longitude. So I have to use a third-party geocoding API.
My code is like a lesson in paranoia: I’ve built in the option to switch between multiple geocoding providers. When one of them inevitably starts enshittifying their service, I can quickly move on to another. It’s like having a “go bag” for geocoding.
Things are better on the client side. I’m using other people’s JavaScript libraries—like the brilliant abcjs—but at least I can self-host them.
I’m using Leaflet for embedding maps. It’s a great little library built on top of Open Street Map data.
A little while back I linked to a new project called OpenFreeMap. It’s a mapping provider where you even have the option of hosting the tiles yourself!
For now, I’m not self-hosting my map tiles (yet!), but I did want to switch to OpenFreeMap’s tiles. They’re vector-based rather than bitmap, so they’re lovely and crisp.
But there’s an issue.
I can use OpenFreeMap with Leaflet, but to do that I also have to use the MapLibre GL library. But whereas Leaflet is 148K of JavaScript, MapLibre GL is 800K! Yowzers!
That’s mahoosive by the standards of The Session’s performance budget. I’m not sure the loveliness of the vector maps is worth increasing the JavaScript payload by so much.
But this doesn’t have to be an either/or decision. I can use progressive enhancement to get the best of both worlds.
If you land straight on a map page on The Session for the first time, you’ll get the old-fashioned bitmap map tiles. There’s no MapLibre code.
But if you browse around The Session and then arrive on a map page, you’ll get the lovely vector maps.
Here’s what’s happening…
The maps are embedded using an HTML web component called embed-map
. The fallback is a static image between the opening and closing tags. The web component then loads up Leaflet.
Here’s where the enhancement comes in. When the web component is initiated (in its connectedCallback
method), it uses the Cache API to see if MapLibre has been stored in a cache. If it has, it loads that library:
caches.match('/path/to/maplibre-gl.js')
.then( responseFromCache => {
if (responseFromCache) {
// load maplibre-gl.js
}
});
Then when it comes to drawing the map, I can check for the existence of the maplibreGL
object. If it exists, I can use OpenFreeMap tiles. Otherwise I use the old Leaflet tiles.
But how does the MapLibre library end up in a cache? That’s thanks to the service worker script.
During the service worker’s install
event, I give it a list of static files to cache: CSS, JavaScript, and so on. That includes third-party libraries like abcjs, Leaflet, and now MapLibre GL.
Crucially this caching happens off the main thread. It happens in the background and it won’t slow down the loading of whatever page is currently being displayed.
That’s it. If the service worker installation works as planned, you’ll get the nice new vector maps. If anything goes wrong, you’ll get the older version.
By the way, it’s always a good idea to use a service worker and the Cache API to store your JavaScript files. As you know, JavaScript is unduly expensive to performance; not only does the JavaScript file have to be downloaded, it then has to be parsed and compiled. But JavaScript stored in a cache during a service worker’s install
event is already parsed and compiled.
I miss A Book Apart, and I really miss An Event Apart—I made so many friends and memories through that conference. I admire Jeffrey’s honest account of how much it sucks when something so good comes to an end.
In 2024, A Book Apart closed its doors after publishing a much-loved collection of more than 50 brief books for people who make websites. The rights to each book have reverted to the authors — hi, that’s us — and we’ve put together this semi-official directory to help you find our books in their new homes.
…now including Going Offline.
I wrote a book about service workers. It’s called Going Offline. It was first published by A Book Apart in 2018. Now it’s available to read for free online.
If you want you can read the book as a PDF, an ePub, or .mobi, but I recommend reading it in your browser.
Needless to say the web book works offline. Once you go to goingoffline.adactio.com you can add it to the homescreen of your mobile device or add it to the dock on your Mac. After that, you won’t need a network connection.
The book is free to read. Properly free. Not the kind of “free” where you have to supply an email address first. Why would I make you go to the trouble of generating a burner email account?
The site has no analytics. No tracking. No third-party scripts of any kind whatsover. By complete coincidence, the site is fast. Funny that.
For the styling of this web book, I tweaked the stylesheet I used for HTML5 For Web Designers. I updated it a little bit to use logical properties, some fluid typography and view transitions.
In the process of converting the book to HTML, I got reaquainted with what I had written almost seven years ago. It was kind of fun to approach it afresh. I think it stands up pretty darn well.
Ethan wrote about his feelings when he put two of his books online, illustrated by that amazing photo that always gives me the feels:
I’ll miss those days, but I’m just glad these books are still here. They’re just different than they used to be. I suppose I am too.
Anyway, if you’re interested in making your website work offline, have a read of Going Offline. Enjoy!
The slides from Hidde’s presentation at Beyond Tellerrand.
This project, based on OpenStreetMap, looks great:
OpenFreeMap lets you display custom maps on your website and apps for free.
You can either self-host or use our public instance.
I’m going to try it out on The Session once there’s documentation for using this with Leaflet.
I hope to make something that could only exist because I made it. Something that is the one thing that it is. Not an average sentence. Not a visual approximation of other people’s work. Not a stolen concept that boils lakes and uses more electricity than anything in my household.
Using ChatGPT to complete assignments is like bringing a forklift into the weight room; you will never improve your cognitive fitness that way.
Another great piece by Ted Chiang!
The companies promoting generative-A.I. programs claim that they will unleash creativity. In essence, they are saying that art can be all inspiration and no perspiration—but these things cannot be easily separated. I’m not saying that art has to involve tedium. What I’m saying is that art requires making choices at every scale; the countless small-scale choices made during implementation are just as important to the final product as the few large-scale choices made during the conception.
This bit reminded me of Simon’s rule:
Let me offer another generalization: any writing that deserves your attention as a reader is the result of effort expended by the person who wrote it. Effort during the writing process doesn’t guarantee the end product is worth reading, but worthwhile work cannot be made without it. The type of attention you pay when reading a personal e-mail is different from the type you pay when reading a business report, but in both cases it is only warranted when the writer put some thought into it.
Simon also makes an appearance here:
The programmer Simon Willison has described the training for large language models as “money laundering for copyrighted data,” which I find a useful way to think about the appeal of generative-A.I. programs: they let you engage in something like plagiarism, but there’s no guilt associated with it because it’s not clear even to you that you’re copying.
I could quote the whole thing, but I’ll stop with this one:
The task that generative A.I. has been most successful at is lowering our expectations, both of the things we read and of ourselves when we write anything for others to read. It is a fundamentally dehumanizing technology because it treats us as less than what we are: creators and apprehenders of meaning. It reduces the amount of intention in the world.
Benjamín Labatut draws a line from the Vedas to George Boole and Claude Shannon onward to Geoffrey Hinton and Frank Herbert’s Butlerian Jihad.
In the coming years, as people armed with AI continue making the world faster, stranger, and more chaotic, we should do all we can to prevent these systems from giving more and more power to the few who can build them.
David is on board. Who else?