Улучшите возможности веб-отладки с помощью исходных карт.
Сегодня мы говорим о картах исходного кода — важнейшем инструменте современной веб-разработки, который значительно упрощает отладку. В этой статье мы рассмотрим основы карт исходного кода, то, как они генерируются и как они улучшают процесс отладки.
Необходимость исходных карт
В старые добрые времена мы создавали веб-приложения на чистом HTML, CSS и JavaScript и размещали те же файлы в Интернете.
Однако, поскольку в настоящее время мы создаем более сложные веб-приложения, ваш рабочий процесс разработки может включать использование различных инструментов. Например:
- Языки шаблонов и препроцессоры HTML: Pug , Nunjucks , Markdown .
- Препроцессоры CSS: SCSS , LESS , PostCSS .
- Фреймворки JavaScript: Angular, React, Vue, Svelte.
- Мета-фреймворки JavaScript: Next.js , Nuxt , Astro .
- Языки программирования высокого уровня: TypeScript , Dart , CoffeeScript .
- И более. Список можно продолжать и продолжать!
Этим инструментам требуется процесс сборки для преобразования вашего кода в стандартные HTML, JavaScript и CSS, понятные браузерам. Кроме того, для оптимизации производительности общепринятой практикой является сжатие (например, использование Terser для минимизации и искажения JavaScript) и объединение этих файлов, уменьшая их размер и делая их более эффективными для Интернета.
Например, используя инструменты сборки, мы можем перенести и сжать следующий файл TypeScript в одну строку JavaScript. Поиграться с демо можно в моем репозитории на GitHub .
/* A TypeScript demo: example.ts */
document.querySelector('button')?.addEventListener('click', () => {
const num: number = Math.floor(Math.random() * 101);
const greet: string = 'Hello';
(document.querySelector('p') as HTMLParagraphElement).innerText = `${greet}, you are no. ${num}!`;
console.log(num);
});
Сжатая версия будет:
/* A compressed JavaScript version of the TypeScript demo: example.min.js */
document.querySelector("button")?.addEventListener("click",(()=>{const e=Math.floor(101*Math.random());document.querySelector("p").innerText=`Hello, you are no. ${e}!`,console.log(e)}));
Однако такая оптимизация может усложнить отладку. Сжатый код, в котором все содержится в одной строке, и более короткие имена переменных могут затруднить определение источника проблемы. Вот тут-то и приходят на помощь исходные карты — они отображают ваш скомпилированный код обратно в исходный код.
Генерация исходных карт
Исходные карты — это файлы, имена которых заканчиваются на .map
(например, example.min.js.map
styles.css.map
). Их можно сгенерировать с помощью большинства инструментов сборки, например, Vite , webpack , Rollup , Parcel , esbuild и других.
Некоторые инструменты включают исходные карты по умолчанию, тогда как другим может потребоваться дополнительная настройка для их создания.
/* Example configuration: vite.config.js */
/* https://vitejs.dev/config/ */
export default defineConfig({
build: {
sourcemap: true, // enable production source maps
},
css: {
devSourcemap: true // enable CSS source maps during development
}
})
Понимание исходной карты
Эти файлы исходных карт содержат важную информацию о том, как скомпилированный код сопоставляется с исходным кодом, что позволяет разработчикам с легкостью выполнять отладку. Вот пример исходной карты.
{
"mappings": "AAAAA,SAASC,cAAc,WAAWC, ...",
"sources": ["src/script.ts"],
"sourcesContent": ["document.querySelector('button')..."],
"names": ["document","querySelector", ...],
"version": 3,
"file": "example.min.js.map"
}
Чтобы понять каждое из этих полей, вы можете прочитать спецификацию исходной карты или эту классическую статью об анатомии исходной карты .
Наиболее важным аспектом исходной карты является поле mappings
. Он использует строку в кодировке VLQ Base 64 для сопоставления строк и местоположений в скомпилированном файле с соответствующим исходным файлом. Это сопоставление можно визуализировать с помощью визуализатора исходной карты, такого как source-map-visualization и Source Map Visualization .
Сгенерированный столбец слева показывает сжатое содержимое, а исходный столбец показывает исходный источник.
Цвет визуализатора кодирует каждую строку в исходном столбце и соответствующий код в сгенерированном столбце.
В разделе сопоставлений показаны декодированные сопоставления кода. Например, запись 65-> 2:2
означает:
- Сгенерированный код: слово
const
начинается с позиции 65 в сжатом содержимом. - Исходный код: слово
const
начинается со второй строки и второго столбца исходного содержимого.
Таким образом, разработчики могут быстро определить взаимосвязь между минимизированным и исходным кодом, что упрощает процесс отладки.
Инструменты разработчика браузера применяют эти карты исходного кода, чтобы помочь вам быстрее выявлять проблемы отладки прямо в браузерах.
На изображении показано, как инструменты разработчика браузера применяют исходные карты, а также сопоставления между файлами.
Расширения исходной карты
Исходные карты поддерживают расширения. Расширения — это настраиваемые поля, которые начинаются с соглашения об именовании x_
. Одним из примеров является поле расширения x_google_ignoreList
предложенное Chrome DevTools. См. x_google_ignoreList , чтобы узнать больше о том, как эти расширения помогают вам сосредоточиться на своем коде.
Это не идеально
В нашем примере переменная greet
была оптимизирована в процессе сборки. Значение было непосредственно встроено в окончательный вывод строки.
В этом случае при отладке кода инструменты разработчика могут не получить возможность вывести и отобразить фактическое значение. Это не только проблемы для инструментов разработчика браузера. Это также усложняет мониторинг и анализ кода.
Это, конечно, решаемая проблема. Один из способов — включить информацию об области действия в карты исходного кода, как это делают другие языки программирования со своей отладочной информацией.
Однако это требует совместной работы всей экосистемы над улучшением спецификации и реализации исходных карт. Идет активное обсуждение улучшения возможностей отладки с помощью карт исходного кода.
Мы с нетерпением ждем возможности улучшить исходные карты и сделать отладку еще менее утомительной!