Merge branch 'hotfix/21.56.9' into master
[gitter.git] / server / handlers / renderers / vue-ssr-renderer.js
blobee674b4feda7645b9275cbdcb73dc36352bd5f96
1 'use strict';
3 const Promise = require('bluebird');
4 const path = require('path');
5 const { createBundleRenderer } = require('vue-server-renderer');
6 const LRU = require('lru-cache');
8 const env = require('gitter-web-env');
9 const logger = env.logger;
11 // Default to production unless we know for sure we are in dev
12 const IS_PRODUCTION = process.env.NODE_ENV !== 'dev';
14 function createRenderer(bundle, options) {
15   // https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/README.md#why-use-bundlerenderer
16   return createBundleRenderer(
17     bundle,
18     Object.assign(options, {
19       // for component caching
20       cache: LRU({
21         max: 1000,
22         maxAge: 1000 * 60 * 15
23       }),
24       // this is only needed when vue-server-renderer is npm-linked
25       basedir: path.resolve(__dirname, '../../../output/assets/js/'),
26       // recommended for performance
27       runInNewContext: false
28     })
29   );
32 function setupDevServer(bundleUpdatedCallback) {
33   const webpack = require('webpack'); // eslint-disable-line node/no-unpublished-require
34   const MFS = require('memory-fs'); // eslint-disable-line node/no-unpublished-require
36   const clientConfig = require('../../../public/js/webpack.config');
37   const serverConfig = require('../../../public/js/webpack.server.config');
39   const readFile = (fs, file) => {
40     try {
41       return fs.readFileSync(path.join(clientConfig.output.path, file), 'utf-8');
42     } catch (err) {
43       // We swallow the error because the next build could be fien
44       logger.error(err);
45     }
46   };
48   const initialCompileDonePromise = new Promise(resolve => {
49     // watch and update server renderer
50     const serverCompiler = webpack(serverConfig);
51     const mfs = new MFS();
52     serverCompiler.outputFileSystem = mfs;
53     serverCompiler.watch({}, (err, stats) => {
54       if (err) {
55         logger.error(err);
56         throw err;
57       }
58       stats = stats.toJson();
59       if (stats.errors.length) {
60         logger.error(
61           `Errors while compiling server webpack config (${stats.errors.length})`,
62           stats.errors
63         );
64         return;
65       }
67       // Read the bundle generated by vue-ssr-webpack-plugin
68       const bundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json'));
70       bundleUpdatedCallback(bundle);
71       resolve();
72     });
73   });
75   return initialCompileDonePromise;
78 // https://ssr.vuejs.org/api/#template
79 // https://ssr.vuejs.org/guide/build-config.html#manual-asset-injection
80 const rendererTemplate = (result, context) => {
81   const stateHtml = context.renderState();
83   return `${stateHtml}${context.styles}${result}`;
86 let renderer;
87 let readyPromise = Promise.resolve();
88 if (IS_PRODUCTION) {
89   // eslint-disable-next-line node/no-unpublished-require, node/no-missing-require
90   const bundle = require('../../../output/assets/js/vue-ssr-server-bundle.json');
91   renderer = createRenderer(bundle, {
92     template: rendererTemplate
93   });
94 } else {
95   // In development: setup the dev server with watch and hot-reload,
96   // and create a new renderer on bundle update.
97   readyPromise = setupDevServer(bundle => {
98     renderer = createRenderer(bundle, {
99       template: rendererTemplate
100     });
101   });
104 async function renderToString(...args) {
105   await readyPromise;
107   return renderer.renderToString(...args);
110 module.exports = renderToString;