【问题标题】:Server Side Rendering Vue with ASP.NET Core 2使用 ASP.NET Core 2 的服务器端渲染 Vue
【发布时间】:2018-06-07 16:32:32
【问题描述】:

我正在尝试了解在使用 aspnet core 时使用 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,因为它位于紧随其后的脚本...

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

【问题讨论】:

    标签: vue.js vuejs2 asp.net-core-2.0 server-side-rendering asp-net-core-spa-services


    【解决方案1】:

    正如您正确注意到的,对于您的项目,标签助手内的result.Html 为空。因此该行不能是生成输出的位置。由于预渲染脚本的 HTML 输出也不包含script 标记,很明显必须生成该标记。唯一可以做到这一点的其他行是PrerenderTagHelper 中的以下行:

    output.PostElement.SetHtmlContent($"<script>{globalsScript}</script>");
    

    这符合观察到的输出,所以我们应该找出globalsScript 的来源。

    如果您查看PrerenderTagHelper 实现,您可以看到它将调用Prerenderer.RenderToString,它返回一个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。

    【讨论】:

    • 啊,太明显了,我想我很接近了;我可以说该属性位于错误的位置,但我没有想到这是因为在解析中设置参数的方式。将 html 移到全局变量之外确实起到了作用!非常感谢您的关注和帮助,感谢您让我重回正轨!
    猜你喜欢
    • 1970-01-01
    • 2017-03-30
    • 2018-01-19
    • 2016-11-08
    • 2018-12-13
    • 2018-12-13
    • 2020-04-10
    • 2022-07-29
    • 2016-05-27
    相关资源
    最近更新 更多