VueJs:服务器端渲染和 Typescript 出错

Posted

技术标签:

【中文标题】VueJs:服务器端渲染和 Typescript 出错【英文标题】:VueJs: Error with server side rendering and Typescript 【发布时间】:2017-09-03 18:09:36 【问题描述】:

我正在尝试使用服务器端渲染 (s-s-r) 和 Typescript 构建堆栈。 一切似乎都很好,但我得到了错误:TypeError: Cannot read property 'render' of undefined。 这是完整的堆栈跟踪:

TypeError: Cannot read property 'render' of undefined
    at normalizeRender (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/vue-server-renderer/build.js:6621:19)
    at render (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/vue-server-renderer/build.js:6840:5)
    at Object.renderToString (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/vue-server-renderer/build.js:6871:9)
    at /Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/dist/server.js:16:14
    at Layer.handle [as handle_request] (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/layer.js:95:5)
    at /Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/index.js:281:22
    at param (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/index.js:354:14)
TypeError: Cannot read property 'render' of undefined
    at normalizeRender (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/vue-server-renderer/build.js:6621:19)
    at render (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/vue-server-renderer/build.js:6840:5)
    at Object.renderToString (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/vue-server-renderer/build.js:6871:9)
    at /Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/dist/server.js:16:14
    at Layer.handle [as handle_request] (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/layer.js:95:5)
    at /Users/shoun/Documents/repositories/vuejs-s-s-r-typescript/node_modules/express/lib/router/index.js:281:22
    at param (/Users/shoun/Documents/repositories/vuejs-s-s-r-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's 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-s-s-r-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')一样挂载,你需要做的是:

&lt;div id="app"&gt; 及其内容全部移动到组件中(可能称其为App.vue?) 向 Vue 实例添加 render 属性,例如 render: h =&gt; h(App),其中 App 是您刚刚创建的组件 将该组件直接用于 s-s-r,即从您的 entry-server.js 或其他任何地方返回它 在entry-client.js 中执行$mount 那个实例以补充水分

【讨论】:

以上是关于VueJs:服务器端渲染和 Typescript 出错的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript 2、React JS 和 Express 服务器端渲染问题

Vuejs184-Vue 服务端渲染实践 ——Web应用首屏耗时最优化方案

仅使用 Nuxt 进行服务器端渲染一页

VueJs Axios 和 Typescript

具有 vue-class-components 和 typescript 的 vuejs 实例属性时出错

哪种服务器适用于 VueJS [关闭]