vue.js - 使用 ASP.NET Core 2 的服务器端渲染 Vue
问题描述
我试图了解使用 aspnet 核心时使用 vuejs 进行服务器端渲染的用法和限制。
我使用这个用于 aspnet 核心和 vuejs 的入门工具包来设置一个简单的 vue 站点,该站点基于此处的代码运行: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 和/或 aspnet 核心的 ssr?
还是我只是在某处错过了一步?
编辑:更多信息
我查看了源代码,我认为这是在此处预呈现该部分的方法:https ://github.com/aspnet/JavaScriptServices/blob/dev/src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs
线
output.Content.SetHtmlContent(result.Html);
result.Html 的值为空。但是,当我手动编辑此值以放置测试值时,它也不会呈现到输出 html,并且 app div 标签仍然为空...
如果我在使用预期输出填充 result.Html 值时做错了什么,那是一回事,我会很感激这样做的一些帮助,特别是因为似乎找到了输出 html,因为它在脚本中立即跟随...
但是,即使我要填充它,它似乎也被跳过了,正如我手动更改值所证明的那样。这是代码中的错误还是我做错了什么,或者两者兼而有之?
解决方案
正如您正确注意到的那样,对于您的项目,result.Html
标签助手内部为空。因此该行不能是生成输出的位置。由于您的预渲染脚本的 HTML 输出也不包含script
标签,因此很明显必须生成该标签。唯一可以做到这一点的其他行是来自以下的PrerenderTagHelper
:
output.PostElement.SetHtmlContent($"<script>{globalsScript}</script>");
这将适合观察到的输出,所以我们应该弄清楚它的globalsScript
来源。
如果您查看PrerenderTagHelper
实现,您会发现它将调用Prerenderer.RenderToString
返回 a RenderToStringResult
。此结果对象在调用您的 Node 脚本后从 JSON 反序列化。
所以这里有两个感兴趣的属性:Html
和Globals
。前者负责包含最终在标签助手中呈现的 HTML 输出。后者是一个 JSON 对象,其中包含应为客户端设置的附加全局变量。这些将在该script
标签内呈现。
如果您查看项目中呈现的 HTML,您会看到有两个全局变量:window.html
和window.__INITIAL_STATE__
. 因此,这两个设置在您的代码中的某个位置,尽管html
不应该是全局的。
罪魁祸首是renderOnServer.js
文件:
vue_renderer.renderToString(context, (err, _html) => {
if (err) { reject(err.message) }
resolve({
globals: {
html: _html,
__INITIAL_STATE__: context.state
}
})
})
如您所见,这将解析仅包含具有和属性的globals
对象的结果。这就是在标签内部呈现的内容。html
__INITIAL_STATE__
script
但是你想要做的不是html
作为上层的一部分globals
而是在上面的层上,以便它被反序列化到RenderToStringResult.Html
属性中:
resolve({
html: _html,
globals: {
__INITIAL_STATE__: context.state
}
})
如果您这样做,您的项目将正确执行服务器端渲染,而初始视图不需要 JavaScript。
推荐阅读
- xamarin - 即使在所有权限到位后,BroadcastReceiver 也没有接收到
- tabulator - 制表器中的几个嵌套表
- python - 日期时间到季节
- java - Java 模块(在 Java 9 中)、OSGi 包和微服务之间的具体区别是什么?他们每个人的具体目的是什么?
- python - Python import 语句中的双下划线是什么意思?
- java - 使用BottomSheetFragment时,下面的灰色显示重叠android导航按钮?
- javascript - lodash 按对象过滤对象数组
- jquery - 如果属性 VALUE 已经存在,删除它,否则添加它 jQuery
- node.js - 如何验证 NestJs 上的请求 excel 数据?
- c# - 使用 O365 共享帐户创建 Outlook 约会