Archived
add ssr-counter example demonstrating SSR + hydration end-to-end
Counter.el defines Counter, CounterPair, and App components with {#if}
conditionals, event handlers, and child component composition.
render.js (generated by elc-ui --target=server) is the Node.js render
script the server calls. app.js (generated by elc-ui --target=web) is the
compiled browser module. hydrate.js attaches the runtime to the
server-rendered DOM without replacing it.
index.html shows the integration point with instructions for injecting
server output and the two CLI commands needed to regenerate both targets.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import { Component, Graph, Renderer, Router, mount } from '../../dist/el-ui.js';
|
||||
|
||||
class Counter extends Component {
|
||||
constructor(props = {}) {
|
||||
super();
|
||||
this.props = props;
|
||||
this._graph = new Graph();
|
||||
this._stateNodes = {};
|
||||
this._state = {};
|
||||
this._stateNodes['count'] = this._graph.seed({ type: 'state', name: 'count', content: 0 });
|
||||
this._state['count'] = 0;
|
||||
this._stateNodes['history'] = this._graph.seed({ type: 'state', name: 'history', content: "" });
|
||||
this._state['history'] = "";
|
||||
for (const [key, nodeId] of Object.entries(this._stateNodes)) {
|
||||
this._graph.subscribe(nodeId, (node) => {
|
||||
this._state[key] = node.content;
|
||||
if (this._renderer) this._renderer.patch();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setState(name, value) {
|
||||
if (this._stateNodes[name] !== undefined) {
|
||||
this._graph.update(this._stateNodes[name], value);
|
||||
}
|
||||
}
|
||||
|
||||
increment() {
|
||||
const __self = this;
|
||||
const count = this._state['count'];
|
||||
const history = this._state['history'];
|
||||
const initialValue = this.props['initialValue'] !== undefined ? this.props['initialValue'] : 0;
|
||||
const label = this.props['label'] !== undefined ? this.props['label'] : "Counter";
|
||||
|
||||
__self.setState('count', count + 1)
|
||||
__self.setState('history', history + "+" + count + " ")
|
||||
|
||||
}
|
||||
|
||||
decrement() {
|
||||
const __self = this;
|
||||
const count = this._state['count'];
|
||||
const history = this._state['history'];
|
||||
const initialValue = this.props['initialValue'] !== undefined ? this.props['initialValue'] : 0;
|
||||
const label = this.props['label'] !== undefined ? this.props['label'] : "Counter";
|
||||
|
||||
__self.setState('count', count - 1)
|
||||
__self.setState('history', history + "-" + count + " ")
|
||||
|
||||
}
|
||||
|
||||
reset() {
|
||||
const __self = this;
|
||||
const count = this._state['count'];
|
||||
const history = this._state['history'];
|
||||
const initialValue = this.props['initialValue'] !== undefined ? this.props['initialValue'] : 0;
|
||||
const label = this.props['label'] !== undefined ? this.props['label'] : "Counter";
|
||||
|
||||
__self.setState('count', 0)
|
||||
__self.setState('history', "")
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
const __self = this;
|
||||
const count = this._state['count'];
|
||||
const history = this._state['history'];
|
||||
const initialValue = this.props['initialValue'] !== undefined ? this.props['initialValue'] : 0;
|
||||
const label = this.props['label'] !== undefined ? this.props['label'] : "Counter";
|
||||
return `<div class="counter" data-el-tag="div"><h2 class="counter-label" data-el-tag="h2">${label }</h2><div class="count-display" data-el-tag="div"><span class="${count > 0 ? "count positive" : count < 0 ? "count negative" : "count zero"}" data-el-tag="span">${count }</span></div><div class="buttons" data-el-tag="div"><button class="btn btn-decrement" data-el-click="() => decrement()" data-el-tag="button">-</button><button class="btn btn-reset" data-el-click="() => reset()" data-el-tag="button">reset</button><button class="btn btn-increment" data-el-click="() => increment()" data-el-tag="button">+</button></div>${(history != "") ? `<div class="history" data-el-tag="div"><span class="history-label" data-el-tag="span">history:</span><code data-el-tag="code">${history }</code></div>` : ``}${(count == 0) ? `<p class="hint" data-el-tag="p">Press + or - to begin.</p>` : ``}</div>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CounterPair extends Component {
|
||||
constructor(props = {}) {
|
||||
super();
|
||||
this.props = props;
|
||||
this._graph = new Graph();
|
||||
this._stateNodes = {};
|
||||
this._state = {};
|
||||
}
|
||||
|
||||
setState(name, value) {
|
||||
if (this._stateNodes[name] !== undefined) {
|
||||
this._graph.update(this._stateNodes[name], value);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const __self = this;
|
||||
return `<div class="counter-pair" data-el-tag="div">${__self._child(Counter, { label: "Left" })}${__self._child(Counter, { label: "Right" })}</div>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class App extends Component {
|
||||
constructor(props = {}) {
|
||||
super();
|
||||
this.props = props;
|
||||
this._graph = new Graph();
|
||||
this._stateNodes = {};
|
||||
this._state = {};
|
||||
}
|
||||
|
||||
setState(name, value) {
|
||||
if (this._stateNodes[name] !== undefined) {
|
||||
this._graph.update(this._stateNodes[name], value);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const __self = this;
|
||||
return `<div class="app" data-el-tag="div"><header class="app-header" data-el-tag="header"><h1 data-el-tag="h1">el-ui SSR + Hydration</h1><p class="subtitle" data-el-tag="p">Server-rendered, client-hydrated with spreading activation</p></header><main class="app-main" data-el-tag="main">${__self._child(Counter, { label: "Main Counter" })}${__self._child(CounterPair, { })}</main></div>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { Counter, CounterPair, App };
|
||||
Reference in New Issue
Block a user