0

I have a working Vue app in my dist directory: when served by a server, everything works fine.

When I try to add server-side rendering using vue-server-renderer, it doesn't work. The page loads, but it isn't being rehydrated properly: most event listeners haven't been added.

No errors are thrown. I'm using the standalone build, Vue 2.1.3, and vue-server-renderer 2.1.3. NODE_ENV is set to development.

Here's my server code:

require('dotenv').config();

const fs = require('fs');
const path = require('path');

const layout = fs.readFileSync('./dist/index.html', 'utf8');

const contentMarker = '<div id="app"></div>';
const contentIndex = layout.indexOf(contentMarker);
const layoutHead = layout.slice(0, contentIndex);
const layoutTail = layout.slice(contentIndex + contentMarker.length);

const express = require('express');
const server = express();

server.use('/static', express.static('./dist/static'));

const bundle = fs.readFileSync('./dist/static/js/app.js', 'utf-8');
const renderer = require('vue-server-renderer').createBundleRenderer(bundle);

server.get('*', (req, res) => {
  res.setHeader('Content-Type', 'text/html');

  const renderStream = renderer.renderToStream({ url: req.url });

  renderStream.once('data', () => {
    res.write(layoutHead);
  });

  renderStream.on('data', chunk => {
    res.write(chunk);
  });

  renderStream.on('end', () => {
    res.end(layoutTail);
  });

  renderStream.on('error', err => {
    if (err && err.code === '404') {
      res.status(404).end('404 | Page Not Found');
      return;
    }

    res.status(500).end('500 Error');
    console.error(err);
  });
});

server.listen(8080, (err) => {
  if (err) {
    throw err;
  }

  console.log('Server is running at http://localhost:8080/');
});
callumacrae
  • 8,185
  • 8
  • 32
  • 49

1 Answers1

0

I figured it out: in this case, the problem was that contentMarker should have been <div id=app></div>, without the quotes: the HTML was being minified by webpack.

The result of not doing this is that the entire layout file was being output, and then the rendered Vue template: this meant that the Vue JS was being loaded before the template, so there was no document to rehydrate.

A warning might have been useful, though!

callumacrae
  • 8,185
  • 8
  • 32
  • 49