Towards Offline First

Evidentia can now be installed as an app on your phone or computer. Once installed, it works offline - no internet required.

This felt like the right next step. The whole point of learning about reasoning is to have it available no matter what's going on around you, you shouldn't need to be sitting at a desk with good wifi. It is more often in a conversation, on a train, or lying awake at 2am wondering why that argument earlier felt wrong.

Progressive Web Apps Are Cool and We Should Talk About Them More

On your phone, visit the site and look for "Add to Home Screen" in your browser menu. On desktop Chrome or Edge, there is a small install icon in the address bar. After that, it behaves a little like any other app.

The Technical Decisions

Making this work required a little bit of work and a pretty big tradeoff.

Before, every page on Cloudflare was shipping the entire curriculum (about 1MB) on first click. This is where caching makes it less visible what's going on: your browser would get the large curriculum.json and then have it until the cache expired it. This is a terrible implementation but it's not far from something that could be neat. If all pages used this, we could get instantaneous page loads. Essentially the entire site could be cached on first click. I would just need to ensure it was on a separate resource explicitly.

But this is where I realized this was fighting Next.js. It killed build times as I increased the number of entries. 5 minutes is not a lot for an enterprise application build, but for a small project like this, it makes what's supposed to be very enjoyable a little less enjoyable.

And if you do the math with our recently added entries, entry pages went from 2.3MB to 44KB that would balloon to 3 or 4 GB total on Cloudflare to build and serve the site by the end of the project. No build system should take longer with each new entry, even if it means that successive clicks theoretically had to fetch different data.

I was at work, at this point I'd benchmark it and put these assumptions to the test: let's see how lighthouse scores are, let's see aggregate data fetched after visiting 10 pages. But there was something else that made me decide before I had to, there was this subtle bug where the page would stutter just a little bit every once in a while when prefetching the next collection. Could this be the reason? That's what drove my decision.

I created a minimal manifest - just lesson IDs and which fallacies belong to each - that handles the same logic in about 2KB. So it is a genuine tradeoff. Now, you don't get the full curriculum, just the lessons you've visited. Which means you can't browse the whole thing offline anymore automatically. I have to build that back in. But this time, it's going to be explicit not implicit.

What Works Now

If you browse through the curriculum while online, those pages become available offline. The search index caches too, so you can look things up without a connection.

The limitation is that you have to visit pages first. If you have never opened a particular fallacy, it will not be there when you go offline.

Monitoring doesn't have to be expensive

[email protected] postbuild
npx pagefind --site out --output-path out/pagefind && echo '
Build size:' && du -sh out/

That's it. My Cloudflare build times were 5 mins and now they're back down to... 2 minutes? That will have to do for remote builds. I also set up Cloudflare wrangler locally so my dev builds can be published to my preview url in just 30 seconds. Much better. I can share with a friend and ask "what do you think of this?" in a snap.

What Comes Next

I am planning a "Download for offline" feature in Settings. Press it once, and the app downloads all 920 pages in the background. After that, the entire curriculum is available anywhere, anytime. The download should be about 3 MB. I know a lot of sites that wouldn't care about this, but I do. I want it to be an explicit download feature that users can choose to use or not.

This is the kind of feature that matters for the long term. Learning happens in small moments throughout the day, not just when conditions are perfect. The tool should be ready when you are. When this is something you always have on you, it becomes a powerful tool for learning and growth.

But this brings up ambiguities to solve for later. What's the TTL? How should we store the data? Better to use localStorage or IndexedDB? Should we store the whole page or just the curriculum file? That would save us ~80MB but might cost a lot in maintenance compared to just letting the browser do its own thing. What about the search index? Should we store it separately or combine it with the curriculum data?

It might sound like the usual overengineering or analysis paralysis, but this tells you something about how being a software engineer tunes into the details. This project is optimizing not just for the learning of the user, but also for my own learning. If I didn't test assumptions, or try to build an accurate model of the landscape, what business would I have building an application precisely about learning, growth, and critical thinking?