VueJs: ошибка с отображением на стороне сервера и Typescript
Я пытаюсь создать стек с помощью Server Side Rendering (SSR) и Typescript.
Все кажется прекрасным, но я получил ошибку: TypeError: Cannot read property 'render' of undefined
.
Вот полная трассировка стека:
TypeError: Cannot read property 'render' of undefined
at normalizeRender (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/vue-server-renderer/build.js:6621:19)
at render (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/vue-server-renderer/build.js:6840:5)
at Object.renderToString (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/vue-server-renderer/build.js:6871:9)
at /Users/shoun/Documents/repositories/vuejs-ssr-typescript/dist/server.js:16:14
at Layer.handle [as handle_request] (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/layer.js:95:5)
at /Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/index.js:281:22
at param (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/index.js:354:14)
TypeError: Cannot read property 'render' of undefined
at normalizeRender (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/vue-server-renderer/build.js:6621:19)
at render (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/vue-server-renderer/build.js:6840:5)
at Object.renderToString (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/vue-server-renderer/build.js:6871:9)
at /Users/shoun/Documents/repositories/vuejs-ssr-typescript/dist/server.js:16:14
at Layer.handle [as handle_request] (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/layer.js:95:5)
at /Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/index.js:281:22
at param (/Users/shoun/Documents/repositories/vuejs-ssr-typescript/node_modules/express/lib/router/index.js:354:14)
Вот моя конфигурация сервера:
import * as express from 'express';
import * as path from 'path';
import * as VueRender from 'vue-server-renderer';
import * as fs from 'fs-extra';
import app from './assets/app';
declare var __dirname;
// Get the HTML layout
const layout = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
// Create a renderer
const renderer = VueRender.createRenderer();
let server = express();
server.get('/hello', function (req, res) {
res.send('Hello World!');
});
server.use('/assets', express.static(path.join(__dirname, 'assets')));
// Handle all GET requests
server.get('*', function (request, response) {
// Render our Vue app to a string
renderer.renderToString(
// Create an app instance
app(),
// Handle the rendered result
function (error, html) {
// If an error occurred while rendering...
if (error) {
// Log the error in the console
console.error(error);
// Tell the client something went wrong
return response
.status(500)
.send('Server Error')
}
// Send the layout with the rendered app HTML
response.send(layout.replace('<div id="app"></div>', html))
}
)
});
let port = 4500;
server.listen(port, () => {
console.log(`App listening on ${port}`);
});
Вы можете найти исходный код в моем репозитории github: https://github.com/sichida/vuejs-ssr-typescript.
Я мог бы использовать некоторую помощь, потому что я застрял...
Большое спасибо!
Ответы
Ответ 1
Я проверил ваше репо и проблема на самом деле находится в файле src/assets/app.ts
, в функции createApp
вы возвращаете объект типа ComponentOptions
, но renderToString
берет объект типа Vue
.
На самом деле это может быть намного проще, чем у вас сейчас:
import * as Vue from 'vue';
let createApp = function () {
return new Vue({
props: ['message'],
template: '<span>{{ message }}</span>',
});
};
export default createApp;
И для этого вам нужно только вернуть новый экземпляр Vue
.
Ответ 2
Что я обнаружил, что для того, чтобы Vue что-то отображал, ему нужно одно:
-
render
свойство
-
template
свойство
- Быть
$mount()
ed
Теперь, если вы похожи на меня, и у вас было что-то подобное в вашем HTML:
<div id="app">
<navbar></navbar>
...
</div>
и используется для его монтирования как app.$mount('#app')
, , что вам нужно сделать:
- Переместите
<div id="app">
полностью с его содержимым в компонент (возможно, назовите его App.vue
?)
- Добавить свойство
render
в экземпляр Vue, например render: h => h(App)
, где App
- только что созданный компонент
- Используйте этот компонент непосредственно для SSR, т.е. верните его из своего
entry-server.js
или другого
- Сделайте
$mount
этот экземпляр в entry-client.js
для гидратации