使用 ASP.NET Core 2 的服务器端渲染 Vue

Server Side Rendering Vue with ASP.NET Core 2

我正在尝试了解在使用 aspnet core 时使用 vuejs 进行服务器端渲染的用法和限制。

我用了this starter kit for aspnet core and vuejs to setup a simple vue site, which is running based on the code here: https://github.com/selaromdotnet/aspnet-vue-ssr-test/tree/master

然后我修改了项目以更新 aspnet-prerendering 并添加了 vue-server-renderer,编译了一个源代码的大杂烩来拼凑这个更新:https://github.com/selaromdotnet/aspnet-vue-ssr-test/tree/ssr

如果我 运行 这个项目,网站似乎加载正常,如果我在浏览器中关闭 javascript,我可以看到服务器端渲染确实出现了执行并填充 html 结果:

但是,因为 JavaScript 被禁用,所以内容没有移动到 dom 中,因为看起来它正在尝试...

我对服务器端呈现的理解是,它会完全填充 html 并向用户提供完整的页面,这样即使 JS 被禁用,他们至少能够看到页面(专门用于 SEO 目的)。我错了吗?

现在我相信现代搜索引擎会执行像这样的简单脚本来获取内容,但我仍然不希望在禁用 js 时呈现空白页面...

这是服务器端渲染的限制,还是 vue and/or aspnet core 的特定 ssr?

还是我只是漏掉了一步?

编辑:更多信息

我查看了源代码,我认为这是预呈现该部分的方法:https://github.com/aspnet/JavaScriptServices/blob/dev/src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs

output.Content.SetHtmlContent(result.Html); 

result.Html 的值为空。但是,当我手动编辑此值以放置测试值时,它也不会呈现到输出 html,并且应用程序 div 标签仍​​然是空的...

如果我在用预期输出填充 result.Html 值时做错了什么,那是一回事,我将不胜感激,特别是因为输出 html 出现可以找到,因为它在紧随其后的脚本中...

但是,即使我要填充它,它也似乎被跳过了,正如我手动更改值所证明的那样。这是代码中的错误还是我做错了什么,或者两者都有?

正如您正确注意到的那样,对于您的项目,标签助手中的 result.Html 为空。因此该行不能是生成输出的位置。由于预呈现脚本的 HTML 输出也不包含 script 标记,因此很明显必须生成该标记。唯一可能执行此操作的其他行是 PrerenderTagHelper:

中的以下行
output.PostElement.SetHtmlContent($"<script>{globalsScript}</script>");

这将符合观察到的输出,所以我们应该弄清楚 globalsScript 来自哪里。

如果你看PrerenderTagHelper implementation, you can see that it will call Prerenderer.RenderToString which returns a RenderToStringResult。此结果对象在调用您的 Node 脚本后从 JSON 反序列化。

所以这里有两个感兴趣的属性:HtmlGlobals。前者负责包含最终在标签助手内部呈现的 HTML 输出。后者是一个 JSON 对象,包含应为客户端设置的附加全局变量。这些是将在 script 标记内呈现的内容。

如果您查看项目中呈现的 HTML,您可以看到有两个全局变量:window.htmlwindow.__INITIAL_STATE__。所以这两个设置在你的代码中的某个地方,虽然 html 不应该是全局的。

罪魁祸首是 renderOnServer.js 文件:

vue_renderer.renderToString(context, (err, _html) => {
    if (err) { reject(err.message) }
    resolve({
        globals: {
            html: _html,
            __INITIAL_STATE__: context.state
        }
    })
})

如您所见,这将解析仅包含具有 html__INITIAL_STATE__ 属性的 globals 对象的结果。这就是在 script 标签内呈现的内容。

但是你想要做的是让 html 不是 globals 的一部分而是在上面的层上,这样它就被反序列化到 RenderToStringResult.Html 属性:

resolve({
    html: _html,
    globals: {
        __INITIAL_STATE__: context.state
    }
})

如果您这样做,您的项目将正确执行服务器端渲染,而不需要 JavaScript 初始视图。