不传递wires的同构hyperHTML组件:跨端模块共享问题
Awesome question! Let's get your hyperHTML components running smoothly both client-side and server-side as an isomorphic module. The key issue here is that hyperHTML's wire method is built for client-side DOM binding, while server-side rendering needs raw HTML strings instead of DOM nodes. Here's a clean, maintainable fix:
Step 1: Abstract Rendering Logic for Cross-Environment Compatibility
First, we'll create a tiny utility to detect the environment and return the right hyperHTML renderer—either the client-side wire for DOM binding or the server-side ssr function for string generation. This keeps our component logic DRY and environment-agnostic.
Step 2: Refactor Your Components
Here's the updated component.js that works everywhere:
// component.js import hyperHTML from 'hyperhtml'; // Utility to get the correct renderer based on environment const getRenderer = (target) => { // Detect if we're running on the server (no window object) const isServer = typeof window === 'undefined'; if (isServer) { // Server-side: return a new SSR renderer each time to avoid cross-request pollution return hyperHTML.ssr(); } else { // Client-side: use hyperHTML's wire for DOM binding return hyperHTML.wire(target); } }; export function ListItem(item) { const html = getRenderer(item); function render() { return html`<li>${item.foo}</li>`; } return render(); } export function List(items) { const html = getRenderer(items); function render() { // On server: maps to string array, which hyperHTML will concatenate // On client: maps to DOM nodes, which hyperHTML will mount return html`<ul>${items.map(ListItem)}</ul>`; } return render(); }
Step 3: Usage Examples
Server-Side (Node.js)
When rendering on the server, the components return raw HTML strings that you can send in HTTP responses:
// server.js import { List } from './component.js'; // Sample data const items = [{ foo: 'First Item' }, { foo: 'Second Item' }, { foo: 'Third Item' }]; // Generate full page HTML const pageHTML = ` <!DOCTYPE html> <html> <body> <h1>My Isomorphic List</h1> ${List(items)} </body> </html> `; // Send to client (e.g., via Express) // res.send(pageHTML);
Client-Side
On the browser, the components return live DOM nodes that you can mount directly into the page—plus hyperHTML's automatic DOM diffing works as expected for updates:
// client.js import { List } from './component.js'; const items = [{ foo: 'First Item' }, { foo: 'Second Item' }]; const listElement = List(items); // Mount to the DOM document.getElementById('app').appendChild(listElement); // Later, if you update items, hyperHTML will efficiently update the DOM // (Just re-call List with updated items and re-mount, or use hyperHTML's state patterns)
Key Notes to Avoid Pitfalls
- Server-Side Cleanup: We create a new
ssrrenderer every time to prevent cross-request state leaks—critical for server scalability. - Client-Side Reactivity: The client-side code retains hyperHTML's full reactive capabilities, so your components will update efficiently when data changes.
- Tooling: If you're using a bundler like Webpack or Rollup, make sure it correctly tree-shakes the hyperHTML code (most modern bundlers handle this automatically for isomorphic modules).
内容的提问来源于stack exchange,提问作者László Balogh

