Vue
headless-prerender works with any client-rendered Vue 3 (or Vue 2) app using Vue Router in history mode. Your components are unchanged.
When you need it
Your index.html mounts into an empty element:
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>Non-JS crawlers see an empty #app. Prerendering returns the rendered markup.
Setup
Deploy the built app as static files.
Run the service:
bashheadless-prerender serve \ --port 3000 \ --allow-origin https://www.example.com \ --cache-ttl 300000
History mode and fallbacks
Vue Router history mode needs the server to serve index.html for unknown paths. Keep that fallback for humans; the prerender service loads the same URL in a browser, so it resolves the route the same way the client would.
Waiting for async data
If route components fetch data in onMounted / setup, the network-idle wait usually covers it. For slower cases:
headless-prerender serve --extra-wait 400Or use router.isReady() plus a global flag:
router.isReady().then(() => {
// optionally wait for your store to hydrate
(window as any).__PRERENDER_READY__ = true;
});Meta tags
Use @unhead/vue (or vue-meta for Vue 2) to set per-route <title> and <meta property="og:*">. The renderer captures the final <head>, so social previews work.
import { useHead } from "@unhead/vue";
useHead({
title: product.value.name,
meta: [
{ property: "og:title", content: product.value.name },
{ property: "og:description", content: product.value.summary },
{ property: "og:image", content: product.value.image },
],
});404 status codes
For a real 404, render a status-code meta tag in your not-found route and have the proxy honour it:
<script setup>
import { useHead } from "@unhead/vue";
useHead({ meta: [{ name: "prerender-status-code", content: "404" }] });
</script>Checklist
- [ ] History-mode fallback to
index.htmlin place - [ ]
--allow-originset - [ ]
--extra-waittuned for async route data - [ ] Per-route head metadata rendered client-side
- [ ] 404 routes marked
- [ ] Caching enabled