Vue Tour
Routing
Similarly to Nuxt,
we define a new page by creating a new +Page.vue
file.
<!-- /pages/index/+Page.vue -->
<!-- Environment: browser and server -->
<template>
This page is rendered to HTML and interactive: <Counter />
</template>
<script setup>
import Counter from '../../components/Counter.vue'
</script>
By default, Vike does Filesystem Routing.
FILESYSTEM URL
/pages/index/+Page.vue /
/pages/about/+Page.vue /about
We can also define a page's route with a Route String (for parameterized routes such as /movies/@id
) or a Route Function (for full programmatic flexibility).
// /pages/index/+route.js
// Note how the two files share the same folder `/pages/index/`; this is how Vike
// knows that `/pages/index/+route.js` defines the route of `/pages/index/+Page.vue`.
// Route Function
export default pageContext => pageContext.urlPathname === '/'
// If we don't create a `+route.js` file then Vike does Filesystem Routing
Render Control
Unlike Nuxt, we control how our pages are rendered.
// /renderer/+onRenderHtml.js
// Environment: server
import { createSSRApp, h } from 'vue'
import { renderToString } from '@vue/server-renderer'
import { escapeInject, dangerouslySkipEscape } from 'vike/server'
export { onRenderHtml }
async function onRenderHtml(pageContext) {
const { Page, data } = pageContext
const app = createSSRApp({
render: () => h(Page, data)
})
const appHtml = await renderToString(app)
const title = 'Vite SSR'
return escapeInject`<!DOCTYPE html>
<html>
<head>
<title>${title}</title>
</head>
<body>
<div id="app">${dangerouslySkipEscape(appHtml)}</div>
</body>
</html>`
}
// /renderer/+onRenderClient.js
// Environment: browser
import { createSSRApp, h } from 'vue'
export { onRenderClient }
async function onRenderClient(pageContext) {
const { Page, data } = pageContext
const app = createSSRApp({
render: () => h(Page, data)
})
app.mount('#app')
}
You may see
import { createSSRApp, h } from 'vue'
for the first time, but every SSR app actually usescreateSSRApp
andh
.Nuxt abstracts this away from us and gives us a slightly faster getting started. But this also means that we lose control over a central piece of our app architecture and we'll eventually lose more time circumventing Nuxt's limiting black box.
This control enables us to easily and naturally integrate any tool we want (Vuex, GraphQL, Service Worker, ...).
Note how we defined the files onRenderClient.js
and onRenderHtml.js
in a directory called /renderer/
: that way, we tell Vike to apply the onRenderHtml()
and onRenderClient()
hooks to all our pages.
This means we can now create a new page just by defining a new +Page.jsx
file (the +route.js
file is optional).
Plus files in /renderer/
can be overridden. For example, we can override the onRenderHtml()
and onRenderClient()
hooks for rendering some of
our pages with a completely different UI framework such as React.
Data Fetching
Let's now have a look at how to fetch data.
<!-- /pages/star-wars/movie/+Page.vue -->
<!-- Environment: browser and server -->
<template>
<h1>{{movie.title}}</h1>
<p>Release Date: {{movie.release_date}}</p>
<p>Director: {{movie.director}}</p>
</template>
<script lang="js">
const data = ['movie']
export default { props: data }
</script>
// /pages/star-wars/movie/+route.js
// Environment: server
// Route String
export default '/star-wars/@movieId'
// /pages/star-wars/movie/+data.js
// Environment: server
import fetch from 'node-fetch'
export async function data(pageContext) {
// The route parameter of `/star-wars/@movieId` is available at `pageContext.routeParams`
const { movieId } = pageContext.routeParams
// By default, +data.js files are loaded and executed only on the server-side
// which means we can use SQL/ORM queries here.
const response = await fetch(`https://star-wars.brillout.com/api/films/${id}.json`)
let movie = await response.json()
// Our render and hydrate functions we defined earlier pass `pageContext.data` to
// the root Vue component `Page`; this is where we define it.
return {
movie
}
}
That's it for the tour and we have actually already seen most of Vike's interface; not only is Vike flexible but it's also simple to use!