同构的hyperHTML组件没有传入电线

时间:2018-04-03 20:09:49

标签: javascript hyperhtml

我有以下两个组成部分:

// component.js
// imports ...

function ListItem(item) {
  const html = wire(item)

  function render() {
    return html`<li>${item.foo}</li>`
  }

  return render()
}

function List(items) {
  const html = wire(items)

  function render() {
    return html`<ul>${items.map(ListItem)}</ul>`
  }

  return render()
}

我想将它们放在客户端和服务器之间共享的模块中。但是,据我所知,尽管API几乎完全相同,但在服务器上我必须从viperHTML模块导入函数,在客户端我必须使用hyperHTML模块。因此,我不能只导入共享模块顶部的函数,但必须在调用站点传递给我的组件。

这样做我的同构组件看起来像这样:

// component.js

function ListItem(html, item) {
  //const html = wire(item) // <- NOTE

  function render() {
    return html`<li>${item.foo}</li>`
  }

  return render()
}

function List(html, itemHtmls /* :( tried to be consistent */, items) {
  //const html = wire(items) // <- NOTE

  function render() {
    return html`<ul>${items.map(function(item, idx) {
      return ListItem(itemHtmls[idx], item)
    })}</ul>`
  }

  return render()
}

从服务器调用组件:

// server.js
const {hyper, wire, bind, Component} = require('viperhtml')

const items = [{foo: 'bar'}, {foo: 'baz'}, {foo: 'xyz'}]
// wire for the list
const listWire = wire(items)
// wires for the children
const listItemWires = items.map(wire)

const renderedMarkup = List(listWire, listItemWires, items)

从浏览器调用将完全相同,期望导入hyperhtml的方式:

// client.js
import {hyper, wire, bind, Component} from 'hyperhtml/esm'

然而,编写这样的代码感觉很不愉快,因为我觉得wire()调用的结果应该存在于组件实例中。有没有更好的方法来编写同构的hyperHTML / viperHTML组件?

1 个答案:

答案 0 :(得分:3)

更新现在hypermorphic模块提供了一种解决方法。

理想的情况是,您只有viperhtml作为依赖项,而hyperhtml会自动引入typeof document === "object",正如the index.js file所示。

此时,客户端捆绑器应该(如果有能力)为您摇动未使用的代码,但是您有一个非常好的观点,并不是立即清楚。

我也不完全确定捆绑包是​​否可以那么聪明,假设像import {hyper, wire, bind, Component} from 'viperhtml' 这样的检查总是如此,并且只针对目标浏览器。

尝试这种方法的一种方法是

render() { return this.html... }
在客户端也是如此,希望捆绑后不会引入viperHTML依赖项,因为浏览器上你需要很多东西。

  

我感觉wire()调用的结果应该存在   在组件实例中。

您可以使用viper.Component简化您的组件,这样您就可以Component而忘记传递电线但我同意您的改进空间。

此时,您只需要解决在一个位置导入哪个Component并定义在客户端和服务器上都可以工作的便携式组件。

这基本上是光class ListItem extends Component { constructor(item) { super().item = item; } render() { return this.html`<li>${this.item.foo}</li>`; } } class List extends Component { constructor(items) { super().items = items; } render() { return this.html` <ul>${this.items.map(item => ListItem.for(item))}</ul>`; } } 首先存在的原因,它让您可以自由地专注于组件而无需考虑连线,方式和/或位置(如果客户端/服务器)。 / p>

~~我打算给你看一个例子,但你把内容与项目联系起来的事实(正确)让我觉得当前的组件也可以改进,所以I've created a ticket as follow up对你的情况而言我希望我会有更好的例子(对于组件)比较晚.~~

修改

我更新了库,让您可以使用a code pen example创建能够在创建时使用/接收数据/项目的组件。

Component

当您使用组件时,您确保这些组件可以在客户端/服务器上移植。

此时唯一的问题是找出检索Component类的最佳方法。

一种可能的解决方案是在单个入口点集中导出此类。

然而,房间里的大象是NodeJS与ESM模块不兼容,浏览器与CommonJS不兼容,所以我没有最好的答案,因为我不知道你是否/如何捆绑你的代码

理想情况下,您可以使用在NodeJS中开箱即用并且与每个浏览器捆绑器兼容的CommonJS,但是您需要区分每个构建将导出function ListItem(item) { return wire(item)`<li>${item.foo}</li>`; } function List(items) { return wire(items)`<ul>${items.map(ListItem)}</ul>`; } 或任何其他超级的文件/ viperHTML相关实用程序。

我希望我已经给你足够的提示,最终解决当前的限制。

道歉,如果现在我没有更好的答案。我以前使用external renders的方式,但很可能不是最方便的方法来使用更复杂的结构/组件。

P.S。你可以像这样编写那些函数

{{1}}