I’ve been experimenting this week with moving my Astro.build powered blog onto a new tech stack. Why? I have no good reason, I just like to learn things and bang my head on my desk for some reason 🥴 In case you haven’t figured it out yet, I am not a professional web developer.
I’m planning on putting together a shortlist of tech I looked into as a separate post, but only once I’ve landed on one that works. I’m currently still struggling to get web component ”slots” to style correctly across the 3 major browsers. You may notice that in my video below.
For now I’m playing in Greenwood, I was hell bent on not using any JS Frameworks because it’s just a very simple blog and shouldn’t require much of anything more than HTML and CSS. I’ll talk more about my Greenwood experience in a follow up.
While bashing my head into the desk I found myself frustrated with the corner I had painted myself into. I wanted a static site, but that meant I had to go through the build/serve/reload cycle. I even tweeted at the project for help (I don’t 🕊).
In the mean time, I tried to get hot reloading working in their static site generator, but a couple of issues popped up.
- ⛔️ Their dev server doesn’t kick off a static site rebuild, resulting in none of my web components being rendered. It works fine if you’re not prerendering your pages though. I think that might have something to do with where it’s watching for changes and serving from. I think it just tries to load stuff from
src
instead of rebuilding intopublic
and reserving. - ⛔️ Their production serve command seems to have intentions of supporting both dynamic routes and static sites but it doesn’t live reload and kick off a rebuild of the
public
folder either. - ⛔️ reload and live-server both failed me for different reasons, one didn’t like serving index.html from sub-folders. The other I think had an issue with CSS files in my web components changing, but the HTML that linked to them was not regenerating with an updated mapped filename. That is an effect of calling
greenwood build
which the dumb hot loading server had no idea about.
So I just smashed together some shell scripting with some mostly (🤏🍎) cross platform utilities. Since I’m laid up after having back surgery(!) ♿️ and working almost exclusively on my Macbook Pro M1, I threw caution to the wind and created some tech debt for when I return to my Gentoo install next week. More on that later.
Prerequisites
- fswatch - Cross platform watch, I forget why
watch
didn’t work out, but it didn’t… I think it didn’t support recursion 🤔
My servehot
script
#!/bin/sh
# method to kill and start the server
restart_server() {
# read server PID from disk
SERVER_PID=$( cat /tmp/greenwood.pid )
if [[ -n $SERVER_PID ]]; then
# when a change occurs kill the old server
echo "Killing process $SERVER_PID"
kill -9 $SERVER_PID
fi
echo "CTRL-C to exit"
node_modules/.bin/greenwood serve & # run the server in the background
# write server PID to disk as this function is called from a child shell
# and cannot mutate the environment of the callee (fswatch)
echo $! > /tmp/greenwood.pid
# (MacOS ONLY) refresh the browsers
sleep 2
osascript bin/refresh_browsers.scpt
}
# make the function visible to child processes
export -f restart_server
# ignore orphans
rm /tmp/greenwood.pid
# bootstrap
restart_server
# watch for changes in the src directory and execute restart as a child process
fswatch -r -o src | xargs -n1 -I{} sh -c "restart_server"
All we do here, in plain old sh
, is make a restart_server
function that can be called like a program.
Its job is to…
- Kill any
greenwood
PID still alive - Call
greewood serve
again in the background. - Stash the PID of that command on disk* for use the next time.
* This has to be to disk because of the nature of child processes and their lack of access to parent environments.
Any changes to my source trigger a build via fswatch
, which is running recursively (-r
) on my src
directory, grouping all events that may land simultaneously as one (-o
) event and piping that event to xargs
. xargs
receives the one argument, does nothing with it (-I{}
) and executes the restart_server
function in a new shell sh -c
.
MacOS browser refresh
For good convenience I wanted all of my open browsers to refresh when I made changes so I didn’t have to manually cycle through each pressing ⌘-R. I mean, I was already burning enough calories laying around here in bed all week as it was… 🤡
activate application "Firefox"
tell application "System Events" to keystroke "r" using command down
activate application "Google Chrome"
tell application "System Events" to keystroke "r" using command down
activate application "Safari"
tell application "System Events" to keystroke "r" using command down
I had to of course give Script Editor and WezTerm Accessibility Privileges to run the script from my terminal.
System Preferences > Security & Privacy > Accessibility > [+]
I’m peripherally aware of there being really fancy ways to do this, probably streamlined, even just websites that will help you test across browsers, but for local development in this moment, I’m satisfied with my approach. I’ll learn that stuff another day.