Как избежать конфликтов идентификаторов между обфусцированными файлами
Когда несколько VM-обфусцированных файлов попадают в один бандл, они могут объявить один и тот же идентификатор верхнего уровня и уронить страницу на этапе разбора. Здесь объясняется, почему так происходит и как это исправить.
Симптом
Сборка проходит без ошибок, но браузер выбрасывает исключение на этапе разбора, ещё до запуска приложения:
Чтобы узнать, сколько чанков объявляют имя из ошибки, посчитайте файлы, содержащие его объявление:
-l выводит каждый подходящий файл один раз, а -w сопоставляет только целые слова, поэтому vmdX не учитывается. var не учитывается, потому что повторное объявление var само по себе не является ошибкой. Результат больше 1
означает, что имя объявлено более чем в одном чанке. Замените vmd на имя из вашего сообщения об ошибке.
Конфликты идентификаторов имеют значение, только когда объявления находятся в одной области видимости. Повторение одного имени в разных модулях или замыканиях ещё не доказывает конфликт; доказательство - ошибка разбора выше.
Почему так происходит
VM-пресеты используют Identifier Names Generator со значением mangled-shuffled. Он перебирает небольшой алфавит в
перемешанном порядке, а при VM-обфускации каждая переименованная глобальная переменная получает префикс vm
(он добавляется перед любым заданным вами identifiersPrefix, так что checkout_ превращается в vm_checkout_...). Перемешанный порядок кешируется на время работы процесса, поэтому файлы,
обфусцированные в одном процессе или с одним и тем же фиксированным seed, берут имена из одной последовательности:
первая глобальная переменная в каждом файле получает одинаковое имя, вторая - другое одинаковое имя, и так далее.
Каждый файл обфусцируется независимо, и для каждого генератор начинает свою последовательность заново. Когда два файла
оказываются в одной области видимости, имена конфликтуют. Два объявления let vmd верхнего уровня попадают в
одну область видимости, и парсер отвергает второе.
Каждый VM-обфусцированный файл объявляет одно имя среды выполнения верхнего уровня без суффикса, и этого достаточно
для конфликта. renameGlobals: true сильно усугубляет ситуацию: каждое объявление верхнего уровня получает короткое
имя vm*, а собственные имена среды выполнения теряют свой уникальный суффикс.
Исправления
Лучше сначала собрать бандл, а затем обфусцировать его один раз. Если вы всё же обфусцируете файлы по отдельности и скрипты разделяют глобальную область видимости, выберите один из вариантов:
Включите
randomIdentifiersPrefix(рекомендуется)Каждый запуск обфускации получает случайный префикс, который добавляется к каждому глобальному идентификатору (при VM-обфускации он заменяет префикс
vmпо умолчанию). Имена из разных файлов больше не делят одно пространство имён, поэтому конфликты исчезают, и вам не нужно вручную согласовывать префиксы.Задайте уникальный
identifiersPrefixдля каждого файлаВручную передавайте свой префикс при обфускации каждого файла (например,
identifiersPrefix: 'auth_'для одного,checkout_для другого). Это работает, но при большом числе файлов легко ошибиться - лучше использовать случайный вариант выше.Переключите
identifierNamesGeneratorнаhexadecimalШестнадцатеричные имена используют гораздо большее пространство ключей, поэтому вероятность того, что два файла выдадут одинаковый идентификатор, намного ниже, но уникальность не гарантируется. Компромисс: идентификаторы длиннее, чем при
mangled-shuffled, поэтому бандл становится немного больше.Используйте пакетную обработку нескольких файлов в интерфейсе или проверьте плагин бандлера
Панель управления добавляет отдельный префикс каждому файлу в пределах одного пакета из нескольких файлов (платные тарифы); файлы из разных пакетов всё равно могут конфликтовать. Если вы используете плагин бандлера, проверьте его поведение, а не предполагайте, что он делает то же самое. Если вы сами вызываете пакет
javascript-obfuscatorили API, префикс нужно включить самостоятельно.
Чтобы проверить исправление, пересоберите и перезагрузите собранное приложение целиком и убедитесь, что SyntaxError
исчез. Имя из прежнего сообщения об ошибке больше не должно объявляться более чем в одном чанке; префикс меняет все
сгенерированные имена, поэтому команда grep выше говорит только об этом конкретном имени, а не о новых.
Связанные опции
randomIdentifiersPrefix- случайный префикс для каждой сборки (рекомендуется)identifiersPrefix- явная строка префиксаidentifierNamesGenerator- вид имён (mangled,hexadecimal, …)
