Dev.to WebDev 🛠 Dev 👁 0 📖 5 min read

Lessons from building 30 small web tools in a week

A week ago I needed a quick Base64 encoder for a token with emojis in it. The first online tool I tried mangled the output. The second required signup. The third wanted my token uploaded to their server. So I spent a we

A week ago I needed a quick Base64 encoder for a token with emojis in it. The first online tool I tried mangled the output. The second required signup. The third wanted my token uploaded to their server.

So I spent a weekend writing my own, then another six days adding every small tool I wished existed. Along the way I learned a lot about Web APIs that have genuinely improved in the last few years. Sharing what might be useful to other developers.

Why no framework

I know React or Vue would have made some things easier. But for thirty independent tools, server-rendered static HTML is honestly the right fit.

Zero JavaScript to load on first paint. Every page is independently cacheable at the edge. No build step means instant edits. No supply chain risk because there are zero npm packages to audit. And the tools work offline after the first page load.

Would hand-rolled vanilla JavaScript on static HTML beat Next.js for this use case? In my benchmarks, yes. Because there is nothing to hydrate. The browser receives HTML, parses a few hundred lines of CSS, then runs a small page-specific script. That is all.

Base64 and the UTF-8 problem

Most online Base64 encoders mangle emojis and non-Latin characters. The reason is that the built-in btoa function in browsers only accepts characters below code point 256. Anything above, like an emoji or an Urdu letter, throws an error.

The fix is to run the string through a UTF-8 encoder first, convert those bytes to a binary string, then Base64 it. Decoding reverses the process. Two short helpers and the problem is solved for every language and every emoji.

I spent an embarrassing amount of time learning this the hard way. If you are writing any text-handling code in the browser, reach for TextEncoder and TextDecoder first. They quietly fix half of JavaScript's historic string problems.

JSON Web Tokens are surprisingly simple to read

A JWT is three pieces of Base64 separated by dots. The first two pieces are JSON after decoding. The third is a signature, which is just bytes.

To read a token, you decode the first two pieces with Base64 and parse them as JSON. That is the entire decoding process. About ten lines of code.

Verifying the signature is a different story and requires the issuer's secret or public key. That is why any public online decoder should be clearly labeled as reading only, never verifying. Users should not paste real production tokens into anything they do not control.

The Web Crypto API is genuinely good now

For years, developers reached for npm packages for anything cryptographic. That is no longer necessary for most use cases.

SHA-1, SHA-256, and SHA-512 are all one-call operations through the browser's SubtleCrypto API. Both text and files can be hashed. Random bytes for UUIDs, tokens, or session IDs come straight from the operating system's secure random number generator through crypto.getRandomValues.

MD5 is the only common hash missing, because it was deprecated out of SubtleCrypto for security reasons. If you need it for file checksum compatibility, you will have to include a JavaScript implementation. Do not use MD5 for anything security-sensitive.

UUIDs without any library

The v4 UUID specification is about ten lines of code once you have access to a cryptographic random number generator. You pull sixteen random bytes, set a few specific bits to mark the version and variant, then format as hex with dashes. Done.

A library adds nothing except bytes to your page. The browser's built-in random source is the same quality that your operating system uses for its own secure code.

If you need time-sortable UUIDs, version seven is similar in structure but replaces the first few bytes with a millisecond timestamp. That version is becoming the default for new databases because random UUIDs fragment B-tree indexes.

Unix timestamps come in four flavors

Different systems return timestamps in seconds, milliseconds, microseconds, or nanoseconds. A pragmatic auto-detector looks at the digit count. Ten digits is seconds, thirteen is milliseconds, sixteen is microseconds, nineteen is nanoseconds. This heuristic covers almost every real-world case I have seen.

Not exhaustive, but pragmatic. The alternative is forcing users to pick the unit themselves, which they get wrong half the time.

Regex pitfalls are real

While building a regex tester, I rediscovered two classic footguns.

First, patterns with the global flag that can match an empty string will infinite-loop unless you manually advance the last-match position when the match has zero length. The regex engine happily keeps trying the same spot forever otherwise.

Second, greedy quantifiers in nested groups can cause catastrophic backtracking. A pattern like a+ inside parentheses with a plus after the group will explore an exponential number of combinations on a string of many a letters. The browser locks up. Users learn to avoid this the hard way.

Both are fixable once you know they exist. Neither is well documented in most regex tutorials.

The cookie consent banner is thirty lines

Most sites solve consent banners with a fifty-kilobyte third-party library. The entire concept is a div with two buttons, a localStorage key to remember the choice, and a link to the privacy policy. About thirty lines of vanilla JavaScript.

Writing this myself clarified what the regulations actually require: an informed choice stored per user, respected across the session. Nothing more. The third-party libraries ship a lot of code to handle edge cases most sites never hit.

Lessons from seven days

A few things that surprised me.

Writing eight hundred word explanations is harder than writing the tools themselves. A Base64 encoder is thirty lines. A good explainer page covering history, UTF-8 handling, URL-safe variants, and why it is not encryption is a thousand words. The content took longer than the code every single time.

Static HTML on a CDN beats any server setup for this workload. No build step. No hydration cost. No cold starts. Just HTML that renders instantly.

Lighthouse scores improve dramatically when you stop including frameworks you do not need. A page with only inline tool-specific JavaScript and shared CSS scores above ninety-five on performance without any optimization work.

The browser platform in 2026 is genuinely capable of replacing a surprising amount of server-side code for tool-style applications. The APIs are stable, well supported, and documented. If you are building anything that does not require persistent state, consider skipping the backend entirely.

Closing

Nothing here is new. All these APIs have been stable for years. But it was still useful for me to write them down after shipping, because the lessons are easy to forget.

If any of these observations save you an afternoon, I will consider the week well spent.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.