Commit 0d0d683c authored by Robert Knight's avatar Robert Knight

Remove live-reload functionality from dev server

The client's dev server had functionality where it could live-update the
sidebar app when certain resources (eg. CSS bundles) were changed without
requiring a restart of the app.

None of the developers were using this functionality, and reloading the
app is not especially painful, so remove it to simplify future maintenance.
parent 8aec28d6
......@@ -7,7 +7,6 @@ const path = require('path');
const changed = require('gulp-changed');
const commander = require('commander');
const debounce = require('lodash.debounce');
const log = require('fancy-log');
const gulp = require('gulp');
const replace = require('gulp-replace');
......@@ -25,14 +24,6 @@ const SCRIPT_DIR = 'build/scripts';
const STYLE_DIR = 'build/styles';
const FONTS_DIR = 'build/fonts';
const IMAGES_DIR = 'build/images';
const TEMPLATES_DIR = 'src/sidebar/templates';
// LiveReloadServer instance for sending messages to connected
// development clients
let liveReloadServer;
// List of file paths that changed since the last live-reload
// notification was dispatched
let liveReloadChangedFiles = [];
function parseCommandLine() {
commander
......@@ -234,47 +225,9 @@ gulp.task(
})
);
gulp.task('watch-templates', function() {
gulp.watch(TEMPLATES_DIR + '/*.html', function(file) {
liveReloadServer.notifyChanged([file.path]);
});
});
const MANIFEST_SOURCE_FILES =
'build/@(fonts|images|scripts|styles)/*.@(js|css|woff|jpg|png|svg)';
let prevManifest = {};
/**
* Return an array of asset paths that changed between
* two versions of a manifest.
*/
function changedAssets(prevManifest, newManifest) {
return Object.keys(newManifest).filter(function(asset) {
return newManifest[asset] !== prevManifest[asset];
});
}
const debouncedLiveReload = debounce(function() {
// Notify dev clients about the changed assets. Note: This currently has an
// issue that if CSS, JS and templates are all changed in quick succession,
// some of the assets might be empty/incomplete files that are still being
// generated when this is invoked, causing the reload to fail.
//
// Live reload notifications are debounced to reduce the likelihood of this
// happening.
liveReloadServer.notifyChanged(liveReloadChangedFiles);
liveReloadChangedFiles = [];
}, 250);
function triggerLiveReload(changedFiles) {
if (!liveReloadServer) {
return;
}
liveReloadChangedFiles = liveReloadChangedFiles.concat(changedFiles);
debouncedLiveReload();
}
let isFirstBuild = true;
/**
......@@ -328,11 +281,7 @@ function generateManifest(opts) {
.pipe(manifest({ name: 'manifest.json' }))
.pipe(
through.obj(function(file, enc, callback) {
// Trigger a reload of the client in the dev server at localhost:3000
const newManifest = JSON.parse(file.contents.toString());
const changed = changedAssets(prevManifest, newManifest);
prevManifest = newManifest;
triggerLiveReload(changed);
// Expand template vars in boot script bundle
generateBootScript(newManifest, opts);
......@@ -354,9 +303,9 @@ gulp.task('serve-package', function() {
servePackage(3001);
});
gulp.task('serve-live-reload', function() {
const LiveReloadServer = require('./scripts/gulp/live-reload-server');
liveReloadServer = new LiveReloadServer(3000, {
gulp.task('serve-test-pages', function() {
const DevServer = require('./scripts/gulp/dev-server');
new DevServer(3000, {
// The scheme is omitted here as the client asset server will use the same
// protcol (HTTP or HTTPS) as the test page server.
clientUrl: `//{current_host}:3001/hypothesis`,
......@@ -375,13 +324,12 @@ gulp.task(
'watch',
gulp.parallel(
'serve-package',
'serve-live-reload',
'serve-test-pages',
'watch-js',
'watch-css',
'watch-fonts',
'watch-images',
'watch-manifest',
'watch-templates'
'watch-manifest'
)
);
......
......@@ -109,7 +109,6 @@
"unorm": "^1.3.3",
"vinyl": "^2.2.0",
"watchify": "^3.7.0",
"websocket": "^1.0.22",
"whatwg-fetch": "^3.0.0",
"wicked-good-xpath": "^1.3.0",
"wrap-text": "^1.0.7",
......
......@@ -2,7 +2,6 @@
const fs = require('fs');
const log = require('fancy-log');
const WebSocketServer = require('websocket').server;
const urlParser = require('url');
const { createServer, useSsl } = require('./create-server');
......@@ -25,21 +24,14 @@ function codeOfConductText() {
*/
/**
* An HTTP and WebSocket server which enables live reloading of the client.
*
* A simple HTTP and WebSocket server
* which serves a test page with the Hypothesis client embedded
* and notifies connected clients when assets are modified, enabling
* the client to live-reload.
* An HTTP server which serves a test page with the development client embedded.
*
* @param {number} port - The port that the test server should listen on.
* @param {Config} config - Config for the server
*
* @constructor
*/
function LiveReloadServer(port, config) {
let connections = [];
function DevServer(port, config) {
function listen() {
const app = function(req, response) {
const url = urlParser.parse(req.url);
......@@ -95,7 +87,6 @@ function LiveReloadServer(port, config) {
window.hypothesisConfig = function () {
return {
liveReloadServer: 'ws://' + appHost + ':${port}',
// Force into focused user mode
// Example focused user mode
......@@ -112,12 +103,6 @@ function LiveReloadServer(port, config) {
};
};
window.addEventListener('message', function (event) {
if (event.data.type && event.data.type === 'reloadrequest') {
window.location.reload();
}
});
var embedScript = document.createElement('script');
embedScript.src = '${
config.clientUrl
......@@ -153,49 +138,14 @@ function LiveReloadServer(port, config) {
const server = createServer(app);
server.listen(port, function(err) {
if (err) {
log('Setting up live reload server failed', err);
log('Setting up dev server failed', err);
}
const scheme = useSsl ? 'https' : 'http';
log(`Live reload server listening at ${scheme}://localhost:${port}/`);
});
const ws = new WebSocketServer({
httpServer: server,
});
ws.on('request', function(req) {
log('Live reload client connected');
const conn = req.accept(null, req.origin);
connections.push(conn);
conn.on('close', function() {
const closedConn = conn;
connections = connections.filter(function(conn) {
return conn !== closedConn;
});
});
log(`Dev server listening at ${scheme}://localhost:${port}/`);
});
}
/**
* Notify connected clients about assets that changed.
*
* @param {Array<string>} assets - A list of paths of assets that changed.
* Paths are relative to the root asset
* build directory.
*/
this.notifyChanged = function(assets) {
connections.forEach(function(conn) {
conn.sendUTF(
JSON.stringify({
type: 'assets-changed',
changed: assets,
})
);
});
};
listen();
}
module.exports = LiveReloadServer;
module.exports = DevServer;
......@@ -336,10 +336,6 @@ function startAngularApp(config) {
.run(setupApi)
.run(crossOriginRPC.server.start);
if (config.liveReloadServer) {
require('./live-reload-client').connect(config.liveReloadServer);
}
// Work around a check in Angular's $sniffer service that causes it to
// incorrectly determine that Firefox extensions are Chrome Packaged Apps which
// do not support the HTML 5 History API. This results Angular redirecting the
......
/* eslint no-console: "off" */
import * as queryString from 'query-string';
import Socket from './websocket';
/**
* Return a URL with a cache-busting query string parameter added.
*
* @param {string} url - The original asset URL
* @return {string} The URL with a cache-buster added.
*/
function cacheBustURL(url) {
let newUrl = url;
const cacheBuster = queryString.parse({ timestamp: Date.now() });
if (url.indexOf('?') !== -1) {
newUrl += '&' + cacheBuster;
} else {
newUrl += '?' + cacheBuster;
}
return newUrl;
}
/**
* Return true if a URL matches a list of paths of modified assets.
*
* @param {string} url - The URL of the stylesheet, script or other resource.
* @param {Array<string>} changed - List of paths of modified assets.
*/
function didAssetChange(url, changed) {
return changed.some(function(path) {
return url.indexOf(path) !== -1;
});
}
/**
* Reload a stylesheet or media element if it references a file
* in a list of changed assets.
*
* @param {Element} element - An HTML <link> tag or media element.
* @param {Array<string>} changed - List of paths of modified assets.
*/
function maybeReloadElement(element, changed) {
const parentElement = element.parentNode;
const newElement = element.cloneNode();
const srcKeys = ['href', 'src'];
srcKeys.forEach(function(key) {
if (key in element && didAssetChange(element[key], changed)) {
newElement[key] = cacheBustURL(element[key]);
}
});
parentElement.replaceChild(newElement, element);
}
function reloadExternalStyleSheets(changed) {
const linkTags = [].slice.apply(document.querySelectorAll('link'));
linkTags.forEach(function(tag) {
maybeReloadElement(tag, changed);
});
}
/**
* Connect to the live-reload server at @p url.
*
* @param {string} url - The URL of the live reload server. If undefined,
* the 'livereloadserver' query string parameter is
* used.
*/
export function connect(url) {
const conn = new Socket(url);
conn.on('open', function() {
console.log('Live reload client listening');
});
conn.on('message', function(event) {
const message = JSON.parse(event.data);
if (message.type === 'assets-changed') {
const scriptsOrTemplatesChanged = message.changed.some(function(path) {
return path.match(/\.(html|js)$/);
});
const stylesChanged = message.changed.some(function(path) {
return path.match(/\.css$/);
});
if (scriptsOrTemplatesChanged) {
// Ask the host page to reload the client (eg. by reloading itself).
window.top.postMessage({ type: 'reloadrequest' }, '*');
return;
}
if (stylesChanged) {
reloadExternalStyleSheets(message.changed);
}
}
});
conn.on('error', function(err) {
console.error('Error connecting to live reload server:', err);
});
}
......@@ -4805,7 +4805,7 @@ is-symbol@^1.0.2:
dependencies:
has-symbols "^1.0.0"
is-typedarray@^1.0.0, is-typedarray@~1.0.0:
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
......@@ -5692,7 +5692,7 @@ mute-stream@0.0.8:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
nan@^2.12.1, nan@^2.14.0:
nan@^2.12.1:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
......@@ -8135,13 +8135,6 @@ type@^1.0.1:
resolved "https://registry.yarnpkg.com/type/-/type-1.0.1.tgz#084c9a17fcc9151a2cdb1459905c2e45e4bb7d61"
integrity sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw==
typedarray-to-buffer@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
dependencies:
is-typedarray "^1.0.0"
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
......@@ -8487,17 +8480,6 @@ webidl-conversions@^4.0.2:
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
websocket@^1.0.22:
version "1.0.31"
resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.31.tgz#e5d0f16c3340ed87670e489ecae6144c79358730"
integrity sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ==
dependencies:
debug "^2.2.0"
es5-ext "^0.10.50"
nan "^2.14.0"
typedarray-to-buffer "^3.1.5"
yaeti "^0.0.6"
whatwg-fetch@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
......@@ -8667,11 +8649,6 @@ y18n@^4.0.0:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
yaeti@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577"
integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=
yallist@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment