Live updates during PHP dev - without React or Watchify

Recently I decided to go back to basics and rewrite my site and blog in as minimal format as possible. No libraries or frameworks, no database, all hand coded, fast loading and clean etc. However, one of the things I really missed from developing with stuff like React was being able to see changes on screen as and when you make them.

For those who haven't used React or watchify, its quite cool, as they detect when source files are updated, recompile the whole site, and present it to the browser automatically.

I wanted that too, instant feedback on my design etc, and I realised it could be done very simply using PHP and vanilla javascript.

First I created a very tiny php service which outputs the timestamp of the last file edited on the project. You could make it output in a proper format (e.g. json), but since this is only for my private dev environment, just the number will do.

<?php
$whitelist = array('127.0.0.1', "::1");

if(!in_array($_SERVER['REMOTE_ADDR'], $whitelist)){
    die();
}

$files = scandir(__DIR__ . '/..');
$max = 0;
foreach($files as $file) {
    $fn = __DIR__ . '/../' . $file;
    $max = max($max, filemtime($fn ));
}
echo $max;

Note that I have an ip whitelist to make sure that even if I accidentally upload this script to my production server it will not work. Even if it worked, I don't think that anyone could do anything particularly nasty with it.

The other note is that scandir works on files and directories and that I am scanning the parent directory. This is because my source files exist outside the public html folder. (In fact they are not on the server at all, but just on my local environment, which is where this script would run)

Next I create a javascript snippet, which I output (conditionally on ip being in whitelist) to the footer template of my site

function updateChecker() {
    let lastUpdateTime = null;
    const xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState === XMLHttpRequest.DONE) {
            if (!lastUpdateTime) {
                lastUpdateTime = xmlhttp.response;
            } else if (xmlhttp.response > lastUpdateTime) {
                location.reload();
                return;
            }
            setTimeout(performCheck,1000);
        }
    };

    function performCheck() {
        xmlhttp.open("GET", "/filesupdated.php", true);
        xmlhttp.send();
    }
    performCheck();
}
updateChecker();

Basically when the site loads, it stores the number from the tiny PHP service, and then checks every second to see if it has changed. If it has gone up, it reloads the site.

On my actual development environment, I have actually got this running an update script which updates all my blog articles too.

Editing articles is now a case of writing markdown, and hitting :w (save) and seeing the changes live on the development server - and that for some reason is way more fun than Wordpress!

It's not quite perfect, as for instance, if I have made errors in my php, it will not report them. I could show these in the alert, but I found just outputting the build time was enough to show me that something funny had gone on, which I did by calling the following snippet:

function addLastUpdatedTimeElement (unix_timestamp) {
    const date = new Date(unix_timestamp * 1000);
    const hours = date.getHours();
    const minutes = "0" + date.getMinutes();
    const seconds = "0" + date.getSeconds();
    const formattedTime = hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);

    const newDiv = document.createElement("div");
    newDiv.style.position = 'fixed';
    newDiv.style.top = 0;
    const newContent = document.createTextNode("Last update: " + formattedTime);
    newDiv.appendChild(newContent);
    document.body.appendChild(newDiv);
}

On a later post I will go over some other features and decisions I made for my site's development, so if you are interested, stay tuned.