Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Doc/Tuto] Example of prerendering for vue. #897

Closed
mathieutu opened this issue Oct 11, 2020 · 10 comments
Closed

[Doc/Tuto] Example of prerendering for vue. #897

mathieutu opened this issue Oct 11, 2020 · 10 comments
Labels
documentation Improvements or additions to documentation

Comments

@mathieutu
Copy link

mathieutu commented Oct 11, 2020

Hi,

I made a simple landing page with vue 3 and vuejs, and would like to prerender it for seo and performance (and usage with netlify form).

I was looking for an existing solution, but didn't find anything, so I've dug in the builder of vite and made my own script. I tried to make it as simple as possible, and at the end it's pretty straightforward, but I've spent few hours to understand vite and rollup build, and I think it can be of interest to some people (you can start from there for SSR too).

I share it in the issue to keep a record, but I think it can be good to add some documentation about prerendering and ssr with vite and vue3.

Please feel free to give me your feedbacks, so we can improve it.

Prerendering with vite and vue3

Update you main.js file

// main.js
import { createApp as createClientApp, createSSRApp } from 'vue'

import './assets/main.css'
import App from './App.vue'

const inBrowser = typeof window !== 'undefined'

// We export a function that will create a standard app in dev, but a ssr app for production.
// To enable hydration on the client, use createSSRApp instead of createApp to create your app instance (separate imports allows hydration logic to be tree-shakeable for apps that do not require hydration).

export const createApp = () => (
  process.env.NODE_ENV === 'production'
    ? createSSRApp(App)
    : createClientApp(App)
)

// When in browser, we create and mount the app like before.
if (inBrowser) {
  createApp().mount('#app')
}

Add a build.js file

const { ssrBuild, build } = require('vite')
const { resolve } = require('path')
const { writeFileSync, rmdirSync } = require('fs')
const renderer = require('@vue/server-renderer')

const build = async () => {
  const outDir = resolve(process.cwd(), 'dist')
  const tmpDir = resolve(process.cwd(), 'dist/tmp')

  // Classic client build. Output assets, and index.html. Returns chunks and generated html.
  const clientResult = await build({ outDir })

  // Build for server side (imports are replaced by requires, and no assets)
  await ssrBuild({
    outDir: tmpDir,

	// Important to keep the export createApp in the main.js. 
    rollupInputOptions: {
      input: { index: 'src/main.js' },
      preserveEntrySignatures: 'allow-extension',
    },
  })

  // We import our main.js createApp from the new server flavored built file.
  const { createApp } = require(tmpDir)

  // Render the html of the app, and insert it in the generated index.html built for client side.
  const content = await renderer.renderToString(createApp()) 
  const indexPath = resolve(outDir, 'index.html')
  const indexOutput = clientResult.html.replace(
    '<div id="app">',
    `<div id="app" data-server-rendered="true">${content}`,
  )

  // Write the new file and remove the server build, we don't need it anymore.
  writeFileSync(indexPath, indexOutput)

  rmdirSync(tmpDir, { recursive: true })

  console.log('🎉 Page generated!')
  process.exit()
}

build().catch((e) => {
  console.error(e)
  process.exit(1)
})

Update you build script.

-    "build": "cross-env NODE_ENV=production vite build"
+    "build": "cross-env NODE_ENV=production node build.js"

Have fun! 🎉 (and please share me your thoughts!)

Moreover, I've only one file here, but next step could be to generate several pages depending of routes.

@mathieutu mathieutu changed the title Prerendering for vue [Doc/Tuto] Example of prerendering for vue. Oct 11, 2020
@underfin underfin added the documentation Improvements or additions to documentation label Oct 12, 2020
@arpowers
Copy link
Contributor

arpowers commented Nov 9, 2020

@mathieutu thanks for posting this. Was helpful.

@frandiox
Copy link
Contributor

frandiox commented Nov 9, 2020

vite-ssr might be helpful in some cases.

@arpowers
Copy link
Contributor

arpowers commented Nov 9, 2020

@frandiox also took a look at your repo as well, also good. I've been struggling with some fringe issues like teleports in SSR (metatags), will report back on where things end up.

@mathieutu
Copy link
Author

Actually, I've just found there where some breaking changes in rc7 and rc9 which break the build process. You need to adapt it to the new versions.

@arpowers
Copy link
Contributor

@mathieutu @frandiox you SSR pros have thoughts on this issue? #972

@frandiox
Copy link
Contributor

@arpowers I'm far from pro 😂
That would be a nice feature but I personally don't need it right now. My approach is running SPA locally during development so there's no need to watch files and build for SSR until deployment. You can see the approach in Vitedge, perhaps you can try something similar for your app.

@arpowers
Copy link
Contributor

You don't think that it's fundamentally important to match your development and production environments?

Hydration and pre-fetching are error-prone enough where I don't feel comfortable developing without SSR.

@frandiox
Copy link
Contributor

@arpowers It is indeed important and I hope they support build watch at some point. However, Vite is still under development and I don't think we can do anything but wait (there are PRs open but not enough people to manage them). In the meantime, you can go with SPA approach at least if this issue is stopping you from building your app 🤔

@arpowers
Copy link
Contributor

It's for a next-gen framework, Factor 7

@yyx990803
Copy link
Member

Closing (stale)

@github-actions github-actions bot locked and limited conversation to collaborators Jul 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

5 participants