cenko.tech

Redesigning a unit converter with no dependencies

A Node.js unit converter rebuilt with live conversion, shareable links and four new categories. It still has no npm dependencies and works without JavaScript.

unit-converter started as a small Node.js server that converts length, weight and temperature. This pull request gave it a new interface and more to convert, with one rule: no npm dependencies.

What changed#

A carpenter’s-rule look. An ink-coloured shell around a boxwood-yellow working surface, with a tick-mark scale that shows where your answer sits. It is responsive down to phone width.

Live conversion. With JavaScript on, the answer updates as you type. You can swap units, copy the result, and click any unit in the all-units table to make it the target. The scale switches between linear and logarithmic.

Shareable links. Every conversion has a URL:

/length?value=12&from=inch&to=centimeter

Four new categories: area, volume (US customary units), speed and time, joining length, weight and temperature.

It still works without JavaScript. The form posts back to the same page and the server renders the result and the table. I checked this with JavaScript turned off, as well as at desktop and phone widths.

Keeping it dependency-free#

The whole app is server.js (an HTTP server using Node’s built-in modules), converters.js and a few static files (the stylesheet, the browser script and the icon). converters.js holds the unit definitions and conversion logic, and loads both in Node and in the browser. The server and the live page use the same code, so they cannot disagree about an answer.

Tests#

npm test runs plain assert checks. The new categories got their own cases, plus one loop that guards every unit at once:

// every unit has a display symbol, and every category converts to itself unchanged
for (const [key, cat] of Object.entries(categories)) {
  for (const u of Object.keys(cat.units)) {
    assert.ok(cat.symbols[u], `${key}/${u} has a symbol`);
    eq(key, 42, u, u, 42);
  }
}

That loop catches a unit added without a display symbol, and any unit whose definition is broken badly enough that converting it to itself changes the value. The fixed cases above it check the actual factors.

Try it#

It needs Node.js 18 or newer:

npm start

Then open http://localhost:3000.

cd ~/blog