Source Maps: быстро и понятно
Механизм Source Maps используется для отображения исходных текстов программы на сгенерированные на их основе скрипты. Несмотря на то, что тема не нова и по ней уже написан ряд статей (например эта, эта и эта) некоторые аспекты все же нуждаются в прояснении. Представляемая статья представляет собой попытку упорядочить и систематизировать все, что известно по данной теме в краткой и доступной форме.
В статье Source Maps рассматриваются применительно к клиентской разработке в среде популярных браузеров (на примере, DevTools Google Chrome), хотя область их применения не привязана к какому-либо конкретному языку или среде. Главным источникам по Source Maps является, конечно, стандарт, хотя он до сих пор не принят (статус — proposal), но, тем не менее, широко поддерживается браузерами.
Работа над Source Maps была начата в конце нулевых, первая версия была создана для плагина Firebug Closure Inspector. Вторая версия вышла в 2010 и содержала изменения в части сокращения размера map-файла. Третья версия разработана в рамках сотрудничества Google и Mozilla и предложена в 2011 (последняя редакция в 2013).
В настоящее время в среде клиентской разработки сложилась ситуация, когда исходный код почти никогда не интегрируется на веб-страницу непосредственно, но проходит перед этим различные стадии обработки: минификацию, оптимизацию, конкатенацию, более того, сам исходный код может быть написан на языках требующих транспиляции. В таком случае, для целей отладки необходим механизм позволяющий наблюдать в дебаггере именно исходный, человекочитаемый код.
Для работы Source Maps необходимы следующие файлы:
- собственно сгенерированный JavaScript-файл
- набор файлов с исходным кодом использовавшийся для его создания
- map-файл отображающий их друг на друга
Map-файл
Вся работа Source Maps основана на map-файле, который может выглядеть, например, так:
Обычно, имя map-файла складывается из имени скрипта, к которому он относится, с добавлением расширения «.map», bundle.js — bundle.js.map. Это обычный json-файл со следующими полями:
- «version» — версия Source Maps;
- «file» — (опционально) имя сгенерированного файла, к которому относится текущий map-файл;
- «sourceRoot» — (опционально) префикс для путей к файлам-исходникам;
- «sources» — список путей к файлам-исходникам (разрешаются аналогично адресам src тега script, можно использовать file://.);
- «names» — список имен переменных и функций, которые подверглись изменению в сгенерированном файле;
- «mappings» — координаты отображения переменных и функций исходных файлов на сгенерированный файл в формате Base64 VLQ;
- «sourcesContent» — (опционально) в случае self-contained map-файла список строк, каждая из которых содержит исходный текст файла из sources;
Загрузка Source Maps
Для того, чтобы браузер загрузил map-файл может быть использован один из следующих способов:
- JavaScript-файл пришел с HTTP-заголовком: SourceMap: (ранее использовался ныне устаревший X-SourceMap: )
- в сгенерированном JavaScript-файле есть особый комментарий вида:
//# sourceMappingURL= (для CSS /*# sourceMappingURL= */)
Таким образом, загрузив map-файл браузер подтянет и исходники из поля «sources» и с помощью данных в поле «mappings» отобразит их на сгенерированный скрипт. Во вкладке Sources DevTools можно будет найти оба варианта.
Для указания пути может использоваться пседопротокол file://. Также, в может быть включено все содержимое map-файла в кодировке Base64. В терминологии Webpack подобные Source Maps названы inline source maps.
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
Ошибки загрузки Source Maps
Следует заметить, что map-файлы не являются частью веб-страницы, поэтому вы не увидите информации об их загрузке во вкладке Network DevTools. Тем не менее, если в сгенерированном файле находится ссылка на несуществующий map-файл, в Console DevTools будет предупреждение вида: «DevTools failed to load SourceMap: . ». Также при наличии ссылки на несуществующий исходник, вместо него будет сообщение вида: «Could not load content for . ».
Self-contained map-файлы
Код файлов-исходников можно включить непосредственно в map-файл в поле «sourcesContent», при наличии этого поля необходимость в их отдельной загрузке отпадает. В этом случае названия файлов в «sources» не отражают их реального адреса и могут быть совершенно произвольными. Именно поэтому, вы можете видеть во вкладке Sources DevTools такие странные «протоколы»: webpack://, ng:// и т.д
Mappings
Сущность механизма отображения состоит в том, что координаты (строка/столбец) имен переменных и функций в сгенерированном файле отображаются на координаты в соотвествующем файле исходного кода. Для работы механизма отображения необходима следующая информация:
(#1) номер строки в сгенерированном файле;
(#2) номер столбца в сгенерированном файле;
(#3) индекс исходника в «sources»;
(#4) номер строки исходника;
(#5) номер столбца исходника;
Все эти данные находятся в поле «mappings», значение которого — длинная строка с особой структурой и значениями закодированными в Base64 VLQ.
Строка разделена точками с запятой (;) на разделы, соответствующие строкам в сгенерированном файле (#1).
Каждый раздел разделен запятыми (,) на сегменты, каждый из которых может содержать 1,4 или 5 значений:
- номер столбца в сгенерированном файле (#2);
- индекс исходника в «sources» (#3);
- номер строки исходника (#4);
- номер столбца исходника (#5);
- индекс имени переменной/функции из списка «names»;
Каждое значение представляет собой число в формате Base64 VLQ. VLQ (Variable-length quantity) представляет собой принцип кодирования сколь угодно большого числа с помощью произвольного числа двоичных блоков фиксированной длины.
В Source Maps используются шестибитные блоки, которые следуют в порядке от младшей части числа к старшей. Старший 6-й бит каждого блока (continuation bit) зарезервирован, если он установлен, то за текущим следует следующий блок относящийся к этому же числу, если сброшен — последовательность завершена.
Поскольку в Source Maps значение должно иметь знак, для него также зарезервирован младший 1-бит (sign bit), но только в первом блоке последовательности. Как и ожидается, установленный sign бит означает отрицательно число.
Таким образом, если число можно закодировать единственным блоком, оно не может быть по модулю больше 15 (11112), так как в первом шестибитном блоке последовательности два бита зарезервированы: continuation бит всегда будет сброшен, sign бит будет установлен в зависимости от знака числа.
Шестибитные блоки VLQ отображаются на кодировку Base64, где каждой шестибитной последовательности соответствует определенный символ ASCII.

Декодируем число mE. Инверсируем порядок, младшая часть последняя — Em. Декодируем числа из Base64: E — 000100, m — 100110. В первом отбрасываем старший continuation бит и два лидирующих нуля — 100. Во втором отбрасываем старший continuation и младший sign биты (sign бит сброшен — число положительное) — 0011. В итоге получаем 100 00112, что соответствует десятичному 67.
Можно и в обратную сторону, закодируем 41. Его двоичный код 1010012, разбиваем на два блока: старшая часть — 10, младшая часть (всегда 4-битная) — 1001. К старшей части добавляем старший continuation бит (сброшен) и три лидирующих нуля — 000010. К младшей части добавляем старший continuation бит (установлен) и младший sign бит (сброшен — число положительное) — 110010. Кодируем числа в Base64: 000010 — C, 110010 — y. Инверсируем порядок и, в итоге, получаем yC.
Для работы с VLQ весьма полезна одноименная библиотека.
Создание и использование Source Maps для css и js в GULP 4
Хотелось бы в двух словах рассказать, как настроить Source Maps для GULP 4, но не получится вырвать из контекста просто пару строк кода, поэтому разобью статью на 2 части. Первая будет с базовым кодом для Source Maps, а во второй части будет куча кода из рабочего проекта.
Source Maps нужны для проектов, где происходит сборка нескольких файлов в один, например, компиляция файлов scss в один файл main.min.css или конкатенация js-файлов в один scripts.min.js . Карты источников нужны для того, чтобы быстро вносить правки, и не искать в каком файле задано определенное правило или функция, особенно когда для сборки используются десятки файлов или различных библиотек.

Так будет выглядеть в инспекторе код без Source Maps:

Так будет выглядеть код с использованием Source Maps:
И по итогу, если нам нужно увеличить отступ снизу у элемента .icon , то нам не нужно искать по всем файлам scss где задано это правило, а с помощью карты источников видим, что данное правило указано в файле _general.scss на 44 строке.
Если вам это не нужно, то дальше можно не читать.
1. Базовый пример вывода Source Maps для js-файла
var gulp = require('gulp'); var plugin1 = require('gulp-plugin1'); var plugin2 = require('gulp-plugin2'); var sourcemaps = require('gulp-sourcemaps'); gulp.task('javascript', function() < gulp.src('src/**/*.js') .pipe(sourcemaps.init()) .pipe(plugin1()) .pipe(plugin2()) .pipe(sourcemaps.write()) .pipe(gulp.dest('dist')); >);
Где — plugin1() и plugin2() — это какие-то образные плагины, которые занимаются минификацией и конкатенацией js-файлов, например.
Дальше будет много кода из рабочего примера, будет использоваться scss, сборка, минификация, конкатенация и т.д.
2. Кастомизированный пример подключения Source Maps в js-файлах и в css-файлах
var syntax = 'scss', gulp = require('gulp'), sass = require('gulp-sass'), cleancss = require('gulp-clean-css'), autoprefixer = require('gulp-autoprefixer'), concat = require('gulp-concat'), uglify = require('gulp-uglify'), rename = require('gulp-rename'), sourcemaps = require('gulp-sourcemaps'), notify = require('gulp-notify'),
Задача для компиляции файла main.min.css с Source Maps
// Compile .scss to *.min.css gulp.task('styles', function() < return gulp.src('app/'+syntax+'/**/*.'+syntax+'') // берем все файлы scss .pipe(sourcemaps.init()) // инициализируем создание Source Maps .pipe(sass(< outputStyle: 'compressed' >).on("error", notify.onError())) // компилируем сжатый файл .css .pipe(rename(< suffix: '.min', prefix : '' >)) // переименовываем файл в .min.css .pipe(autoprefixer(['last 15 versions'])) // добавляем вендорные префиксы .pipe(cleancss( > >)) // удаляем все комментарии из кода .pipe(sourcemaps.write()) // пути для записи SourceMaps - в данном случае карта SourceMaps будет добавлена прям в данный файл main.min.css в самом конце .pipe(gulp.dest('app/css')) // перемещение скомпилированного файла main.min.css в папку app/css >);
Задача для конкатенации файла scripts.min.js с Source Maps
// Concatenate all .js from /libs/ to libs.min.js gulp.task('scripts', function() < return gulp.src([ 'app/libs/jquery/dist/jquery.min.js', // указываем пути всех подключаемых библиотек и файлов JS 'app/js/common.js', // основной файл функций подключаем в самом конце ]) .pipe(sourcemaps.init()) // инициализируем создание Source Maps .pipe(concat('scripts.min.js')) // объединяем все вышеперечисленные файлы в один scripts.min.js .pipe(uglify()) // минифицируем и удаляем комментарии из файла scripts.min.js .pipe(sourcemaps.write()) // пути для записи SourceMaps - в данном случае карта SourceMaps будет добавлена прям в данный файл scripts.min.js в самом конце в формате комментария .pipe(gulp.dest('app/js')) // перемещаем полученный файл scripts.min.js в директорию app/js >);
Все классно, но есть одна проблема.
sourcemaps.write() — не указаны пути для файла *.map, значит карта источников будет записана внутри файла в самый конец, тем самым увеличивая вес файлов более чем в два раза. Это не круто, но зато карты источников будут работать и в Chrome, и в Firefox.
sourcemaps.write(‘.’) — в таком формате source map запишется отдельным файлом в той же папке, что и основной файл, в формате main.min.css.map и scripts.min.js.map.
Проблема с лишним содержимым в виде карты путей решаема.
Source Maps нужны нам только во время разработки, поэтому при билде продашена просто удалим все комментарии из файлов .css и .js — а карта источников записана именно в виде комментария.
Это часть кода из моей таски ‘build’:
var buildCss = gulp.src('app/css/**/*.css') .pipe(cleancss( > >)) // удаляем все комментарии из css .pipe(gulp.dest('dist/css')); // отправляем полученный файл на продакшен var buildJs = gulp.src('app/js/**/*.js') .pipe(uglify()) // удаляем все комментарии из js .pipe(gulp.dest('dist/js')); // отправляем полученный файл на продакшен
По итогу, на продакшене будут чистые минифицированные файлы без лишнего кода и комментариев.
Для оптимизации запросов на сервер можно объединить иконки и небольшие картинки, которые используются в css,…
В общем, перепробовал десятки разных плагинов и настроек, но .jpg совсем не оптимизировались, а иногда…
Бесконечный анимированный фон с эффектом параллакса создан на основе варианта 2 из этой статьи HTML…
Изменение внешнего вида для чекбокса с помощью CSS HTML для чекбокса или радио-кнопок CSS для…
Введение в Javascript Source Maps
Вы когда-нибудь думали, как было бы здорово, если бы слитый в один файл и минифицированный яваскрипт код в production-окружении можно было удобно читать и даже отлаживать без ущерба производительности? Теперь это возможно, если использовать штуку под названием source maps.
Если коротко, то это способ связать минифицированный/объединённый файл с файлами, из которых он получился. Во время сборки для боевого окружения помимо минификации и объединения файлов также генерируется файл-маппер, который содержит информацию об исходных файлах. Когда производится обращение к конкретному месту в минифицированном файле, то производится поиск в маппере, по которому вычисляется строка и символ в исходном файле. Developer Tools (WebKit nightly builds или Google Chrome Canary) умеет парсить этот файл автоматически и прозрачно подменять файлы, как будто ведётся работа с исходными файлами. На момент написания (оригинальной статьи — прим. перев.) Firefox заблокировал развитие поддержки Source Map. Подробнее — на MozillaWiki Source Map.
Пример — правильное определение места в исходном коде
В этом примере можно ткнуть в любом месте textarea правой кнопкой и выбрать пункт «Get original location». При этом будет произведено обращение к файлу-мапперу с передачей строки и номера символа в минифицированном коде, и будет показан соответствующий кусок кода из исходного файла. В консоль будут выведены номер строки и номер символа в исходном файле и другая интересная информация.

Реальное использование

Прежде чем смотреть следующий пример, нужно активировать просмотр source maps в Chrome Canary или WebKit nightly, для этого в свойствах активировать пункт «Enable source maps» (см. скриншот)
Продолжим. Предыдущий пример был интересным, но как это можно использовать? Зайдите на dev.fontdragr.com настроенным браузером Google Chrome и вы увидите, что яваскрипты на странице не скомпилированы и можно смотреть отдельные js-файлы. Это всё благодаря использованию маппера, а на самом деле код на странице скомпилирован. Все ошибки, выводы в лог и точки останова будут маппиться на исходный код, и отлаживать код будет очень удобно. В итоге можно работать с production-сайтом как с тестовым.
Зачем вообще нужны Source Maps?
- CoffeeScript
- ECMAScript 6 и выше
- SASS/LESS и т.п.
- Практически любой язык, который компилируется в JavaScript
Google Web Toolkit (GWT) недавно добавил поддержку Source Maps и Ray Cromwell из GWT сделал отличный скринкаст, показывающий работу Source Map в действии.

Другой пример использует библиотеку Google Traceur, которая позволяет писать на ES6 (ECMAScript 6) и компилировать в ES3-совместимый код. Компилятор Traceur также генерирует source map. Посмотрите на пример использования особенностей ES6 (классов и traits), как если бы они поддерживались браузером нативно. Textarea в примере также позволяет писать ES6-код, который будет компилироваться на лету в ES3 и также будет создаваться файл-маппер.
Пример — можно написать код на ES6 и сразу посмотреть в отладчике
Как это работает?
Единственный пока компилятор/минификатор с поддержкой Source Map — Closure compiler (как при компиляции сгенерировать маппер — написано ниже). При минификации JavaScript будет создан и файл-маппер. Пока Closure compiler не добавляет в конец файла специальный комментарий для Google Chrome Canary dev tools о том, что доступен файл-маппер:
//@ sourceMappingURL=/path/to/file.js.map
Такой комментарий позволяет браузеру искать нужное место в исходном файле, используя файл-маппер. Если идея использовать странные комментарии вам не нравится, то можно добавить к скомпилированному файлу специальный заголовок:
X-SourceMap: /path/to/file.js.map

Как и комментарий, это скажет клиенту, где искать маппер для этого файла. Использование заголовка также позволяет работать с языками, которые не поддерживают однострочные комментарии.
Файл-маппер будет скачан только если включено свойство и открыта консоль. Ну и конечно нужно будет залить исходные файлы, чтобы они были доступны по указанным в маппере путям.
Как сгенерировать файл-маппер?
Как уже говорилось выше, нужен будет Closure compiler для минификаци, склейки и генерации файла-маппера для нужных JavaScript-файлов. Для этого нужно выполнить команду:
java -jar compiler.jar \ --js script.js \ --create_source_map ./script-min.js.map \ --source_map_format=V3 \ --js_output_file script-min.js
Нужные флаги — это —create_source_map и —source_map_format . Последний нужен, т.к. по умолчанию маппер создаётся в формате V2, а нам нужен V3.
Внутреннее устройство Source Map
Чтобы лучше понять Source Map, возьмём для примера небольшой файл-маппер и подробно разберём, как устроена «адресация». Ниже приведён немного модифицированный пример из V3 spec:
- Версию маппера
- Название минифицированного/объединённого файла для production
- sourceRoot позволяет дописывать префикс в путь к исходным файлам
- sources содержит названия исходных файлов
- names содержит все настоящие названия переменных/функций из полученного файла
- а mappings — это соответствующие минифицированные названия
BASE64 VLQ или как сделать Source Map маленьким

Изначально в спецификации был описан очень подробный вывод всех зависимостей, что делало файл-маппер в 10 раз больше размером, чем сгенерированный файл. Вторая версия уменьшила размер файла вполовину, а третья версия — уменьшила ещё раз вполовину. Теперь для 133kB файла генерируется ~300kB файл-маппер. Как же удалось добиться такого уменьшения и при этом уметь отслеживать сложные зависимости?
Используется VLQ (Variable Length Quantity) и Base64-кодирование. Свойство mappings — это одна очень большая строка. Внутри этой строки точки с запятой (;) отделяют номера строк в сгенерированном файле. Внутри получившейся строки используются запятые для отделения сегментов кода. Каждый из сегментов представляет собой 1, 4 или 5 VLQ-полей. Некоторые могут быть длиннее за счёт бита продолжения. Каждый сегмент строится на основе предыдущего, что помогает уменьшить размер файла.
Как говорилось раньше, каждый сегмент может быть 1, 4 или пятью VLQ. На диаграмме показаны 4 VLQ с одним битом продолжения. Разберём её подробнее и покажем, как маппер вычисляет положение в исходном файле. Сегмент состоит из пяти вещей:
- Номер символа в сгенерированном файле
- Исходный файл
- Номер строки в исходном файле
- Номер символа в исходном файле
- Исходное название (если есть)
(прим. перев.: не осилил до конца перевести эту часть статьи, полностью можно прочесть в оригинале; если есть желающие помочь — пишите, буду благодарен)
Потенциальные проблемы с XSSI
В спецификации говорится о возможных проблемах с внедрением XSS при использовании Source Map. Избавиться от неё можно, написав в начале своего map-файла » )]> «, чтобы сделать это js-файл невалидным и вызвать ошибку. WebKit dev tools уже умеет её забарывать:
if (response.slice(0, 3) === ")]>")
Как видно, первые три символа обрезаются и производится проверка их на соответствие указанному в спецификации невалидному коду и в этом случае вырезается всё до следующего символа перевода строки.
@sourceURL и displayName в действии: eval и анонимные функции
Эти два соглашения хотя пока и не входят в спецификацию Source Map, но позволяют серьёзно упростить работу с eval и анонимными функциями.
Первый хелпер очень похож на свойство //@ sourceMappingURL и вообще-то в спецификации (V3) упоминается. Включив этот специальный комментарий в код, который потом будет выполнен через eval , можно назвать eval -ы, что даст им более логичные имена при работе в консоли. Ниже приведён простой пример с использованием компилятора CoffeeScript:

Пример — пропущенный через eval код со сгенерированным именем
Другой хелпер позволяет давать имена анонимным функциям при помощи свойства displayName , указанного в контексте этой функции. Попрофилируйте этот пример, чтобы увидеть displayName в действии.

Пример — названия для анонимных функций через displayName (только WebKit NIghtly)
При профилировании будут показываться красивые названия вместо (anonymous function) . Но скорее всего displayName не будет включён в финальную сборку Google Chrome. Хотя надежды ещё остаются, предлагают также переименовать свойство в debugName.
К моменту написания статьи присваивание названий коду, выполненному через eval , поддерживают только Firefox и Google Chrome. Свойство displayName доступно только в ночных сборках Google Chrome.
Вливайтесь
Есть очень длинное обсуждение по поддержке Source Map в CoffeeScript.
У UglifyJS также есть тикет про поддержку Source Map.
Вы можете помочь, если примете участие в обсуждении и выскажете мнение по поводу нужности поддержки Source Map. Чем больше будет инструментов, поддерживающих эту технологию, тем будет проще работать, так что требуйте её поддержки в вашем любимом OpenSource-проекте.
Source Map не идеален
Есть одна неприятность с использованием Source Map для нормальной отладки. Проблема заключается в том, что при попытке проверить значение аргумента или переменной, определённой в контексте исходного файла, контекст ничего не вернёт, т.к. он на самом деле не существует. Нужен какой-то обратный маппинг, чтобы проверить значение соответствующей переменной/аргумента в минифицированном коде и сопоставить его исходному коду.
Проблема решаемая, а при должном внимании к Source Map могут появиться ещё более интересные его применения.
Инструменты и ресурсы
- Nick Fitzgerald сделал форк UglifyJS с поддержкой Source Map
- Paul Irish сделал простое демо Source Map
- Conrad Irwin написал удобный Source Map gem для Ruby-разработчиков
- Что ещё почитать про именование eval и свойство displayName
- Можно посмотреть исходный код Closure Compiler создания Source Map
- Несколько скриншотов и разговор о поддержке GWT source maps
Source Map — мощный инструмент для разработчика. Он позволяет держать production-код максимально сжатым, но при этом позволяет его отлаживать. Так же полезен для начинающих разработчиков, чтобы посмотреть код, написанный опытными разработчиками, чтобы поучиться правильному структурированию и написанию своего кода без необходимости продираться сквозь минифицированный код. Так чего же вы ждёте? Сгенерируйте Source Map для своего проекта!
Source Maps¶
Карты исходников позволяют сопоставить преобразованный файл с исходным файлом. Основное назначение карт исходных текстов — облегчить отладку и помочь в исследовании проблем, возникающих в релизных сборках.
Без исходных карт при возникновении ошибки в сборке релиза вы увидите стектрейс следующего вида:
1 2 3 4
TypeError: Cannot read property 'data' of undefined at anonymous(app:///index.android.bundle:1:4277021) at call(native) at p(app:///index.android.bundle:1:227785)
При создании карт исходного кода трассировка стека будет включать путь, имя файла и номер строки исходного файла:
1 2 3 4
TypeError: Cannot read property 'data' of undefined at anonymous(src/modules/notifications/Permission.js:15:requestNotificationPermission) at call(native) at p(node_modules/regenerator-runtime/runtime.js:64:Generator)
Это позволяет сортировать проблемы с релизом, используя расшифровываемую трассировку стека.
Следуйте приведенным ниже инструкциям, чтобы начать работу с картами источников.
Включите карты источников на Android¶
Hermes¶
По умолчанию карты исходников строятся в режиме Release, если не установлен hermesFlagsRelease . В этом случае карты источников должны быть включены.
Для этого убедитесь, что в файле android/app/build.gradle вашего приложения установлено следующее.
1 2 3 4
project.ext.react = [ enableHermes: true, hermesFlagsRelease: ["-O", "-output-source-map"], // plus whichever flag was required to set this away from default ]
Если все сделано правильно, вы должны увидеть местоположение исходной карты во время вывода Metro build.
Writing bundle output to:, android/app/build/generated/assets/react/release/index.android.bundle Writing sourcemap output to:, android/app/build/intermediates/sourcemaps/react/release/index.android.bundle.packager.map
Сборки разработки не создают пакет и поэтому уже имеют символы, но если сборка разработки имеет пакет, вы можете использовать hermesFlagsDebug , как описано выше, чтобы включить карты исходников.
Включите карты источников на iOS¶
По умолчанию карты источников отключены. Чтобы включить их, необходимо определить переменную окружения SOURCEMAP_FILE .
Для этого в Xcode перейдите к этапу Build Phase — «Bundle React Native code and images».
В верхней части файла рядом с другими экспортами добавьте запись для SOURCEMAP_FILE в предпочтительное местоположение и имя. Как показано ниже:
1 2 3 4
export SOURCEMAP_FILE="$(pwd)/../main.jsbundle.map"; export NODE_BINARY=node ../node_modules/react-native/scripts/react-native-xcode.sh
Если все сделано правильно, вы должны увидеть местоположение исходной карты во время вывода Metro build.
Writing bundle output to:, Build/Intermediates.noindex/ArchiveIntermediates/application/BuildProductsPath/Release-iphoneos/main.jsbundle Writing sourcemap output to:, Build/Intermediates.noindex/ArchiveIntermediates/application/BuildProductsPath/Release-iphoneos/main.jsbundle.map
Символизация вручную¶
Вы можете прочитать о ручной символизации трассы стека на странице symbolication.
Комментарии
(C) 2021-2023, Справочник React Native разработчика
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the «Software»), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED «AS IS», WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. —>
