我试图了解使用aspnet核心时使用vuejs进行服务器端渲染的用法和限制。
我使用this starter kit for aspnet core and 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似乎是发现,因为它紧跟在脚本之后......
然而,即使我填充它,它似乎被跳过,我手动更改值就是证明了这一点。这是代码中的错误还是我做错了,或者两者都错了?
答案 0 :(得分:2)
正如您所注意到的,对于您的项目,标记帮助程序中的result.Html
为空。因此该行不能是生成输出的位置。由于预呈现脚本的HTML输出也不包含script
标记,因此很明显必须生成某些内容。唯一可以执行此操作的其他行是PrerenderTagHelper
:
output.PostElement.SetHtmlContent($"<script>{globalsScript}</script>");
这符合观察到的输出,因此我们应该找出globalsScript
的来源。
如果您查看PrerenderTagHelper
实施,可以看到它会调用Prerenderer.RenderToString
并返回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。