Vue.js SPA Preset
Preset file: presets/vue-spa.toml
Works with Vue 3 + Vite, Vue 2 + CLI, and Nuxt in CSR mode.
Overview
Vue SPAs mount components into a <div id="app"> element. Vue uses v-cloak directives to hide content until the app is mounted, and scoped CSS generates data-v-* hash attributes on elements.
Key Configuration
[render]
wait_for = "networkidle"
timeout_secs = 15
post_wait_js = """
document.querySelectorAll('[v-cloak]').forEach(el => el.removeAttribute('v-cloak'));
"""
[render.postprocess]
enabled = true
strip_scripts = true
strip_noscript = true
strip_comments = true
strip_event_handlers = true
strip_hydration_attrs = true # Removes data-v-*, data-server-rendered
resolve_lazy_images = true
v-cloak Removal
Vue's v-cloak directive hides elements until the Vue instance is mounted. In rendered output, v-cloak may still be present if Vue's initialization is slightly delayed. The post_wait_js script removes it after rendering completes:
document.querySelectorAll('[v-cloak]').forEach(el => el.removeAttribute('v-cloak'));
Without this, elements with v-cloak and a corresponding CSS rule ([v-cloak] { display: none }) would be invisible in the rendered HTML, even though all content has been rendered into the DOM.
Hydration Attribute Stripping
With strip_hydration_attrs = true, PRISM removes:
| Attribute | Purpose in Vue | Why It's Stripped |
|---|---|---|
data-v-* | Scoped CSS hash identifiers | Only meaningful with Vue's scoped <style> processing |
data-server-rendered | Marks SSR-rendered content for hydration | Only needed for client-side hydration matching |
Before:
<div data-v-abc123 data-server-rendered="true">
<p data-v-abc123>Hello World</p>
</div>
After:
<div>
<p>Hello World</p>
</div>
Nuxt CSR Mode
For Nuxt.js in client-side rendering mode (SPA mode), this preset works directly. The route exclusions include /_nuxt/** to skip Nuxt's build assets:
[routes]
exclude = [
"/api/**",
"/_nuxt/**", "/static/**", "/assets/**",
# ... asset extensions
]
If your Nuxt app uses SSR or SSG, PRISM is less necessary since Nuxt already renders HTML server-side. PRISM can still help with pages that have heavy client-side data fetching after initial SSR.
Full Preset
[render]
wait_for = "networkidle"
timeout_secs = 15
post_wait_js = """
document.querySelectorAll('[v-cloak]').forEach(el => el.removeAttribute('v-cloak'));
"""
[render.postprocess]
enabled = true
strip_scripts = true
strip_noscript = true
strip_comments = true
strip_event_handlers = true
strip_hydration_attrs = true
resolve_lazy_images = true
[render.content_validation]
enabled = true
min_text_length = 100
require_title = true
min_html_bytes = 1024
[routes]
include = ["/**"]
exclude = [
"/api/**",
"**/*.js", "**/*.css", "**/*.json", "**/*.xml",
"**/*.png", "**/*.jpg", "**/*.gif", "**/*.svg", "**/*.ico",
"**/*.woff", "**/*.woff2", "**/*.ttf", "**/*.wasm", "**/*.map",
"/_nuxt/**", "/static/**", "/assets/**",
"/manifest.json", "/sw.js", "/robots.txt", "/sitemap.xml",
]