· 2 min read
CSP without inline scripts: what had to be switched off in Nuxt
Why a strict script-src self policy breaks static Nuxt, which three steps made the site compatible, and the build check that keeps it so.
The policy script-src 'self' without unsafe-inline closes a whole class of XSS: any inline script simply does not run. You pay for it in compatibility with tools that like to inject code into HTML.
What Nuxt does by default
A static build puts an inline script with window.__NUXT__ and an importmap into the page, and inlines styles. Under a strict policy the browser blocks them and the page is left without hydration: the markup is there, the interactivity is not. The portfolio site itself had this: the fixed CSP on the VPS blocked hydration until the importmap was dropped from the export and the Nuxt config was moved into a file.
What was done in landscape-bureau-nuxt
experimental.entryImportMapis off innuxt.config.ts.- Inline styles are off:
features.inlineStyles: false. - A
postgeneratescript moveswindow.__NUXT__into a file_nuxt/inline-<hash>.js.
So it does not come back
check-security inspects the generated HTML and fails the build if it finds an executable inline script, a <style> or style="". The same trick is in the React project bike-workshop-react (the linter bans style={}) and in ceramics-vue.
The result: CSP script-src 'self' and style-src 'self', HSTS, nosniff and frame-ancestors 'none' work together with a live site on Cloudflare Pages. This is a concept with a fictional bureau, and I did not run Lighthouse.