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(
18 Object.assign(options, {
19 // for component caching
22 maxAge: 1000 * 60 * 15
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
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) => {
41 return fs.readFileSync(path.join(clientConfig.output.path, file), 'utf-8');
43 // We swallow the error because the next build could be fien
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) => {
58 stats = stats.toJson();
59 if (stats.errors.length) {
61 `Errors while compiling server webpack config (${stats.errors.length})`,
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);
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}`;
87 let readyPromise = Promise.resolve();
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
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
104 async function renderToString(...args) {
107 return renderer.renderToString(...args);
110 module.exports = renderToString;