Whilst attempting to convert my blog to use a Content Security Policy (CSP) I was inundated with CSP violations relating to unsafe-eval
that was nailed down to the use of the alpine.js package. Now Alpine.js does have a CSP friendly build but it is yet (at the time of writing) to be published to npm. The instructions require you to build and distribute your own copy of alpine.js which isn't ideal but once that hurdle has been overcome it is possible to convert our usage to be CSP friendly. The instructions on alpine.js are rather light in detail about what this entails and so I will detail some of my own findings.
Starting off
The navbar for this site is one of the controls utilising alpine.js and this is what it looked like before conversion.
<nav
x-data="{ isOpen: false }"
class="..."
@keydown.escape="isOpen = false"
@click.away="isOpen = false"
>
<!--Toggle button (hidden on large screens)-->
<button
@click="isOpen = !isOpen"
type="button"
class="..."
:class="{ 'transition transform-180': isOpen }"
aria-label="Menu"
>
<svg
class="h-6 w-6 fill-current"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
>
<path
x-show="isOpen"
fill-rule="evenodd"
clip-rule="evenodd"
d="..."
/>
<path
x-show="!isOpen"
fill-rule="evenodd"
d="..."
/>
</svg>
</button>
...
</nav>
Identification of the unsafe-inline
violations
The following items cause the unsafe-inline
violation to fire and will need moving to external APIs as detailed by alpine.js
{ isOpen: false }
!isOpen
isOpen = false
isOpen = !isOpen
{ 'transition transform-180': isOpen }
Creating and applying the external API
Following the initial advice and some investigation (okay some judicious logging) the following API was created
Alpine.data("navbar", () => ({
isOpen: false,
isClosed() {
return !this.isOpen;
},
closeNavbar() {
this.isOpen = false;
},
toggleNavbar() {
this.isOpen = !this.isOpen;
},
generateNavbarClasses() {
return { transition: this.isOpen, "transform-180": this.isOpen };
},
...
}));
and wired into the html like so
<nav
x-data="navbar"
class="..."
@keydown.escape="closeNavbar"
@click.away="closeNavbar"
>
<!--Toggle button (hidden on large screens)-->
<button
@click="toggleNavbar"
type="button"
class="..."
:class="generateNavbarClasses"
aria-label="Menu"
>
<svg
class="h-6 w-6 fill-current"
xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24"
>
<path
x-show="isOpen"
fill-rule="evenodd"
clip-rule="evenodd"
d="..."
/>
<path
x-show="isClosed"
fill-rule="evenodd"
d="..."
/>
</svg>
</button>
...
</nav>
Repeating the above steps for other areas now means the site is CSP friendly and unsafe-eval
does not need to be applied to the Content Security Policy for the site to work.
As always, your feedback is appreciated
Photo by Stephan Seeber on Unsplash