Подстановка значений в шаблон на стороне сервера
Внедряйте отрисованные на сервере значения (например, выражения Go html/template `{{ .Field }}`) в VM-обфусцированный JavaScript, не ломая конвейер обфускации.
Проблема
Ваш бэкенд (Go, Rails, Django, PHP, …) отдаёт файл JavaScript, содержимое которого должно частично отрисовываться
для каждого запроса — эндпоинт API, список фича-флагов, блоб начального состояния, id сборки, nonce. Вы обфусцируете этот
JS с vmObfuscation: true, но вам также нужно, чтобы шаблонизатор подставил плейсхолдеры в обфусцированном результате
после завершения обфускации. Если плейсхолдеры вобраны в байт-код VM (поведение по умолчанию для строк и
идентификаторов), шаблонизатору нечего подставлять.
Какую опцию выбрать?
| Значение с сервера… | Использовать |
|---|---|
| Сырое JS-выражение (литерал массива, объект, число, булево значение, вызов функции) | reservedNames + плейсхолдер-идентификатор |
| Строка, и вы контролируете разделители шаблонизатора | reservedStrings + плейсхолдер-шаблонный литерал |
Строка, и шаблонизатор навязывает определённые разделители (например, Go {{ .Field }}) | reservedStrings + плейсхолдер-строка или шаблонный литерал |
Паттерн 1 — reservedNames с плейсхолдером-идентификатором
Лучше всего для: внедрения сырых JS-выражений (массивы, объекты, числа, …) без каких-либо забот об экранировании кавычек.
Выберите отличительный идентификатор, который никогда не столкнётся с настоящим кодом, обращайтесь к нему напрямую и
укажите в reservedNames регулярное выражение, соответствующее ему. При VM-обфускации идентификатор направляется через
массив зарезервированных выражений и появляется в результате дословно.
Исходник
(function () {
var initialState = __INITIAL_STATE__;
bootstrap(initialState);
})();
Опции обфускатора
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedNames: ['^__INITIAL_STATE__$']
});
После обфускации
Где-то в результате вы найдёте массив зарезервированных выражений, похожий на:
let _r = [__INITIAL_STATE__, /* …other entries… */];
Токен __INITIAL_STATE__ переживает переименование идентификаторов и не вбирается в байт-код VM.
Подстановка на стороне хоста (пример на Go)
tpl := template.Must(template.New("obf.js").Parse(obfuscated))
tpl.Execute(w, map[string]any{
"InitialState": map[string]any{"user": "alice", "theme": "dark"},
})
…где ваш шаблон Go заменяет токен на сырое JS-выражение:
{{ `__INITIAL_STATE__` }} → {{ .InitialState | toJSON }}
Результат:
let _r = [{"user":"alice","theme":"dark"}, /* … */];
Ни кавычек, ни экранирования — внедрённое значение разбирается движком JS как обычное выражение.
Паттерн 2 — reservedStrings с плейсхолдером-шаблонным литералом
Лучше всего для: шаблонизаторов в стиле Go / Jinja, которым нужны разделители вроде {{ .Field }}, оказывающиеся
валидным JS-текстом при обёртывании в обратные кавычки.
Плейсхолдер живёт внутри одноквазийного, неинтерполируемого шаблонного литерала. При VM-обфускации это направляется через массив зарезервированных выражений, сохраняя в результате сырую форму с обратными кавычками.
Исходник
(function () {
var featureFlags = JSON.parse(`{{.Config.FeatureFlags}}`);
applyFlags(featureFlags);
})();
Опции обфускатора
UI
Чтобы зарезервировать плейсхолдер {{.Config.FeatureFlags}} из исходника выше, добавьте это регулярное выражение в поле
Reserved Strings — с одинарными обратными слешами. Интерфейс хранит значение дословно, поэтому, в отличие от JS-кода,
обратные слеши не удваиваются:
\{\{[^}]+\}\}

API
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedStrings: ['\\{\\{[^}]+\\}\\}']
});
После обфускации
let _r = [`{{.Config.FeatureFlags}}`, /* … */];
Плейсхолдер сохраняется байт в байт, включая окружающие обратные кавычки.
Подстановка на стороне хоста
Замените {{.Config.FeatureFlags}} на валидную JSON-строку — во время выполнения она окажется внутри обратных кавычек,
которые не требуют экранирования внутренних кавычек:
flagsJSON, _ := json.Marshal(config.FeatureFlags) // e.g. {"newCheckout":true,"darkMode":false}
out := strings.ReplaceAll(obfuscated, "{{.Config.FeatureFlags}}", string(flagsJSON))
Во время выполнения: JSON.parse(`{"newCheckout":true,"darkMode":false}`) — работает.
Паттерн 3 — reservedStrings с плейсхолдером-строкой в кавычках
Лучше всего для: исходного кода, который должен оставаться в ES5 (без шаблонных литералов), или случаев, когда окружающий API ожидает обычный строковый литерал.
Плейсхолдер — строковый литерал в одинарных или двойных кавычках. При VM-обфускации он направляется через массив
зарезервированных строк, который выводится как сериализованный через JSON.stringify JS-массив — всегда в двойных
кавычках независимо от стиля кавычек на входе.
Исходник
(function () {
var tags = JSON.parse("{{.Page.Tags}}");
renderTags(tags);
})();
Опции обфускатора
UI
Чтобы зарезервировать плейсхолдер {{.Page.Tags}} из исходника выше, добавьте это регулярное выражение в поле
Reserved Strings — с одинарными обратными слешами. Интерфейс хранит значение дословно, поэтому, в отличие от JS-кода,
обратные слеши не удваиваются:
\{\{[^}]+\}\}

API
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedStrings: ['\\{\\{[^}]+\\}\\}']
});
После обфускации
var _rs = ["{{.Page.Tags}}", /* … */];
Подстановка на стороне хоста
Поскольку плейсхолдер находится внутри JS-строки в двойных кавычках, во внедряемой полезной нагрузке JSON внутренние
символы " должны быть экранированы как \":
raw, _ := json.Marshal(page.Tags) // e.g. ["news","tech","release"]
// Escape " for embedding inside a JS double-quoted string.
escaped := strings.ReplaceAll(string(raw), `"`, `\"`)
out := strings.ReplaceAll(obfuscated, "{{.Page.Tags}}", escaped)
Итоговый результат:
var _rs = ["[\"news\",\"tech\",\"release\"]", /* … */];
Во время выполнения: JSON.parse("[\"news\",\"tech\",\"release\"]") → ["news","tech","release"].
Если вы забудете об экранировании, браузер увидит несбалансированные кавычки и бросит SyntaxError. Паттерн 2 полностью
обходит это, используя обратные кавычки.
Несколько плейсхолдеров в одной программе
Все три паттерна сочетаются. Одно регулярное выражение reservedStrings с чередованием может соответствовать любой форме
плейсхолдера, которую выдаёт ваш шаблонизатор:
JavaScriptObfuscator.obfuscate(source, {
vmObfuscation: true,
reservedNames: ['^__INITIAL_STATE__$'],
reservedStrings: ['\\{\\{[^}]+\\}\\}']
});
Вы можете смешивать плейсхолдеры-идентификаторы (для сырых JS-значений) и плейсхолдеры-строки (для отрисованного JSON) в одном исходнике — выбирайте под каждый плейсхолдер по тому, что сервер действительно внедрит.
Замечания о совместимости
- Не переиспользуйте плейсхолдеры между идентификаторами и строками. Зарезервированное имя вроде
__TOKEN__и зарезервированная строка, соответствующая__TOKEN__, описывают два разных пути в коде (массив зарезервированных выражений против массива зарезервированных строк). Используйте для каждого различающиеся текстовые формы — например, соглашениеUPPER_SNAKEдля плейсхолдеров-идентификаторов и форму, обёрнутую разделителями ({{ ... }},%{...},<<<...>>>), для плейсхолдеров-строк. Так ошибка в одном регулярном выражении не сможет незаметно совпасть с другим. - Регулярные выражения
reservedStringsприменяются к сырым строковым значениям. Регулярное выражение сопоставляется со значением строки во время выполнения, а не с текстом исходника.\{\{[^}]+\}\}соответствует строкам, которые содержат{{.something}}(или любую другую форму{{...}}). Если ваш плейсхолдер может быть обёрнут дополнительным содержимым ("prefix-{{.Field}}-suffix"), регулярное выражение всё равно совпадёт, но сохранится вся строка целиком — планируйте подстановку с учётом этого. - Работает с любым шаблонизатором. Хотя в примерах используется синтаксис Go
text/template, ничто в интеграции с javascript-obfuscator не специфично для Go. Подойдёт всё, что может выполнить замену на уровне строк в результате обфускатора: Rails ERB, Django, короткие теги PHP, sed в CI-конвейере и т. д. Выбирайте разделители, которые ваш движок выдаёт естественно и которые не сталкиваются с настоящим синтаксисом JS.
