The Real Fake Cameras Of Toy Story 4

The Nerdwriter on what makes Toy Story 4 feel so authentic.

Handling JavaScript events with Web Workers

Alex MacArthur:

The advantages of Web Workers are many, but things really clicked for me when it came to the several DOM event listeners in any given application. These all necessarily live on the browser’s main thread, and if that thread is congested by a long-running process, the responsiveness of those listeners begins to suffer, stalling the entire application until the event loop is free to continue firing.

Here’s an example (first hit freeze, then try hitting the other button or resizing the textarea):

See the Pen
Event Blocking – No Worker
by Alex MacArthur (@alexmacarthur)
on CodePen.

In his post he lays out a way of offloading that long running task into a Web Worker.

For the Sake of Your Event Listeners, Use Web Workers →

πŸ’β€β™‚οΈ Be sure to check out the mentioned workerize, as that’s easier to grasp when compared to the postMessage code.

let worker = workerize(`
	export function add(a, b) {
		// block for half a second to demonstrate asynchronicity
		let start =;
		while ( < 500);
		return a + b;

(async () => {
	console.log('3 + 9 = ', await worker.add(3, 9));
	console.log('1 + 2 = ', await worker.add(1, 2));

Fullwidth Content Strips and CSS Subgrid = ❀️

When having fullwidth content strips on your site CSS Grid is a thankful piece of technology. You can use it to place items between the first and last grid-line, as detailed in Breaking Elements out of Their Containers in CSS

πŸ’β€β™‚οΈ Alternatively you can also use this .full-bleed utility class

To lay out the content inside those fullwidth strips, with respect to the main grid, CSS Subgrid comes in handy

In this article, we’ll be exploring one specific use case: augmenting a Grid-infused article layout. This article layout will allow for certain sections of content to break out into full-width areas.

.article-body {
    display: grid;
    grid-template-columns: [fullWidth-start] 1rem 
                           [left-start]      1fr 
                           [article-start right-start] minmax(20ch, 80ch) 
                           [article-end left-end] 1fr 
                           [right-end] 1rem [fullWidth-end];

.article-body .full-width {
    display: grid;
    grid-template-columns: subgrid;

.article-body .full-width .right {
    grid-column: right;

With this addition, children of .full-width can target columns of .article-body itself.

Use CSS Subgrid to layout full-width content stripes in an article template →

Getting started with GitHub Actions and Laravel (~PHP)

Ruben Van Assche from Spatie:

When GitHub released its new product: GitHub Actions a whole new world opened for developers. Let’s dive right in and see what it brings for the Laravel community.

In How to set up PHP for use in a GitHub Action I’ve layed out how to use shivammathur/[email protected] in GitHub Actions. This post goes very nicely along with it. Recommended read, even if you don’t write Laravel (like me).

I especially like the part where an extra MySQL service is spun up from within the workflow, and then used in the tests.

// ...

        // ...

                image: mysql:5.7
                    MYSQL_ALLOW_EMPTY_PASSWORD: yes
                    MYSQL_DATABASE: our-awesome-tested-app
                    - 3306
                options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
        // ...

Getting started with GitHub Actions and Laravel →

Run a PHP app in a Docker Container (Notes)

The past week I took a closer look at the several options on how to run a PHP app with Docker. In the past I’ve ran a few pre-built containers, but now I wanted to truly get to the bottom of it all as I don’t always need a full blown container with all extensions, but want to start from a rather clean base and build upon that. This post mainly functions as a note to my future self and lists projects that I found interesting during my research.

ℹ️ I was only looking to run a PHP app, without any other services (MySQL, Redis, etc) so these are not covered here. If you’re using docker-compose it’s “only” a matter of also adding those and exposing them over the (internal) network.



This one uses docker-compose which starts up a php:fpm container and an nginx container with a network between them. Nginx is configured to pass requests for PHP files to php-fpm. This is how many articles tackle this.



This one also uses php-fpm and Nginx but installs them from scratch and stores them in one single container (e.g. no docker-compose). Processes are controlled using supervisord



Official PHP Image with Apache2 and PHP. Comes with handy utils such as docker-php-ext-configure, docker-php-ext-install, and docker-php-ext-enable. This gist is a good reference to installing many extensions

FROM php:7.4-apache

RUN apt-get update && apt-get install -y \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libpng-dev \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd

RUN apt-get update && apt-get install -y \
        zlib1g-dev \
        libicu-dev \
        g++ \
    && docker-php-ext-configure intl \
    && docker-php-ext-install intl

# …

RUN a2enmod rewrite

Apache Modules are enabled using the common a2enmod. Log and error files are symlinked to /dev/stdout and /dev/stderr



Starts with an alpine image and installs Apache and PHP into them without too much cruft. Also symlinks the log and error files on startup (not from the Dockerfile). Also installs Composer quite cleverly by leveraging its command line options.

RUN curl -sS | php -- \
    --install-dir=/usr/local/bin --filename=composer



Official Composer Image. You can use this container to run composer install in, and then copy its contents into the “main” container:

FROM composer:1.9.1 as composer 

COPY composer.json composer.lock /app/
RUN composer install \
    --ignore-platform-reqs \
    --no-interaction \
    --no-plugins \
    --no-scripts \
    --prefer-dist \
    --optimize-autoloader \

FROM php:7.4-apache

# …

COPY --chown=www-data:www-data --from=composer /app/vendor/ /var/www/vendor/

# …


Did this help you out? Like what you see?
Consider donating.

I don’t run ads on my blog nor do I do this for profit. A donation however would always put a smile on my face though. Thanks!

β˜•οΈ Buy me a Coffee ($3)


Due next summer.

ESNext: Relatively format time with Intl.RelativeTimeFormat

An ECMAScript Language Feature that just moved to Stage-4, and thus will be part of ES2020, is Intl.RelativeTimeFormat. It’s a way to format time in a relative manner – such as β€œ10 minutes ago” or β€œin 3 quarters” – while also keeping a language into account.


πŸ’β€β™‚οΈ The TC39 Committee has a 4 stage process in place, ranging from stage-0 to stage-4, by which it develops a new language feature. Stage-4 is the Finished Phase.

const rtf_en = new Intl.RelativeTimeFormat('en');

console.log(rtf_en.format(-1, 'day')); // ~> 1 day ago
console.log(rtf_en.format(30, 'seconds')); // ~> in 30 seconds
const rtf_nl = new Intl.RelativeTimeFormat('nl-BE', {
    localeMatcher: 'best fit', // other values: 'lookup'
    numeric: 'auto', // other values: 'always'
    style: 'short', // other values: 'long' or 'narrow'

console.log(rtf_nl.format(-1, 'day')); // ~> gisteren
console.log(rtf_nl.format(30, 'seconds')); // ~> over 30 sec.



The constructor takes two arguments: locales and options. Both are optional:

new Intl.RelativeTimeFormat([locales[, options]]);

Possible units to use while formatting are "year", "quarter", "month", "week", "day", "hour", "minute", and "second".


Constructor Arguments


The locales argument is a BCP 47 language tag which identifies the locale to use. The main parts, amongst others, of a BCP 47 language tag are language, script, and region

  • The language part is a 2/3 character long ISO 639-1 code
  • The (optional) script part is a 4 character long ISO 15924 code
  • The (optional) region part is a 2 alpha or 3 digit long ISO 3166-1 code

When more than one part is present, they are separated by a dash (-)


  • "nl": Dutch (language).
  • "nl-BE": Dutch as used in Belgium (language + region).
  • "zh-Hans-CN": Chinese written in simplified characters as used in China (language + script + region).

When locale is omitted, it will default to the language-setting of the browser/system.


The options object allows you to tweak how Intl.RelativeTimeFormat behaves. It has the following properties:

  • localeMatcher

    The locale matching algorithm to use. Possible values are "lookup" and "best fit" (default)

  • numeric

    The format of output message. Possible values are "always" (always include a number in the output, default) or "auto" (which allows output such as “in 1 day” to be rewritten in the more natural "tomorrow")

  • style

    The length of the output message, e.g. "in 1 month" vs. "in 1 mo.". Possible values are "long" (default), "short", or “narrow” (which mostly yields the same result as "short", depending on the language)


Extracting all parts with formatToParts

If you don’t want a string to be returned, you can use formatToParts() to get an object describing all parts:

const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });

// Format relative time using the day unit.
rtf.formatToParts(-1, "day");
// > [{ type: "literal", value: "yesterday"}]

rtf.formatToParts(100, "day");
// > [{ type: "literal", value: "in " }, { type: "integer", value: "100", unit: "day" }, { type: "literal", value: " days" }]


JS/Browser Support

Intl.RelativeTimeFormat shipped in V8 v7.1.179 (included Chrome 71) and Firefox 65.

Polyfills are available:


Did this help you out? Like what you see?
Consider donating.

I don’t run ads on my blog nor do I do this for profit. A donation however would always put a smile on my face though. Thanks!

β˜•οΈ Buy me a Coffee ($3)