Skip to content

Instantly share code, notes, and snippets.

@atomize
Created April 1, 2019 16:45
Show Gist options
  • Save atomize/5853fa9e5603606fc7830aee74b4e128 to your computer and use it in GitHub Desktop.
Save atomize/5853fa9e5603606fc7830aee74b4e128 to your computer and use it in GitHub Desktop.
Static HTML generator for Prism.js highlighted sites.
const fetch = require('node-fetch');
const fs = require('fs');
const jsdom = require("jsdom");
const {
JSDOM
} = jsdom;
const argv = require('minimist')(process.argv.slice(2))
const options = {
runScripts: "dangerously",
resources: "usable",
}
function injectIIFE(dom) {
let evalFunction = `
let reqNumber = 0;
let doneNumber = 0;
(function bam() {
function SendMessage(e) {
if (window.CustomEvent) {
var event = new CustomEvent("newMessage", {
bubbles: true,
cancelable: true
});
window.dispatchEvent(event);
}
}
var origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function () {
console.log('request started!');
reqNumber++
this.addEventListener('load', function () {
console.log('request completed!');
doneNumber++
if (reqNumber == doneNumber){
SendMessage(document)
console.log('message sent')
}
});
origOpen.apply(this, arguments);
};
})();`
dom.window.eval(evalFunction)
return dom
}
function manipulateDOM(dom) {
dom.window.addEventListener("newMessage", newMessageHandler, false);
function newMessageHandler() {
let sourceArray = []
const fetcher = (eachFile) => {
return fetch(eachFile)
.then(response => {
return response.buffer();
})
}
const filePromises = (eachFile) => {
return new Promise((resolve, reject) => {
fs.readFile(eachFile, (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
Array.prototype.forEach.call(dom.window.document.querySelectorAll('link[rel="stylesheet"]'), function (element) {
let el;
if (argv.file) {
el = element.href.replace('file:\/\/', '')
} else if (argv.url) {
el = element.href
}
sourceArray.push(el);
element.parentNode.removeChild(element)
});
Array.prototype.forEach.call(dom.window.document.querySelectorAll('script'), function (element) {
element.parentNode.removeChild(element)
});
let allPromises;
if (argv.file) {
allPromises = sourceArray.map(filePromises)
} else if (argv.url) {
allPromises = sourceArray.map(fetcher);
}
Promise.all(allPromises).then(onfulfilled => {
const totalBufferContent = Buffer.concat(onfulfilled)
return totalBufferContent.toString()
}).then((buf) => {
let styleEl = dom.window.document.createElement('STYLE')
styleEl.textContent = buf
dom.window.document.head.appendChild(styleEl)
fs.writeFile('index.static.html', dom.serialize(), (err) => {
if (err) throw err;
console.log('Done')
})
})
}
}
if (argv.file) {
JSDOM.fromFile(argv.file, options).then(injectIIFE).then(manipulateDOM)
} else if (argv.url) {
JSDOM.fromURL(argv.url, options).then(injectIIFE).then(manipulateDOM)
} else {
console.log('gimme a file!')
return
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment