A More General Solution
Javascript alone does not seem to be able to solve this problem. Until browsers add back in the support they used to have for doing this, I don't think there's a perfectly general solution.
While I think my previous Emacs solution is a good one, for people who use text editors that do not have builtin web servers, here's another answer which is a bit broader.
Use inotifywait
Many OSes can setup a program to execute whenever a file is modified without having to poll. There is no one API for all OSes, but Linux's inotify works better than most and is easy to use.
Here is a shell script which, when run in the directory where your HTML and CSS files are, will tell Firefox to reload whenever changes are saved. You could also call it with specific filenames if you want it to only watch a few files.
#!/bin/bash
# htmlreload
# When an HTML or CSS file changes, reload any visible browser windows.
# Usage:
#
# htmlreload [ --browsername ] [ files ... ]
#
# If no files to watch are specified, all files (recursively) in the
# current working directory are monitored. (Note: this can take a long
# time to initially setup if you have a lot of files).
#
# An argument that begins with a dash is the browser to control.
# `htmlreload --chrom` will match both Chromium and Chrome.
set -o errexit
set -o nounset
browser="firefox" # Default browser name. (Technically "X11 Class")
keystroke="CTRL+F5" # The key that tells the browser to reload.
sendkey() {
# Given an application name and a keystroke,
# type the key in all windows owned by that application.
xdotool search --all --onlyvisible --class "$1" \
key --window %@ "$2"
}
# You may specify the browser name after one or more dashes (e.g., --chromium)
if [[ "${1:-}" == -* ]]; then
browser="${1##*-}"
shift
fi
# If no filenames given to watch, watch current working directory.
if [[ $# -eq 0 ]]; then
echo "Watching all files under `pwd`"
set - --recursive "`pwd`" #Added quotes for whitespace in path
fi
inotifywait --monitor --event CLOSE_WRITE "$@" | while read; do
#echo "$REPLY"
sendkey $browser $keystroke
done
Prerequisites: inotifywait and xdotool
You'll need inotifywait
and xdotool
installed for this to work. On Debian GNU/Linux (and descendants, such as Ubuntu and Mint) you can get those programs using a single command:
sudo apt install inotify-tools xdotool
Optional: Working with Chromium
I suggest using Firefox due to a strangeness in the way Chromium (and Chrome) handle input in windows that do not have focus. If you absolutely must use Chromium, you can use this sendkey()
routine instead:
sendkeywithfocus() {
# Given an application name and a keystroke, give each window
# focus and type the key in all windows owned by that application.
# This is apparently needed by chromium, but is annoying because
# whatever you're typing in your text editor shortly after saving
# will also go to the chromium window.
# Save previous window id so we can restore focus.
local current_focus="$(xdotool getwindowfocus)"
# For each visible window, focus it and send the keystroke.
xdotool search --all --onlyvisible --class "$1" \
windowfocus \
key --window %@ "$2"
# Restore previous focus.
xdotool windowfocus "$current_focus"
}
Optional: Working in Wayland
I have not tested it out, but read that Wayland now has a program called ydotool
which is a drop in replacement for xdotool
.
flymd
package is a super-interesting pointer, but it works only with Markdown buffers. – Chaingfile:///
protocol. If you are serving them locally onlocalhost
or something it should be fine. – Hagermanfile:///
(haven't tried) but it does work withlocalhost
. – Gaisericflymd
does nothing special. It either just directly dojQuery.get()
(which works on Firefox), or pass--allow-file-access-from-files
flag to Chrome. – Thorvald