Last active
March 30, 2019 09:57
-
-
Save mems/e4d3f234992b6fbbe871dae1fc2e091f to your computer and use it in GitHub Desktop.
Webpage resources graph (read HAR)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Webpage resources graph</title> | |
<script> | |
function readFileAsText(file){ | |
const reader = new FileReader(); | |
reader.readAsText(file); | |
return new Promise((resolve, reject) => { | |
reader.addEventListener("loadend", event => resolve(reader.result)); | |
reader.addEventListener("error", event => reject(event.detail)); | |
}); | |
} | |
/** | |
* Search for the first matching resource by URL or create a new one if not exist (for cases of evaluated scripts) | |
*/ | |
function getResourceByURL(resources, url, type = "unknown"){ | |
let resource = resources.find(resource => resource.url === url); | |
if(!resource){ | |
resource = new Resource(url, type); | |
resources.push(resource); | |
} | |
return resource; | |
} | |
let readingDataTransferItems = false; | |
async function readDataTransferItems(items){ | |
readingDataTransferItems = true; | |
const fileItem = Array.from(items).find(item => item.kind === "file" && (/^application\/(?:[a-z.-]+\+)?json(?=>$|;)/i.test(item.type) || /\.(json|har)$/i.test(item.getAsFile().name))); | |
if(fileItem){ | |
try{ | |
const data = JSON.parse(await readFileAsText(fileItem.getAsFile())).log; | |
const allResources = []; | |
const allDependencies = []; | |
for(const {id: pageID} of data.pages){ | |
const resources = []; | |
const dependencies = []; | |
for(const {request: {url}, _initiator: initiatorDetails, pageref} of data.entries){ | |
if(pageref !== pageID){ | |
continue; | |
} | |
const resource = new Resource(url, "");//TODO get type | |
let initiator; | |
switch(initiatorDetails.type){ | |
case "other": | |
dependencies.push(new Dependency( | |
resource, | |
resources[0] || null,// root | |
)); | |
break; | |
case "script": | |
let stack = initiatorDetails.stack; | |
let stackDependencies = new Set(); | |
// From top to bottom of the stack | |
do{ | |
for(const {url, scriptId, lineNumber, columnNumber} of stack.callFrames){ | |
const dependency = getResourceByURL(resources, url || `eval:///${scriptId}`, "script");// generate an URL based on script ID for evaluated scripts (Chrome use sourceURL if provided) | |
// Skip already registered dependencies | |
if(stackDependencies.has(dependency)){ | |
continue; | |
} | |
dependencies.push(new Dependency(resource, dependency, lineNumber, columnNumber)); | |
stackDependencies.add(dependency); | |
} | |
}while(stack = stack.parent) | |
break; | |
case "parser": | |
// could be parser HTML (images) | |
// or CSS background or font (an element use it) | |
dependencies.push(new Dependency( | |
resource, | |
getResourceByURL(resources, initiatorDetails.url), | |
initiatorDetails.lineNumber, | |
initiatorDetails.columnNumber | |
)); | |
break; | |
default: | |
console.warn(`Unknown initiator type ${initiatorDetails.type}`); | |
} | |
resources.push(resource); | |
} | |
allResources.push(...resources); | |
allDependencies.push(...dependencies); | |
} | |
console.log(allResources); | |
console.log(allDependencies); | |
}catch(error){ | |
console.log(error); | |
} | |
} | |
readingDataTransferItems = false; | |
} | |
class Dependency{ | |
constructor(dependency, resource, line = 0, column = 0){ | |
this.dependency = dependency; | |
this.resource = resource; | |
this.line = line; | |
this.column = column; | |
} | |
} | |
class Resource{ | |
constructor(url, type = "unknown"){ | |
this.url = url; | |
this.type = type; | |
} | |
} | |
document.addEventListener("dragover", event => { | |
// prevent default to allow drop | |
event.preventDefault(); | |
}); | |
document.addEventListener("drop", event => { | |
event.preventDefault(); | |
if(readingDataTransferItems){ | |
return; | |
} | |
readDataTransferItems(event.dataTransfer.items); | |
}); | |
</script> | |
</head> | |
<body> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment