Интерпретатор выражений
По умолчанию парсер Vega генерирует код для разобранных выражений Vega, а среда выполнения создаёт из него функции JavaScript с помощью конструктора Function. Хотя парсер Vega выполняет собственные проверки безопасности, создание функций из исходного кода во время работы нарушает политики, защищающие от межсайтового скриптинга (XSS), например директиву script-src без разрешения unsafe-eval.
Начиная с версии 5.13.0 Vega поддерживает интерпретацию выражений, совместимую с политикой безопасности содержимого (Content Security Policy, CSP). Пакет vega-interpreter предоставляет подключаемый интерпретатор: он обходит абстрактное синтаксическое дерево (AST) выражения и последовательно выполняет его операции. Интерпретатор позволяет соблюдать CSP, но может снизить производительность. В тестах начального разбора и обработки потока данных он в среднем примерно на 10% медленнее. При интерактивных обновлениях разница может быть больше: в них обычно больше выражений, а однократные затраты на разбор через Function распределяются по последующим обновлениям.
Чтобы использовать интерпретатор, выполните три шага:
- Загрузите модуль
vega-interpreterотдельным тегомscript, как показано ниже, или включите его в собственную сборку Vega. - Вызовите парсер Vega с параметром
{ast: true}, чтобы в результат были включены разобранные синтаксические деревья. - Передайте интерпретатор в конструктор представления Vega (
View). Среда выполнения воспользуется альтернативным вычислителем выражений.
Пример
В следующем примере CSP задана через метатег HTML. В большинстве случаев политику задаёт сервер.
Исходный HTML-код страницы (ключевое слово CSP 'self' обязательно заключается в одинарные кавычки):
<head>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' cdn.jsdelivr.net" />
<script src="https://cdn.jsdelivr.net/npm/vega@6"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-interpreter@1"></script>
</head>
<body>
<div id="view"></div>
<script src="main.js"></script>
</body>
Исходный код main.js. Скрипт вынесен в отдельный файл, поскольку многие политики CSP запрещают unsafe-inline.
let view;
fetch('https://vega.github.io/vega/examples/bar-chart.vg.json')
.then(res => res.json())
.then(spec => render(spec))
.catch(err => console.error(err));
function render(spec) {
// Разобрать спецификацию Vega и включить AST в результат
// Вторым аргументом передать null вместо конфигурации
const runtime = vega.parse(spec, null, { ast: true });
// Передать интерпретатор выражений в конструктор View через параметр expr
view = new vega.View(runtime, {
expr: vega.expressionInterpreter,
renderer: 'svg', // способ отрисовки: canvas или svg
container: '#view', // родительский контейнер DOM
hover: true // включить обработку наведения
});
return view.runAsync();
}