Skip to content
This repository has been archived by the owner on Nov 23, 2023. It is now read-only.

Commit

Permalink
Merge pull request #32 from fastify/vue-ssr-perf
Browse files Browse the repository at this point in the history
fix(vue): hydration order, ssr performance
  • Loading branch information
galvez authored Jun 29, 2022
2 parents 2d615df + d483a53 commit 6c6104d
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 23 deletions.
32 changes: 18 additions & 14 deletions packages/fastify-dx-vue/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,23 +63,27 @@ export function createHtmlFunction (source, scope, config) {
// Decide which templating functions to use, with and without hydration
const headTemplate = context.serverOnly ? soHeadTemplate : unHeadTemplate
const footerTemplate = context.serverOnly ? soFooterTemplate : unFooterTemplate
// Decide whether or not to include the hydration script
if (!context.serverOnly) {
hydration = (
'<script>\n' +
`window.route = ${devalue(context.toJSON())}\n` +
`window.routes = ${devalue(routes.toJSON())}\n` +
'</script>'
)
}
// Render page-level <head> elements
const head = new Head(context.head).render()
// Create readable stream with prepended and appended chunks
const readable = Readable.from(generateHtmlStream({
body,
stream,
head: headTemplate({ ...context, head, hydration }),
footer: footerTemplate(context),
// TODO refactor generateHtmlStream to
// fix inner arrow function allocation
footer: () => footerTemplate({
...context,
// Decide whether or not to include the hydration script
...!context.serverOnly && {
hydration: (
'<script>\n' +
`window.route = ${devalue(context.toJSON())}\n` +
`window.routes = ${devalue(routes.toJSON())}\n` +
'</script>'
)
}
}),
}))
// Send out header and readable stream with full response
this.type('text/html')
Expand All @@ -88,12 +92,12 @@ export function createHtmlFunction (source, scope, config) {
}

export async function createRenderFunction ({ routes, create }) {
// Create convenience-access routeMap
const routeMap = Object.fromEntries(routes.toJSON().map((route) => {
return [route.path, route]
}))
// create is exported by client/index.js
return async function (req) {
// Create convenience-access routeMap
const routeMap = Object.fromEntries(routes.toJSON().map((route) => {
return [route.path, route]
}))
let stream = null
let body = null
// Creates main Vue component with all the SSR context it needs
Expand Down
2 changes: 1 addition & 1 deletion packages/fastify-dx-vue/server/stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export async function * generateHtmlStream ({ head, body, stream, footer }) {
yield chunk
}
}
yield footer
yield footer()
}
2 changes: 1 addition & 1 deletion packages/fastify-dx-vue/virtual/core.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { inject } from 'vue'
import { useRoute, createMemoryHistory, createWebHistory } from 'vue-router'

export const isServer = typeof process === 'object'
export const isServer = import.meta.env.SSR
export const createHistory = isServer ? createMemoryHistory : createWebHistory
export const serverRouteContext = Symbol('serverRouteContext')
export const routeLayout = Symbol('routeLayout')
Expand Down
6 changes: 5 additions & 1 deletion packages/fastify-dx-vue/virtual/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ export default async function create (ctx) {
const router = createRouter({ history, routes })
const layoutRef = ref(ctxHydration.layout ?? 'default')

instance.config.globalProperties.$isServer = isServer

instance.provide(routeLayout, layoutRef)
ctxHydration.state = reactive(ctxHydration.state)
if (!isServer) {
ctxHydration.state = reactive(ctxHydration.state)
}

if (isServer) {
instance.provide(serverRouteContext, ctxHydration)
Expand Down
2 changes: 1 addition & 1 deletion packages/fastify-dx-vue/virtual/layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</template>

<script>
import { defineAsyncComponent, inject } from 'vue'
import { inject } from 'vue'
import { routeLayout } from '/dx:core.js'
import * as DefaultLayout from '/dx:layouts/default.vue'
Expand Down
10 changes: 9 additions & 1 deletion packages/fastify-dx-vue/virtual/root.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ import Layout from '/dx:layout.vue'

<template>
<router-view v-slot="{ Component }">
<Suspense>
<template v-if="$isServer">
<Layout>
<component
:is="Component"
:key="$route.path"
/>
</Layout>
</template>
<Suspense v-else>
<Layout>
<component
:is="Component"
Expand Down
2 changes: 1 addition & 1 deletion packages/fastify-dx-vue/virtual/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async function hydrateRoutes (from) {
}
return window.routes.map((route) => {
route.loader = memoImport(from[route.id])
route.component = lazy(from[route.id])
route.component = () => route.loader()
return route
})
}
Expand Down
2 changes: 1 addition & 1 deletion starters/vue/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
<meta charset="utf-8">
<link rel="stylesheet" href="./base.css">
<!-- head -->
<!-- hydration -->
</head>
<body>
<main><!-- element --></main>
</body>
<!-- hydration -->
<script type="module" src="/dx:mount.js"></script>
</html>
12 changes: 11 additions & 1 deletion starters/vue/client/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<h1>Welcome to Fastify DX for Vue!</h1>
<h1>{{ message }}</h1>
<p><img :src="logo" /></p>
<ul class="columns-2">
<li><router-link to="/using-data">/using-data</router-link> demonstrates how to
Expand All @@ -19,7 +19,17 @@
</template>

<script setup>
import { isServer, useRouteContext } from '/dx:core.js'
import logo from '/assets/logo.svg'
const { state } = useRouteContext()
if (isServer) {
// State is automatically hydrated on the client
state.message = 'Welcome to Fastify DX for Vue!'
}
const message = state.message
</script>

<script>
Expand Down
10 changes: 9 additions & 1 deletion starters/vue/client/root.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ import Layout from '/dx:layout.vue'

<template>
<router-view v-slot="{ Component }">
<Suspense>
<template v-if="$isServer">
<Layout>
<component
:is="Component"
:key="$route.path"
/>
</Layout>
</template>
<Suspense v-else>
<Layout>
<component
:is="Component"
Expand Down

0 comments on commit 6c6104d

Please sign in to comment.