В некоторых дебаггерах существует tracing с возможностью проверки (condition) значения (например в регистре) в моменте шага (trace into/trace over). То есть, это аналог step into/step over только в автоматическом режиме (без постоянного нажатия кнопок).
И вот захотелось такого же в Chromium браузерах.
Но получилось только в Chrome, так как chrome.sidePanel (это такое окно расширения в окне) отсутствует в Opera и Yandex Browser. Другие не пользую.
Если использовать devtools_page (это внедрение вкладки в devtools панель), то мы получим визуальный tracing, так как нужно открывать devtools и все шаги будут видны. Всякие отдельные окна не рассматривал.
Короче, кому сразу код, то скачать архив: v0.0.0.1.
Или посмотреть исходники:
А далее кому интересны некоторые моменты в коде...
Используемые разрешения:
"permissions": [\n\t"debugger", // дебаггер, основа\n\t"tabs", // доступ к владкам\n\t"sidePanel", // панелька\n\t"contextMenus" // контекстное меню, но можно и не нужно\n]
sidePanel, повторюсь, отличная вещь. Главное, не указывать в manifest.json:
"side_panel": {\n\t"default_path": "tracing.html"\n}
Иначе панель будет открываться для всех вкладок. Для осознания сего понадобилось некоторое время.
service_worker используется для внедрения в контекстное меню и открытия панели:
"background": {\n\t"service_worker": "service-worker.js"\n}
Этапы работы:
1. Прикрепляем дебаггер к активной вкладке. Текущая стабильная версия Chrome DevTools Protocol 1.3:
chrome.debugger.attach({tabId}, '1.3', callback);
2. Включаем деббагер: chrome.debugger.sendCommand({tabId}, 'Debugger.enable');
3. И сразу ставим на паузу: chrome.debugger.sendCommand({tabId}, 'Debugger.pause');
Если скрипты уже отработали, то это вызывает ошибку. Просто перегружаем страницу.
4. Теперь только step intochrome.debugger.sendCommand({tabId}, 'Debugger.stepInto');
В котором (пока экспериментально), можно указать скрипты которые нужно пропускать skipList:
[{\n\tscriptId: scriptId,\n\tstart: {lineNumber: startLine, columnNumber: startColumn},\n\tend: {lineNumber: endLine, columnNumber: endColumn}\n}]
Это спасает от ненужных шагов в ненужных скриптах. Вещь!
Но есть проблема, если указать невалидный scriptId, то вываливается ошибка и шаг не происходит. Отваливаются скрипты на странице, и по идее нужно проверять актуальность скрипта. Что увеличивает время выполнения и пока не реализовано.
5. Отслеживаем дебаггерские событияchrome.debugger.onEvent.addListener((source, method, params) => {});
Основные события:
Получить код по scriptId:
chrome.debugger.sendCommand({tabId}, 'Runtime.getScriptSource', {scriptId});
chrome.debugger.sendCommand({tabId}, 'Runtime.getProperties', {objectId: object.objectId});
В котором так же может быть object, то есть, нужна рекурсия.
Так же, если область поиска global, то для скорости обхода нужно исключить все переменные window Object.keys(window) и встроенные функции.
Есть проблема. Объекта с objectId который выдает дебаггер, может не существовать.
{"code":-32000,"message":"Could not find object with given id"}
Вообще, с этими ошибками есть непонятки. Code может быть один и тот же:
{"code":-32000,"message":"No script with passed id."}\n{"code":-32000,"message":"Can only perform operation while paused."}
Вторая проблема это значение текущей позиции: params.callFrames[].location, params.callFrames[].scopeChain[].endLocation, params.callFrames[].scopeChain[].startLocation.
Иногда похоже на отдаленную реальность, иногда они выходят за границы кода.
То есть, location может указывать на строку 12, но если получить код, то в нем всего 8 строк. Поэтому может вылететь: alert('bad location');
Скрипты, которые используются в данной вкладке. Можно отметить для пропуска и посмотреть исходной код.
Что ищем, то и найдем. И если найдено, то можно остановить прогулку, и посмотреть, где это.
Так же существует возможность поставить breakpoint, но его не будет в списке у вкладки.
chrome.debugger.sendCommand({tabId}, 'Debugger.setBreakpointByUrl', {lineNumber, columnNumber, scriptHash});
А выглядит вот так:
Страница для теста: ищем test, в одном случае это значение из base64, а в другом это конкатенация.
P.S. Сыро, очень сыро, как и сам протокол Chrome DevTools...