Time to read
, 2135 words, 3rd grade
Iʼve been refining my coding practices, and Iʼm very happy with how far Iʼve gotten with them. Farther than even I had hoped.
A key goal of my Craft Code efforts is to reduce or eliminate the use of external dependencies in shipped code. The Craft Code site is an example of this. Other than a polyfill or two, it has no client-side dependencies not written by me.
Even I am surprised at how easy this turned out to be.
More than a decade now Iʼve advocated for reducing dependencies in web applications. From 2013 to 2014, I ran 12-week web development boot camps for General Assembly in London, Santa Monica, and Hong Kong. I pushed the learners hard to avoid dependencies whenever possible.
In short: they never met a RubyGem (dependency) that they didnʼt like. They would add gems for anything and everything.
I remember one gem in particular. It did one thing only: it added a single attribute to links. And I remember saying to the learner, “Come on! You couldnʼt add that attribute yourself when you code the link?”
The learnerʼs answer: “But why should I if the gem will do it for me?” That learner went far in web development, Iʼm guessing.
In short, I could not deter them. Why do anything if you can get a dependency to do it for you, am I right? Those folks, if any are still coding, must love the new AI / LLM tools.
Me? I like to code. And I want to know what Iʼm coding.
I have never liked any of the UI component libraries, especially MUI. Itʼs an atrocity. Sorry, but it is. I have another essay in the works to prove it.
True, I used Sass
Stylus and then
PostCSS. But as CSS improved I found that I needed preprocessors less and less (pun
intended). CSS properties made that final. And now with
@supports and more, there is no going back.
Iʼve been a proponent of semantic HTML since, hmm, forever. The late Nineties to be exact. I was riding the XHTML train until WHATWG derailed it with HTML5 … sigh. I still have a bit of PTSD from those battles …
I have always written the most semantically-correct, accessible, and usable code that I could manage. WCAG AAA, baby. Or at least AA. Since 1997!
So HTML, CSS, and JS are no problem. But one thing that working in React, Svelte, SolidJS, etc. has done is to sell me on the component style of developing.
To get the benefits of a component architecture, I did investigate using the TypeScript compiler and JSX alone. No library or framework. But in the end I realized that I was rewriting SolidJS, so why bother?
A year or so ago, I started testing some of the newer frameworks to see if there was anything that I liked. I tried qwik, Marko, Stencil, Lit, and others.
Iʼd already built sites in Svelte and SolidJS and yes, I even tried 11ty but didnʼt care for it. I donʼt even like Markdown that much, although Iʼll use it where it makes sense, generally as MDX.
One framework did catch my eye. Unlike qwik, it didnʼt pollute my code with tons of cruft. Unlike many others, it didnʼt force me to choose the one true way. That framework was Astro with its “islands” architecture.
At this point I had pretty much given up on pure vanilla JS. Too painful, I thought.
So I built a site for my partner in Astro and I used “islands” of SolidJS for the forms. It is a very simple site.
I started with JAMStack served from S3. Then added a couple of Lambda serverless functions to handle the forms. I used SES for the contact form and MailerLite for the newsletter sign up. A bit of API Gateway and Route 53 for routing and we were good to go.
A side note: Wow! AWS is an enormous PITA. So overly-complex! And such terrible documentation! We have since switched to Vercel and I am much, much happier. Bye, Jeff! Hola, Guille!
The new site was very nice. But the inclusion of Solid kept bugging me. Shouldnʼt we be able to make a form using only Web APIs at this point? So I experimented a little.
I discovered that I could get the DOM to do the form validation for me. Better, I could easily intercept the DOM validation. Then I could provide my own using the DOMʼs FormValidity object.
Oh, my! Eight years of React had devastated my once-proficient grasp of user agent fundamentals. How embarrassing! Iʼve been playing catch up for a year or so now.
I wrote my own simple JS script to handle form validation and submission.
Years ago, I was a big fan of Ramda. I added Ramda to my sites first thing, even though it was a large dependency. And this was before tree shaking.
And I never used lenses or, heaven forbid, transducers because hello! Other devs? My coworkers would freak out. And yes, I speak from painful experience. Yet another reason I prefer solo projects: the only limitation is me.
I do favor composition. But it is easy to write simple, curried wrappers for the built-in
methods such as
sort. And I could also add a
Where workable, I write my own utilities leveraging JS methods. But in a composable, pure FP way, naturally. These days I have my own library. I import utility functions as I need them. Itʼs surprising how rarely I do.
You may ask, isnʼt your utility library a dependency?
Yes, it is. But it is my code, same as if it were in the app itself. I am not averse to code re-use. I am averse to depending on other peopleʼs code.
Hereʼs a simple example. Iʼm sure that I can improve it, but thatʼs the fun part. Over time, these utilities will get better and better. And I will control them all and know exactly how they work.
So, no more Ramda for me. But what about React (or Solid) and re-rendering?
The interactivity on most sites comes from one of two activities. The first is form validation/submission. I have already solved this. The second is UI interaction, such as accordions, drawers, etc. I can handle most of this with simple CSS. Maybe a bit of progressive enhancement.
Unless youʼre building complex online apps (e.g., a spreadsheet), what else is there?
The simple truth is that most of the state that we manage on the front end using complex state management libraries is actually server state. We push it all up to the browser because we are running a client-side, typically single-page app. The state we need to maintain on the client is usually minimal. And we can keep it in the DOM itself. No, really.
With CSS pseudo-classes such
:checked, I can do almost
anything I need to do. I add a bit of JS
to smooth things out. Or to remember settings, for which session
storage is wonderful. But everything works without JS. Even the forms.
Ironically, Iʼve now decided that this switch is overkill. It complicates the code unnecessarily. Your system already allows you to switch the site between light and dark mode. Do we really need a switch for this site alone?
But the site owner loves it, so Iʼm having a hard time convincing her to abandon it. Murder your darlings, I guess.
The forms submit to serverless functions. I use one per form. The functions look to see if the submission was via HTTP or AJAX. If the former, it redirects. Yes, this means I need extra pages for each error and for success, but thatʼs no biggie.
DOM methods such as
document.createElement. Easy peasy.
And it all works perfectly! I built Craft Code using this approach.
Oh, but wonʼt that be SLOW?
Um, no. Itʼs rather fast. Click on a few links here if you donʼt believe me. I am building all my websites using this vanilla HTML/CSS/JS approach. I use Astro and TypeScript on the back end, but ship only vanilla code that I wrote by hand.
And not only do these vanilla sites achieve AAA on the WCAG 2.2 guidelines. Note: thatʼs TRIPLE-A, not double. They also score 100% across the board consistently on Lighthouse. Thatʼs 100% on Performance, Accessibility, Best Practices, and SEO. Even on mobile.
I keep trying to improve that, but 100% seems to be some sort of limit.
When people visit these pages they usually remark immediately,
Oh, wow. Thatʼs fast! Iʼve had no complaints about the interface or the forms.
OK, the occasional snarky one about my choices of typefaces and colors.
But hey! Iʼve never pretended to be a graphic designer.
Is it vanilla on the back end, too? I donʼt even know what that would mean, but Iʼm not stupid. I use cloud services for hosting, serverless functions, image manipulation, and more. I like to sit out on the edge, although I do worry about sustainability.
Currently, Iʼm using Vercel for hosting and I am pretty happy with it. Seems they care about sustainability, as do I. Thanks, Guille. Keep up the good work.
I donʼt see any point in loading gobs of extra code written by strangers. People I donʼt know and who donʼt know me. People who have zero stake in my projects. People who may or may not write sustainable, secure, robust code. People who may or may not maintain it.
And why borrow code to do what the browser is already capable of doing? The browser is faster and better. Itʼs native code, after all.
Ergo, I resist adding dependencies unless it is something the browser doesnʼt provide and I cannot do myself.
But donʼt take my word for it. See what the Web Sustainability Guidelines have to say about dependency management.