I have been closely trying to follow this Vue SSR guide and in that example the author has placed his Express routes within a file called server.js
. Simply for organisation purposes, I wish to keep my Express routes in a router.express.js
file within my src/router
folder instead of in the root file of server.js
.
So this is a cutdown version of my router.express.js
file:
const vueServerRenderer = require('vue-server-renderer');
const setupDevServer = require('../../build/setup-dev-server'); //webpack dev config
const express = require('express');
const app = express();
const router = express.Router();
const createRenderer = (serverBundle) =>
vueServerRenderer.createBundleRenderer(serverBundle, {
runInNewContext: false,
template: fs.readFileSync(path.resolve(__dirname, '../index.html'), 'utf-8')
});
let renderer;
if (process.env.NODE_ENV === 'development') {
setupDevServer(app, (serverBundle) => {
renderer = createRenderer(serverBundle);
});
} else {
renderer = createRenderer(require('../../dist/vue-ssr-server-bundle.json'));
}
router.get('/', async function (req, res) {
const context = {
url: req.params['0'] || '/'
};
let html;
try {
html = await renderer.renderToString(context);
} catch (error) {
if (error.code === 404) {
return res.status(404).send('404 | Page Not Found');
}
return res.status(500).send('500 | Internal Server Error');
}
res.end(html);
});
module.exports = router;
The problem is that I also need the vue-server-renderer
code to be in the server.js
file. I would then make the app require
the router.express.js
file so the Express routes work like this:
const vueServerRenderer = require('vue-server-renderer');
const setupDevServer = require('../../build/setup-dev-server'); //webpack dev config
const app = express();
const createRenderer = (serverBundle) =>
vueServerRenderer.createBundleRenderer(serverBundle, {
runInNewContext: false,
template: fs.readFileSync(path.resolve(__dirname, '../index.html'), 'utf-8')
});
let renderer;
if (process.env.NODE_ENV === 'development') {
setupDevServer(app, (serverBundle) => {
renderer = createRenderer(serverBundle);
});
} else {
renderer = createRenderer(require('../../dist/vue-ssr-server-bundle.json'));
}
app.use(require('./router/express.router.js'));
Whenever I do this, I get a Webpack error stating that
WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema. - configuration.entry'app' should be a string.
If I remove the vue-server-renderer
code from server.js
then it runs fine. But the reason for having that code within server.js
is so that the development environment works properly. Basically if the code is not in server.js
then I cannot use hot-reloading or anything.
If I get rid of router.express.js
and put all that code in server.js
including the routes, then it all works perfectly including my development environment.
Why can I not (or rather how can I) keep my Express routes in a separate file and still have the vue-server-renderer
stuff work?
Update: setup-dev-server.js
file:
const setupDevServer = (app, onServerBundleReady) => {
const webpack = require('webpack');
const MFS = require('memory-fs');
const path = require('path');
const clientConfig = require('./webpack.client.config');
const serverConfig = require('./webpack.ssr.config');
// additional client entry for hot reload
clientConfig.entry.app = ['webpack-hot-middleware/client', clientConfig.entry.app];
const clientCompiler = webpack(clientConfig);
// setup dev middleware
app.use(require('webpack-dev-middleware')(clientCompiler, {
publicPath: clientConfig.output.publicPath,
serverSideRender: true,
logLevel: 'silent',
}));
// setup hot middleware
app.use(require('webpack-hot-middleware')(clientCompiler));
// watch src files and rebuild SSR bundle
global.console.log('Building SSR bundle...');
const serverCompiler = webpack(serverConfig);
const mfs = new MFS();
serverCompiler.outputFileSystem = mfs;
serverCompiler.watch({}, (error, stats) => {
if (error) throw error;
global.console.log(
`${stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
})}\n\n`
);
if (stats.hasErrors()) {
console.error(stats.compilation.errors);
throw new Error(stats.compilation.errors);
}
// read bundle generated by vue-ssr-webpack-plugin
const bundle = JSON.parse(
mfs.readFileSync(path.join(clientConfig.output.path, 'vue-ssr-server-bundle.json'), 'utf-8')
);
onServerBundleReady(bundle);
});
};
module.exports = setupDevServer;
1) Inside of your 'router.express.js' file write:
module.exports = router;
at the bottom of the file.2) Inside of your 'server.js' file write:
const router = require('./router/express.router.js');
at the top of the file.3) And now where you used to have
app.use(require('./router/express.router.js'));
replace that withapp.use(router);
4) At the top of 'server.js' write
const vueSsrBundle = require('../../dist/vue-ssr-server-bundle.json')
5) Lastly replace
renderer = createRenderer(require('../../dist/vue-ssr-server-bundle.json')
Withrenderer = createRenderer(vueSsrBundle)
EDIT the issue you are facing is on this line And probably related to the file 'app.js' or 'client-entry-js'