Tutorial

Prerender Vue.js Apps with prerender-spa-plugin v3

Published on July 30, 2017
Default avatar

By Joshua Bemenderfer

Prerender Vue.js Apps with prerender-spa-plugin v3

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

SSR (Server-Side Rendering) gets all the love these days. Speeding up initial-page-loads by sending a full HTML page instead of a skeleton with a few scripts is a really great idea. There’s a catch though. SSR is hard. There are a lot of things to worry about and it breaks easily. The truth is, in most cases, SSR is overkill. You can gain most of the benefits of SSR in your Vue.js app by using prerender-spa-plugin to pre-render your site to static pages at build time.

Pre-rendering is sort of like Server-Side Rendering mixed with static site generation, but simpler. You tell the pre-renderer which routes you want, then it fires up a browser or equivalent environment, loads the pages, and dumps the resulting HTML into file paths that match the routes. This gives you fully-rendered static pages, resulting in faster perceived load times and no need for odd hacks for deployment on static site servers. Once the JavaScript finishes loading, your app will continue to work as normal.

Pre-rendering isn’t a silver bullet though, don’t use it if you have hundreds of routes, or need to pre-render dynamic content without placeholders.

Anyway, enough chit-chat. Let’s see how to do it.

Note: prerender-spa-plugin 3.0 is still in alpha, so API usage may change in the future. I’ll try to keep this article up-to-date. See the official documentation if something here doesn’t work properly.

This guide assumes you’ve set up a quick projet with vue-cli with the webpack-simple template, though it’s pretty much the same for any webpack setup.

Usage

Install prerender-spa-plugin in your Vue.js project.

# Yarn
$ yarn add prerender-spa-plugin@next -D
# or NPM
$ npm install prerender-spa-plugin@next --save-dev

Then, in webpack.config.js, require() the relevant package.

webpack.config.js (Partial)
var path = require('path')
var webpack = require('webpack')
// Add these
const PrerenderSPAPlugin = require('prerender-spa-plugin')
// Renders headlessly in a downloaded version of Chromium through puppeteer
const PuppeteerRenderer = PrerenderSPAPlugin.PuppeteerRenderer

...

module.exports = {
  ...
  plugins: [
    new PrerenderSPAPlugin({
      staticDir: __dirname, // The path to the folder where index.html is.
      routes: ['/'], // List of routes to prerender.
      renderer: new PuppeteerRenderer()
    })
  ]
}

...

Now, after you run webpack again, you should find that index.html in the project root now contains the rendered content of the page as well.

Switching Renderers

PuppeteerRenderer is great… except when it isn’t. It’s not super fast and can’t render a ton of pages without hogging a ton of system resources.

If you need to render hundreds or thousands of pages, JSDOMRenderer might be a better choice. jsdom fakes a browser environment inside of Node.js and mocks as much as it can. It does a fairly good job, but can’t handle everything. You may need to adjust your app to work around certain new or unusual APIs that might not be present.

JSDOMRenderer doesn’t come with prerender-spa-plugin by default. You’ll have to install it with.

# Yarn
$ yarn add @prerenderer/renderer-jsdom -D
# NPM
$ npm install @prerenderer/renderer-jsdom --save-dev

JSDOMRenderer Example:

var path = require('path')
var webpack = require('webpack')
// Add these
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const JSDOMRenderer = require('@prerenderer/renderer-jsdom')

...

module.exports = {
  ...
  plugins: [
    new PrerenderSPAPlugin({
      staticDir: __dirname, // The path to the folder where index.html is.
      routes: ['/'], // List of routes to prerender.
      renderer: new JSDOMRenderer()
    })
  ]
}

...

If you wanted, it’s fairly trivial to implement your own renderer as well. See the official documentation for more information.

Configuration

Delayed rendering

You don’t always want to render the page right off. Sometimes you want to wait for something to happen.

All three renderers can can wait for three different triggers:

Wait for an element to exist:

renderer: new PuppeteerRenderer({
  // Wait to render until the element specified is detected with document.querySelector.
  renderAfterElementExists: '#app'
})

Wait for a document event to be fired:

You can trigger an event in your app with document.dispatchEvent(new Event('my-document-event'))

renderer: new PuppeteerRenderer({
  // Wait to render until a specified event is fired on the document.
  renderAfterDocumentEvent: 'my-document-event'
})

Wait for a specified amount of time:

renderer: new PuppeteerRenderer({
  // Renders after 5000 milliseconds. (5 seconds.)
  renderAfterTime: 5000
})

Variable injection

The renderers can also inject a variable into the global scope before your app scripts run. This is useful if you need to pass something to your app or change behavior depending on whether or not the page is being prerendered.

renderer: new PuppeteerRenderer({
  // injectProperty: '__PRERENDER_INJECTED'
  // You can change the property added to window. The default is window.__PRERENDER_INJECTED.
  // Inject can be any object that is JSON.stringify-able.
  inject: {
    nestLocation: 'bayou'
  }
})

Now in your app, window.__PRERENDER_INJECTED.nestLocation === 'bayou'

That’s about it for now! Enjoy pre-rendering!

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Joshua Bemenderfer

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel