Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a local HTML page auto-refresh on file change?

I view local HTML files in my default browser via the file:// protocol.

I would like to add some code/script to the HTML file, so that on change of the file (and ideally on change of the sucked-in CSS files) the browser refreshes the page.

I tried including Live.js via

<script type="text/javascript" src="http://livejs.com/live.js"></script>

but it does not seem to have any effect for files accessed via file://. - Any solution known which works here?

PS 1: I found another question relating to this problem, but it does not address the local file case.

PS 2: I know I can reload the page periodically via

<meta http-equiv="refresh" content="1">

but that is not what I need; I need reload on change.

like image 886
halloleo Avatar asked Feb 19 '18 02:02

halloleo


2 Answers

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.

like image 125
hackerb9 Avatar answered Oct 18 '22 00:10

hackerb9


Browsers restrict access to the file:/// protocol for security reasons. In Firefox, even extensions no longer have access to local files, so you will most likely have to serve the files locally in order to use a live reload script. If you do that you could just use Live.js, but something like this might be slightly simpler to set up. (Requires Node.js)

like image 38
Herohtar Avatar answered Oct 18 '22 00:10

Herohtar