Browsers as build targets
I've been having a great time over at Mastodon. But I do miss the enthusiasm around building for the web, compared to Twitter. There's less talk of doing new powerful, efficient, delightful things with websites. There's a near constant stream of strongly worded discussions around building sites, with lots of people saying we can do without many of the tools involved with building websites. I feel heading in that direction is a bad idea.
Browsers are special
Websites and the browsers that display them are an outlier when you consider the process of making a website vs. basically anything else. Let's say your building...
- ... a computer game. You write some C++/C#/GLSL, and produce an optimised executable and packed binary assets.
- ... a spreadsheet. You write some formulas in cells, and save a binary file that you can send to your colleagues.
- ... a spreadsheet editor. You write some C++/Java, and produce an optimised executable that can open and save spreadsheet files.
- ... a beautiful fantasy image. You sketch in PhotoShop/Krita, and save out a compressed binary file that you can post online.
- ... a sick beat. You scratch around in (Whatever the fuck audio people use), and save out a compressed binary file that can be played by media players.
- ... a movie. You edit together some clips in AfterEffects/DaVinci Resolve/Windows Movie Maker, and produce a compressed binary file that can be played by media players.
- ... a media player. You write some C++/C#, and produce an optimised executable that can play back media files.
- ... a movie streaming service. You write some Rust/ Go /C#, and produce a program that can send compressed binary media files over the internet.
- ... a compiler. You write some Rust, and produce an optimised executable, that when run will allow you to write some Rust, and produce an optimised executable.
- ... an instant messaging platform. You write some Rust/Go /C++, and produce a an optimised executable that can open network sockets and send binary data back and forth.
- ... an operating system. You write some C/Assembly, and produce an optimised image that can run other programs.
- ... a website. You write some HTML/CSS/JS, and send this loose bunch of plain text files over the network to be interpreted by a web browser. Wait a sec, what the fuck?
How did we get here? Well obviously we started with just HTML. Compilers were slow as shit in those days (for example, writing shorter variable names had considerable impact on compile speed), and it's really just a bunch of markup (read: mostly text with some light structuring), so things are fine as they are. There's not going to be much of an advantage to sticking a build step in here somewhere. You write your page and that exact file will get sent over the network to be displayed.
Then we add CSS. No biggie, we just do another request or two and style the markup we have on the page. Users are already comfortable writing and shipping their HTML exactly as is, so adding a little more plain text for CSS is the easiest way forward.
Then we add JS. No biggie, we just do another request or two and interpret the script we get. Users are already comfortable writing and shipping their HTML/CSS exactly as is, so adding a little more plain text for JS is the easiest way forward.
Now we've arrived at today. Oh no.
Suddenly, everything
So it turns out having a medium that's a mix of linked documents with interactivity sprinkled on top is a really useful and powerful thing. The web has become an important part of modern life. Social media, online shopping, job seeking, property hunting, all of it delivered through a common interface. Seriously, could you imagine having to download an app to do online shopping, then needing to switch to a different app when you go to a different store? Absolute madness.
Backwards compatibility is important, as often once a site is built it will stay that way for a long time. Browsers are amazingly backwards compatible, with ancient websites loading just fine. Even websites that have glaring errors like missing closing tags, will work fine because browsers are built to be tolerant of terrible inputs.
We don't need no tools!
Things used to be bad. Basically everyone needed jQuery to make building interactive UIs while staying sane. Otherwise you'd have to use terrible APIs while working around different browser behaviours. But browsers have now put a lot of effort into standardisation, which is great!
In fact it's so good now, that a lot of people suggest building websites without using any tools. Many curse the modern web frameworks saying they're unecessary. They suggest things like:
- You don't need a bundler, because ESM and HTTP2 solves the hundreds of requests problem, and gzip removes the need for minification.
- You don't need TypeScript, just write JS! (Always bet on JS!)
- You don't need a framework, you can just use WebComponents.
...along with a general attitude of "I should be able to right click inspect your site and be able to reverse engineer how you did something. That's how I learnt web dev, and more people should learn this way!"
Tools are good actually
Sometimes I feel the people from the previous section need to spend some time with compiled languages. The idea that you should be able to reasonably inspect all webpages is nonsense to me. Most people do not learn web development by inspecting other sites. They do university courses, or watch talks on YouTube, or read things on MDN. Nobody (barring extremely nerdy outliers) reverse engineer executables to figure out how something was acheived. You just google it instead. It will be documented somewhere (Usually MDN). Of course I want the debug friendly version of the code when I'm developing. But as soon as I'm ready to push to prod? Get the compiler to do it's magic.
Treeshaking feels like an absolute must when dealing with big
libraries like three.js.
The browser isn't going to know what code it needs and what code it
doesn't. It's just going to see a big pile of import * as Stuff from "...";
statements at the top of each JS file, and it'll download all
of it. Bundlers can walk through the code you wrote, and only include
the bits of the library you actually need. Additionally things like constant
folding can strip this down even further. Could you imagine trying to
do constant folding manually? Please no.
TypeScript is worth it for the autocomplete alone. Being able to get
a list of properties on something by doing 'Ctrl+Space' is so much
faster than doing a console.log
everytime I'm interacting
with an object. But it's the bug prevention that makes it truly shine.
I'll often take old JS code and convert it to TS, and come to the conclusion
of "How did this ever work!?" (Spoiler, it didn't. The slightest unforseen
circumstance would make it explode). Yeah you have to type a few more
characters, but I sleep easier knowing that it won't randomly detonate
in prod. At this point it even looks like JS is betting on TS
, rather than the other way around.
People like to mock frameworks for changing every few years, but this is often because new (simpler, faster, etc.) ways of doing things are discovered and implemented. Things like WebComponents are something that seem to complicate the platform more than elevating it . Then suddenly people wonder why there is such a browser monopoly going on. Hmm, I wonder why? 🤔
Which I feel starts getting to the core of my issue with a lot of
the "anti-framework" crowd. To quote Sam Selikoff:
HTML gives users two interactions: links and forms. If
you want your users to be able to do anything other than
click a link and then navigate, or submit a form and
then navigate, you need JavaScript.
Every site I've worked on has required stuff that isn't links and forms.
But writing WebComponents looks hideously verbose and error prone, it
looks like I'm using jQuery again. I don't want to write user interfaces
imperatively. I've done that, it sucked hard. Building user interfaces
declaratively
has made my life so much easier.
And so we reach the critical point, which is browsers should be the target platform and not the all encompassing solution . Frameworks will always be able to move faster than any new browser standard. Just look at all the craziness going on with Qwik . Browsers should be providing low level controls to enable new functionality (E.g. WebGL, WebSockets, Web Workers), not adding higher and higher levels of abstraction for things we can already do. Especially when the frameworks produce better results than the "built-in" stuff. That's why I cannot understand people who suggest that frameworks are bad.
Write once, unlimited flexibility, infinite power
Frameworks are exceptionally powerful and flexible tools. It's actually fun to build websites now. Being able to compose complicated logic server side, client side, build time, or anywhere in-between using the same code is incredible. For the first time in a long time, I'm actually excited to build for the web, and I'm optimistic about where things are going.