Archive for the 'General' Category

Redirector

As part of my work, I sometimes I need to redirect links to a local installation of a web app, so I can debug a particular issue.

For example, I might receive an email with a link to https://test.example.com/what/ever?thing=stuff but I want to see what happens with the code running at http://localhost:3000/what/ever?thing=stuff. For a while I’ve been copying the link, pasting it, manually editing it, and carrying on. But I thought there had to be a better way.

It turns out Einar Egilsson’s Redirector extension is a better way. Install it in your browser (Firefox is my daily driver) and add a redirect like so:

Include Pattern: https://test.example.com/*
Redirect to: http://localhost:3000/$1

So when the redirect is enabled, any links to https://test.example.com will be redirected to localhost:3000. Thank you, Einar!

Google Fonts vs GDPR

The Bavarian state court in Munich, Germany, on 20 January 2022, decided that using Google fonts in your site breaches the GDPR.

Ton Zijlstra (via Adactio)

Paged.JS and CSS Flex / Grid

Paged.JS is a marvel. It’s a Javascript library which helps paginate HTML content, making it suitable for print output. It implements a lot of the CSS Paged Media specifications – so I guess you can think of it as a polyfill. I’ve combined it with Puppeteer to transform a variety of HTML documents into PDFs, complete with repeating headers, footers, footnotes, etc.

It’s amazing, but imperfect. I’ve run into a few issues in the current version (v0.2.0 at the time of writing). My HTML documents make extensive use of CSS flex and grid for layout. For the most part this works fine with Paged.JS, except at the borders between pages. For example, I can use break-inside: avoid to avoid page breaks from happening inside an element:

@media print {
  .block {
    break-inside: avoid;
  }
}

However, if that element happens to be either a flex parent (it has display: flex;) or a flex item (it’s a direct child of a flex parent), the break-inside property is either ignored, or causes other “interesting” issues. Improvements are on the roadmap, but in the meantime we need a workaround. It’s not ideal, but the most reliable way I’ve found is to fall back to older layout techniques, like block, inline-block or float:

@media print {
  .block {
    display: block;
    break-inside: avoid;
  }
}

They’re obviously not quite as flexible, but they work!

It’d be really nice if the various browser engines out there implemented more of the Paged Media specifications natively. As much as I love Paged.JS, I’d love to be able to remove it. Maybe one day…

When Flow typing didn’t quite work properly (and it was all my own fault)

I’m working on a Javascript and React application, which uses Flow to enforce types. For the most part, I love working with Flow, but it hadn’t been working properly for a while.

My IDEs (both Webstorm and VSCode) both reported type errors correctly, but running flow check at the command line (or on CircleCI) always returned No errors! Great, except there were errors lurking in there – loads more than Webstorm was finding!

It turned out to be because I had this line in my .flowconfig:

[options]
module.system.node.resolve_dirname=src

That was there so I could use absolute imports (meaning I could type import Foo from "utils/bar"; instead of import Foo from "../../../../../../../../utils/bar";). Unfortunately that turned out to a broken config, which masked a hell of a lot of problems! Luckily I wasn’t the first person to run into this. The correct way to do that is:

[options]
module.name_mapper='^utils/\(.*\)$' -> '<PROJECT_ROOT>/src/utils/\1'

And add another module.name_mapper line for each top-level folder under src.

If you’re importing from a file at the top level (e.g. import type { Foo } from "flow-types";) the module.name_mapper will look something like this:

module.name_mapper='^flow-types' -> '<PROJECT_ROOT>/src/flow-types.js'

Unfortunately, when I corrected the problem, it revealed a lot of Flow errors in my codebase. Flow has got a lot more strict since I introduced the problem (and that’s a good thing). Luckily, most of those issues are relatively simple to fix!

What to do when the HTML download attribute is ignored

It turns out web browsers will usually ignore the <a download="filename"> HTML attribute on cross-origin requests.

The answer is for the server to set the HTTP Content-Disposition header in the response:

Content-Disposition: attachment;

This assumes the filename on the server is correct. In my case (for complicated and boring reasons), it is not, so I also need to set a filename in in the Content-Disposition HTTP header, e.g. Content-Disposition: attachment; filename="example.pdf".

In my case, the files are stored on a Google Storage bucket. Their name is not the same as the name the user wants (e.g. the file is called export_yVW4Bg-f63rpZIUiXvWct.pdf but the user wants export_31Jan2022.pdf). So when I create the file, I also need to set the Content-Disposition header accordingly.

This code snippet is part of a Google Cloud Function running on NodeJS, and I’m using the @google-cloud/storage library:

const { Storage } = require("@google-cloud/storage");

// Set the metadata to make the PDF download correctly
const setFileMetadata = async (
  bucketName,
  fileName,
  downloadFileName
) => await storage
      .bucket(bucketName)
      .file(fileName)
      .setMetadata({
        contentDisposition: `attachment; filename="${downloadFileName}"`,
        contentType: contentType,
      });

await setFileMetadata("my-unique-bucket-name", "export_yVW4Bg-f63rpZIUiXvWct.pdf", "export_31Jan2022.pdf");

Google’s engineers have posted a more comprehensive code sample, showing how you can also set other headers (e.g. cache-control) and metadata on the file.

The 1996 GT LTS-3

I had one of those, in black! It was rad. Also terrible and squeaky. But mostly rad.

Electric milk floats

When I was a kid, we had milk delivered to our door every day. There’s plenty to be said about that, but today’s point: It was delivered by an EV, and at the time it was completely normal.

When I was growing up in the 1980s, we had fresh milk delivered to our door every day, by someone driving an EV. At the time that was completely normal. Over time, those EVs just faded away.

The EV design was chosen in part because they’re quiet (especially compared the the diesel and petrol engines of the time) – the milk was being delivered to residential streets in the early hours of the morning.

Unigate Milk Float
Unigate Milk Float by f1jherbert on Flickr.

There’s a lot of buzz around the likes of Amazon and UPS ordering huge numbers of EV delivery vehicles from companies like Rivian and Arrival. These things are super cool and potentially transformative, but the concept isn’t exactly new. Specialist electric vehicles designed for short hop (or last mile) deliveries in towns and cities have existed for nearly a century. It turns out Wales and Edwards started making these things in the early 1950s, and Morrison-Electricar were building them as far back as the 1930s.

We just forgot about them for a while.

Making it harder to screw up

Chris Coyier’s Make it hard to screw up driven development struck a chord with me. If there’s ever going to be more than one of you working on a codebase, having a style guide for your CSS or SASS or Javascript or whatever makes sense. Having it automatically applied when you hit save means you rarely have to worry about adhering to the style – it just happens for you. I’ve yet to have one of these tools break my code, either.

One thing Chris didn’t mention though was running a spellchecker over your code. It may sound completely bananas, but hear me out. Firstly, it’s a code-specific spell checker. Secondly, I’ve worked on projects before where we’ve ended up with 3 different spellings of the word “palette”, because 3 different people assumed they had it right. It also means you’re implicitly being encouraged to give your variables and CSS classes meaningful names, so when you revisit the code in the future it’ll make a bit more sense. We used cSpell to do this, but I’m sure other similar products are available.

These tools don’t just exist in the development tools, either. We have them set up in our CI environment, so you can’t merge a code change unless it passes all of the tests – and the tests include both spell checking and matching the style guide. The system won’t let you screw these particular things up – leaving you free to concentrate on not screwing up the actual logic.

I’m a big fan of working this way, in case it wasn’t obvious.