Last active
October 25, 2017 17:20
-
-
Save kdzwinel/5b27649ec5829121e628b79c276a1e52 to your computer and use it in GitHub Desktop.
Quick and dirty implementation of runtime type profiling in Visual Studio Code
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
const vscode = require('vscode'); | |
const path = require('path'); | |
// puppeteer is great because it's easy to use, but it comes with 30MB headless Chrome that | |
// we can't use as it doesn't have `Profiler.startTypeProfile` yet. We have to point to a | |
// locally installed Chrome Canary instead. It's fine for a POC, but puppeteer isn't probably | |
// a good fit in a long run. | |
const puppeteer = require('puppeteer'); | |
const PATH_TO_CANARY = '/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary'; | |
let browser = null; | |
let page = null; | |
function activate(context) { | |
const collection = vscode.languages.createDiagnosticCollection('javascript'); | |
const disposable = vscode.commands.registerCommand('extension.typeProfile', async () => { | |
if (!browser) { | |
browser = await puppeteer.launch({ executablePath: PATH_TO_CANARY }); | |
page = await browser.newPage(); | |
} | |
await page.reload(); | |
// I haven't found an official way to send CDP commands directly via puppeteer, so I'm using | |
// a private API here (remember it's a POC!) | |
await page._client.send('Runtime.enable'); | |
await page._client.send('Profiler.enable'); | |
await page._client.send('Profiler.startTypeProfile'); | |
const document = vscode.window.activeTextEditor.document; | |
const fileName = path.basename(document.uri.toString()); | |
// Compile script | |
const { scriptId, exceptionDetails } = await page._client.send('Runtime.compileScript', { | |
expression: document.getText(), | |
sourceURL: fileName, | |
persistScript: true | |
}); | |
if (exceptionDetails) { | |
// Exception lineNumber and columnNumber can be used to highlight offending code. | |
vscode.window.showErrorMessage(`Error compiling script: ${exceptionDetails.text} ${exceptionDetails.lineNumber}:${exceptionDetails.columnNumber}`); | |
return; | |
} | |
// Execute script | |
await page._client.send('Runtime.runScript', { scriptId }); | |
const { result } = await page._client.send('Profiler.takeTypeProfile'); | |
const script = result.find(script => script.url === fileName); | |
if (script) { | |
const document = vscode.window.activeTextEditor.document; | |
const diagnostics = script.entries.map(entry => { | |
// I'm highlighting only 1 character, it'd be better to highlight whole symbol | |
const typePositionStart = document.positionAt(entry.offset); | |
const typePositionEnd = new vscode.Position(typePositionStart.line, typePositionStart.character + 1); | |
const range = new vscode.Range(typePositionStart, typePositionEnd); | |
const typesString = entry.types.map(type => type.name).join(' or '); | |
return new vscode.Diagnostic(range, `V8 says it's a ${typesString}`, vscode.DiagnosticSeverity.Information); | |
}); | |
collection.set(document.uri, diagnostics); | |
} | |
await page._client.send('Profiler.stopTypeProfile'); | |
await page._client.send('Profiler.disable'); | |
await page._client.send('Runtime.disable'); | |
}); | |
context.subscriptions.push(disposable); | |
} | |
exports.activate = activate; | |
async function deactivate() { | |
if (browser) { | |
await browser.close(); | |
} | |
} | |
exports.deactivate = deactivate; |
@kdzwinel, do you reckon this is also available in any of the latest nodejs builds?
@nojvek yes, you have to use TOT though: https://github.com/v8/node . Also, see https://github.com/fhinkel/type-profile .
[Edit] I've updated the first comment with some more thoughts/info
@kdzwinel @novek I've created a repo for this extension, https://github.com/auchenberg/vscode-javascript-type-profiler
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That's the core of the extension, all other files that are needed to run it can be generated with Yeoman (docs).
You can see it working in this preview.
Some thoughts: