Перейти к содержимому

Политика безопасности содержимого (CSP)

Чтобы Alpine мог выполнять простые строки из HTML-атрибутов как выражения JavaScript, например x-on:click="console.log()", ему необходимо использовать утилиты, нарушающие принцип «unsafe-eval» Политики безопасности содержимого, которую некоторые приложения могут применять в целях безопасности.

Чтобы приспособиться к средам, где этот CSP необходим, Alpine предлагает альтернативную сборку, которая не нарушает «unsafe-eval», но имеет более строгий синтаксис.

Установка

Вы можете использовать эту сборку, включив её в тег <script> или установив с помощью менеджера пакетов.

Через CDN

Вы можете включить CDN этой сборки в виде тега <script>, как это делается в стандартной сборке Alpine:

<!-- Ядро Alpine, дружественное к CSP -->
<script
defer
src="https://cdn.jsdelivr.net/npm/@alpinejs/csp@3/dist/cdn.min.js"
></script>

Через менеджер пакетов

Вы можете установить эту сборку для использования внутри вашего пакета следующим образом:

Окно терминала
npm add @alpinejs/csp

Затем инициализируйте её из вашего пакета:

import Alpine from '@alpinejs/csp';
window.Alpine = Alpine;
window.Alpine.start();

Пример использования

Чтобы дать представление о том, как может выглядеть использование сборки CSP, вот копируемый HTML-файл с работающим компонентом счётчика, использующим обычную настройку CSP:

<html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'nonce-a23gbfz9e'"
/>
<script
defer
nonce="a23gbfz9e"
src="https://cdn.jsdelivr.net/npm/@alpinejs/csp@3/dist/cdn.min.js"
></script>
</head>
<body>
<div x-data="counter">
<button x-on:click="count++"><span x-text="count"></span></button>
</div>
<script nonce="a23gbfz9e">
document.addEventListener('alpine:init', () => {
Alpine.data('counter', () => {
return {
count: 1,
increment() {
this.count++;
},
};
});
});
</script>
</body>
</html>

Ограничения API

Поскольку Alpine больше не может интерпретировать строки как обычный JavaScript, ему приходится разбирать и конструировать из них JavaScript-функции вручную.

В связи с этим ограничением для регистрации объектов x-data необходимо использовать Alpine.data, а на свойства и методы из него ссылаться только по ключу.

Например, такой встроенный компонент не будет работать.

<!-- Плохо -->
<div x-data="{ count: 1 }">
<button @click="count++">Увеличить</button>
<span x-text="count"></span>
</div>

Однако, если разбить выражения на внешние API, то для сборки CSP будет справедливо следующее:

<!-- Хорошо -->
<div x-data="counter">
<button @click="increment">Увеличить</button>
<span x-text="count"></span>
</div>
Alpine.data('counter', () => ({
count: 1,
increment() {
this.count++;
},
}));

Сборка CSP поддерживает доступ к вложенным свойствам (аксессорам свойств) с использованием точечной нотации.

<!-- Это тоже работает -->
<div x-data="counter">
<button @click="foo.increment">Увеличить</button>
<span x-text="foo.count"></span>
</div>
Alpine.data('counter', () => ({
foo: {
count: 1,
increment() {
this.count++
},
},
}))