230mb Dependencies for a Simple Website!?

I recently started this blog to have a place where I can publish my projects and my CV. It is a simple website, and since I will be the only author, I wanted it to be as simple as possible. I tried to not reinvent the wheel here, because this website was in planning- and development hell for over a year.

I am pretty happy with the result. The blog looks and feels like I intended, but as you read the title, I am flabbergasted about the JavaScript footprint of the website.

Disclaimer

I am surely biased on npm and JavaScript. I am sure I am doing some things wrong here, and there would be a better solution. But: I always think, simple things should be simple, and being wasteful with resources and dependencies, always catches up to you. More moving parts, mean more potential problems.

Initial Implementation

So what did I want to archive here? I wanted a website that:

  1. Is static (no CMS, no scripting language, or active component on the server)
  2. Can be authored using a text editor, git, and rsync
  3. Has a light- and dark theme

The Backend

Since I knew from the start, I want to use a static site generator, and I am the original author of Flamingo, it would have made sense to just use this existing tool, but I saw the opportunity to procrastinate and throw over the launch schedule of this website in on go, by creating a new static site generator from scratch: LimePress (it's always a good idea to create new tools first, for projects with deadlines).

Don't get me wrong: Flamingo is one of my most successful projects, and I use it, to generate the documentation of Lona, to this day. I started the development of Flamingo in 2017, so six years ago. When I started, I knew very little about the problem that a static site generator solves. It grew fast into a very stable, and feature-rich tool, but as of today, I am not so happy with some of the design decisions, I made on the way.

I always wanted to build a much simpler tool, but the only application for a static site generator that I had was lona-web.org. Since lona-web.org uses pretty much all features of Flamingo, and is critical infrastructure for the Lona project, the transition would have been long and painful, using a new and unfinished tool. So I waited for a smaller project, that needs fewer features: This blog!

We are already off to a good start here. I already reinvented the wheel on the first tool to use, and I did not even mention something like the design or the frontend yet. But don't worry, it gets worse in the end ;)

The Frontend

For the frontend, I chose to use Bootstrap5 using TypeScript and Sass. As mentioned before, I wanted to offer a light- and a dark theme. I have problems with night blindness, so I prefer light theme pretty much everywhere, but I know, most people don't.

The theme switch, at the top, created the first challenge for the project: I wanted a smooth transition from light to dark, when the switch is clicked, so I couldn't just generate a light and dark version of every page, and just link them together, because then, a click would have been like the flip of a light switch.

Light- and dark theme are implemented using a special CSS class that is attached to the body element of the page, which gets toggled when the switch is clicked. This is done using Typescript and a CSS transition, on startup.

This solves the light-switch-problem, but creates a new one: When a link is clicked, the page gets reloaded, and the setup-code, which checks which theme is selected, runs again. This means if you select the dark theme and click a link, the page flashes the light theme for a split second, which is pretty annoying.

To fix this, I use Swup. Swup only refreshes the parts of the page, that actually have to change, when a link is clicked. That means the initial setup, for the theme, runs only on the first click on the page, rather than on every click. Also: The page feels pretty smooth like this, which is a nice bonus :)

The Actual Problem

So everything worked, the website looked nice and felt smooth, and I released only a year late \o/. Happy ending right? Kind of.

While writing a long blog-post, I realized it would be nice to have anchor links, behind headlines, to link to. HTML anchors didn't work as I wanted with Swup, but Swup actually has a plugin that implements anchor links. Unfortunately, the plugin was not compatible with the fairly old Swup version I used, because I chose the version when the project started.

We now have reached the rant part of this post. My frustration started when I tried to upgrade Swup to a suitable version for the Swup plugin. To me, npm is not very intuitive, and I don't use it that often. What I wanted was something like pip's "pip install --upgrade", which does exactly what it says: It upgrades previously installed packages to the latest release.

I did not research this very deeply, and gave up after like five tries, with command lines, I googled together; and failed. I ended up googling the latest version of Swup, and installing it explicitly.

The installation took a long time. A suspiciously long time. Then I noticed this:

Uhm ok!? Seems to be a bit excessive, for what I thought of as very few dependencies.

// package.json { "dependencies": { "@fortawesome/fontawesome-free": "^6.1.1", "@speed-highlight/core": "^1.1.7", "@swup/ga-plugin": "^1.1.0", "bootstrap": "^5.1.3", "http-server": "^14.1.1", "photoswipe": "^5.2.8", "sass": "^1.53.0", "source-code-pro": "^2.38.0", "source-sans": "^3.46.0", "swup": "^2.0.19", "typescript": "^4.7.4" } }

To be fair: Not all of them really have to be accessed by the end-user, and are only used at compile time, but still! I mean look at this: We installed a hand-full of libraries, and the package-lock file contains over 10000 lines. We installed 359 packages.

Then I wondered: Did I do something wrong when updating? How bad was it before? The answer is: It was not great before, and it doubled after the update.

Solution

To be fair: This is no problem-problem. It obviously works, but it is bothering me that a simple website like this, has to have a footprint this big. Also: I noticed that one of the libraries I use, speed-highlight, has a source file for every language it can highlight. Every of these JavaScript files has to be downloaded by the client, which increases the initial loading time.

I know I said I won't reinvent the wheel but I really dislike the approach of Swup, and the few alternatives I researched. Coincidentally, I created something like Swup for a work-related project, a few months ago. It has no dependencies and is around 120 lines long. So I will polish this solution until I can use it for this website.

To solve the highlight problem, I will use pygments, which is a static highlighting tool, that only runs at compile time, and not when visiting the website.