grind-assets
Version:
Asset management for Grind
208 lines (164 loc) • 4.76 kB
JavaScript
;
function _isnil(val) { return val === null || typeof val === 'undefined'; }
function Socket(referenceScript) {
if (!window.WebSocket) {
throw new Error('This browser does not support websockets, live reload will not work.');
}
var listeners = {};
var attempts = 0;
var attemptsReset = null;
var pending = false;
var socket = connect();
var firstConnect = true;
function connect() {
var protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
var socket = new WebSocket("".concat(protocol, "://").concat(window.location.host, "/@assets/socket"));
socket.onopen = function () {
if (attemptsReset) {
clearTimeout(attemptsReset);
}
if (firstConnect && !_isnil(referenceScript) && referenceScript.hasAttribute('data-since')) {
socket.send(JSON.stringify({
type: 'init',
since: Number(referenceScript.getAttribute('data-since'))
}));
}
attemptsReset = setTimeout(function () {
attempts = 1;
}, 1000);
firstConnect = false;
};
socket.onclose = _reconnect.bind(null, 'close');
socket.onerror = _reconnect.bind(null, 'error');
socket.onmessage = function (message) {
message = JSON.parse(message.data);
{
(listeners[message.type] || []).forEach(function (listener) {
return listener(message.asset, message);
});
}
};
return socket;
}
function _reconnect() {
if (socket.readyState === WebSocket.OPEN) {
return;
}
if (pending) {
return;
} else {
pending = true;
}
var delay = Math.min(30, Math.pow(2, attempts) - 1) * 1000;
if (attemptsReset) {
clearTimeout(attemptsReset);
attemptsReset = null;
}
setTimeout(function () {
attempts++;
pending = false;
socket = connect();
}, delay);
}
return {
on: function (event, callback) {
if (!Array.isArray(listeners[event])) {
listeners[event] = [];
}
listeners[event].push(callback);
}
};
}
function cacheBust(url) {
url = url.replace(/(\?|&)?__ts=\d+/g, '');
if (url.indexOf('?') >= 0) {
url += '&';
} else {
url += '?';
}
return "".concat(url, "__ts=").concat(Date.now());
}
function CssReloader(pathname) {
var reload = [];
for (var i = 0, length = document.styleSheets.length; i < length; i++) {
var sheet = document.styleSheets[i];
if (findFiles$1(sheet).indexOf(pathname) === -1) {
continue;
}
reload.push(sheet);
}
var _loop = function (j, length2) {
var link = reload[j].ownerNode;
var replacement = link.cloneNode();
replacement.href = cacheBust(replacement.href);
replacement.addEventListener('load', function () {
link.remove();
}, false);
replacement.addEventListener('error', function () {
replacement.remove();
}, false);
link.parentNode.insertBefore(replacement, link);
};
for (var j = 0, length2 = reload.length; j < length2; j++) {
_loop(j);
}
}
function findFiles$1(stylesheet) {
var rules = stylesheet.cssRules || [];
for (var i = rules.length - 1; i >= 0; i--) {
var rule = rules[i];
if (rule.selectorText !== '#__liveReloadModule') {
continue;
}
return JSON.parse(JSON.parse(rule.style.content));
}
return [];
}
var attributeName = 'data-live-reload-module';
function JsReloader(pathname) {
var scripts = getScripts();
for (var i = 0, length = scripts.length; i < length; i++) {
var script = scripts[i];
var moduleName = script.getAttribute(attributeName);
if (findFiles(moduleName).indexOf(pathname) === -1) {
continue;
}
window.location.reload();
break;
}
}
function findFiles(name) {
return (window.__liveReloadModules || {})[name] || [];
}
function getScripts() {
var results = [];
var scripts = document.getElementsByTagName('script');
for (var i = 0, length = scripts.length; i < length; i++) {
var script = scripts[i];
if (!script.hasAttribute(attributeName)) {
continue;
}
results.push(script);
}
return results;
}
function LiveReloader(context) {
context.socket.on('change', function (pathname) {
if (Object.keys(context.errors).length > 0) {
return window.location.reload();
} else if (/(css|sass|less|stylus|styl)$/i.test(pathname)) {
CssReloader(pathname);
} else if (/(js|jsx)$/i.test(pathname)) {
JsReloader(pathname);
}
});
}
var context = {
errors: {}
};
context.socket = Socket(document.currentScript);
LiveReloader(context);
context.socket.on('error', function (_, error) {
context.errors[error.id] = error;
});
window.$grindAssets = Object.freeze(context);