【问题标题】:Server Side Rendering with viperHTML使用 viperHTML 进行服务器端渲染
【发布时间】:2019-02-12 14:08:53
【问题描述】:

我正在开发一个 Symfony 应用程序,并且刚刚使用 https://github.com/spatie/server-side-rendering 获得了用于 JS 的 SSR。到目前为止,我只为 React 使用“现成的”SSR 解决方案,但目前我正在尝试使用 hyperHTML/viperHTML 并且面临一些到目前为止我无法通过查看可用文档/示例来解决的问题。

我目前的测试sn-p是这样的:

const viperHTML = require('viperhtml');

class Component extends viperHTML.Component {    
    constructor(props) {
        super();
        this.props = props;
    }

    render() {
        return this.html`
      <h1>Hello, ${this.props.name}</h1>`;
    }
}

console.log(new Component({ name: 'Joe' }).render().toString());

这里的问题是,如果没有显式调用render(),我就没有输出。查看一些官方示例,这不应该是必要的,至少不是Component。例如,我已经尝试在构造函数中使用setState(),但没有区别。

另外,如果不同时使用console.log()toString(),我也没有输出。这是出乎意料的。我知道这里可能需要toString()(没有它,正在渲染&lt;buffer /&gt;),但console.log() 似乎很奇怪。当然,这可能根本与 viperHTML 无关。但是实例化组件是我唯一需要做的事情。

我还不清楚如何编写一个同构/通用组件,即一个包含标记、事件处理程序等的文件,在服务器上呈现,然后在客户端上水合。当我根据文档 (https://viperhtml.js.org/hyperhtml/documentation/#essentials-6) 添加内联事件处理程序时,它实际上被内联到呈现的标记中,这不是我想要的。 我检查了超形态和 viperNews 应用程序,但到目前为止这对我没有帮助。

【问题讨论】:

    标签: prerender server-side-rendering hyperhtml


    【解决方案1】:

    如果有帮助,您可以read viperHTML tests 了解如何使用组件。

    这里的问题是,如果没有显式调用 render() 我没有输出。

    组件旨在用于在服务器或客户端呈现布局。这意味着如果您将组件实例传递给 hyper/viperHTML 视图,您不必担心调用任何内容,一切都会为您完成。

    const {bind, Component} = require('viperhtml');
    
    class Hello extends Component {    
      constructor(props) {
        super().props = props;
      }
      render() {
        return this.html`<h1>Hello, ${this.props.name}</h1>`;
      }
    }
    
    console.log(
      // you need a hyper/viperHTML literal to render components
      bind({any:'ref'})`${Hello.for({ name: 'Joe' })}`
        // by default you have a buffer to stream in NodeJS
        // if you want a string you need to use toString()
        .toString()
    );
    

    由于默认情况下 NodeJS 流缓冲区,viperHTML 生成的任何布局都将是缓冲区,因此可以在组合时进行流式处理(即使用 Promises 作为插值值)。

    我也不清楚如何编写一个同构/通用组件,即一个包含标记、事件处理程序等的文件,在服务器上呈现,然后在客户端上水合。

    hyperHTML 的原始版本有一个名为adopt() 的方法,其目的是通过相同的模板文字来水合活动节点。

    虽然 viperHTML 有一个 viperhtml.adoptable = true 开关来呈现可采用的内容,但 hyperHTML adopt 功能仍然是 not quite there yet,因此,目前,您可以轻松地在 SSR 和 FE 之间共享视图,但您需要一旦 SSR 页面登陆或第一次做出反应,就以不同的方式接管客户端,并在远处接管客户端。

    这不是最佳选择,但我担心水合位,如果做得对,会很耗时,而且我还没有找到时间来完成它并发货。

    此时可能是 hyperHTML v3。

    我希望这个答案有助于理解 viperHTML 的工作原理以及当前状态。

    【讨论】:

    • 非常感谢,安德烈
    • Andrea,我得到了简短的跟进。 hyperHTML 的 adopt 会或多或少等同于 React 的 hydrate 吗?另外,我现在接手客户做bind(document.getElementById('my-container'))`${new Hello()}`; 之类的事情,它基本上可以工作,这很棒。但是我在做 SSR 时从后端传递道具,我想避免在客户端重新渲染组件。有没有办法实现这一点(可能在onconnected 内部)?
    • 如果管道中有监听器,组件不会在客户端做出预期的反应,而adopt 会将活动 dom 映射到当前模板而不更改其节点,但会寻址监听器和其他善良。还可以考虑使用Hello.for(data) 而不是new Hello(data),否则每次相同的组件都会被丢弃并重新渲染。最后,我不 React,所以听起来相似的 hydrate 可能相当于(仍然)缺少的采用。