Skip to content

Instantly share code, notes, and snippets.

@Munawwar
Last active August 12, 2016 11:36
Show Gist options
  • Save Munawwar/29e7c9f9c6613a4f041588cb8808d7c6 to your computer and use it in GitHub Desktop.
Save Munawwar/29e7c9f9c6613a4f041588cb8808d7c6 to your computer and use it in GitHub Desktop.
SystemJS LESS transpiling & caching plugin (uses IndexedDB, which is cleared after each session).
/*global Promise, console*/
/**
* Usage:
* Promise.all([
* System.import('./systemjs-less-cacher.js'),
* System.import('./less.js')
* ]).then(function (values) {
* var lessCacher = values[0],
* less_browser = values[1],
* url = 'localhost/some.less',
* lessCode = 'html {height: 100%}';
* lessCacher(url, lessCode, less_browser, function (err, css) {
* //use css here
* });
* })
*/
module.exports = new Promise(function initialize(resolve) {
var dummy = function (url, less, less_browser, callback) {
callback(null, null);
};
if (!window.indexedDB) {
return resolve(dummy);
}
var db;
var Module = {
_cache: {},
init: function () {
return (new Promise(function (resolve, reject) {
//First time init
if (!window.sessionStorage.getItem('systemjs-less-cacher')) {
// Create an objectStore for this database
var objectStore = db.createObjectStore("less", { keyPath: "key" });
objectStore.transaction.oncomplete = function () {
window.sessionStorage.setItem('systemjs-less-cacher', 'true');
resolve(Module);
};
objectStore.transaction.onerror = function(event) {
console.error(event);
resolve(dummy);
};
} else {
var start = Date.now();
var request = db.transaction(["less"], "readwrite").objectStore("less").get('cache');
request.onerror = function(event) {
reject(event);
};
request.onsuccess = function() {
Module._cache = request.result ? request.result.data : {};
console.log(Date.now() - start);
resolve(Module);
};
}
}));
},
saveTimer: null,
/*Persist cache to db*/
save: function () {
var transaction = db.transaction(["less"], "readwrite");
transaction.objectStore("less").delete('cache');
transaction.objectStore("less").add({key: 'cache', data: Module._cache});
},
/**
* Cache URL's CSS code and LESS code hash.
* @private
*/
setItem: function (url, css, lessHash) {
if (css !== null) {
Module._cache[url] = {
css: css,
lessHash: lessHash
};
} else {
delete Module._cache[url];
}
clearTimeout(Module.saveTimer);
Module.saveTimer = setTimeout(Module.save, 1000);
},
/**
* Get URL's cached CSS and LESS code hash.
* @private
*/
getItem: function (url) {
if (url in Module._cache) {
return Module._cache[url];
} else {
return null;
}
},
/*FNV-1 hash algorithm from https://gist.github.com/vaiorabbit/5657561. It gives very less collisions.*/
hash: function fnv32(str) {
var FNV1_32A_INIT = 0x811c9dc5;
var hval = FNV1_32A_INIT;
for ( var i = 0; i < str.length; ++i ) {
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
hval ^= str.charCodeAt(i);
}
return hval >>> 0;
},
/**
* @param {String} url URL to less file (with the .less extension)
* @param {String} less The less code
*/
cache: function (url, less, less_browser, callback) {
var lessHash = Module.hash(less) + '',
item = Module.getItem(url);
if (item && item.lessHash === lessHash) {
callback(null, item.css);
} else {
//render it using less
less_browser.render(less, {
filename: url,
rootpath: url.replace(/[^\/]*$/, '')
}, function (err, data) {
Module.setItem(url, data.css, lessHash);
callback(null, data.css);
});
}
}
};
(function (callback) {
//Clear db on new session.
if (!window.sessionStorage.getItem('systemjs-less-cacher')) {
var request = window.indexedDB.deleteDatabase('systemjs-less-cacher');
request.onsuccess = callback;
request.onerror = function (event) {
console.error(event.target);
resolve(dummy);
};
} else {
callback();
}
}(function () {
var request = window.indexedDB.open("systemjs-less-cacher", 1);
request.onerror = function (event) {
console.error(event.target);
resolve(dummy);
};
request.onsuccess = function (event) {
if (!db) {
db = event.target.result;
Module.init().then(function (mod) {
resolve(Module.cache);
});
}
};
request.onupgradeneeded = function (event) {
db = event.target.result;
Module.init().then(function (mod) {
resolve(Module.cache);
});
};
}));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment