0

我有以下两个组件:

// 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 组件?

4

1 回答 1

3

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


理想的情况是您只拥有依赖项viperhtml,而这又会hyperhtml自动引入,正如您在 index.js 文件中看到的那样。

那时,如果有能力,客户端捆绑器应该为您摇树未使用的代码,但您有一个很好的观点,但还不是很清楚。

我也不完全确定捆绑程序是否可以那么聪明,假设检查typeof document === "object"总是正确的并且仅针对浏览器。

尝试的一种方法是

import {hyper, wire, bind, Component} from 'viperhtml'

在客户端也是如此,希望它不会在捆绑后引入 viperHTML 依赖项,因为您在浏览器上永远不需要很多东西。

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

您可以使用viper.Component简化您的组件,这样您就可以拥有render() { return this.html... }并且您忘记了传递电线,但我同意您的观点,还有改进的空间。

此时,您只需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>`;
  }
}

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

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

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

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

理想情况下,您将使用 CommonJS,它在 NodeJS 中开箱即用,并且与每个浏览器捆绑程序兼容,但是您需要在每次构建时区分将导出该文件Component或任何其他 hyper/viperHTML 相关实用程序的文件。

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

抱歉,如果现在我没有更好的答案。我以前使用外部渲染的方式,但它很可能不是使用更复杂的结构/组件的最方便的方式。


PS你可以像这样编写这些函数

function ListItem(item) {
  return wire(item)`<li>${item.foo}</li>`;
}

function List(items) {
  return wire(items)`<ul>${items.map(ListItem)}</ul>`;
}
于 2018-04-04T09:50:32.060 回答