Use Preact as a Dependency?
Hi there!
Omi looks really neat! I'm wondering you think it would be possible to use Preact as an upstream dependency rather than inlining it? There are some "hooks" in the source that might be useful for this (options.vnode, options.event, etc).
The advantage of doing so would be that when Preact is updated, Omi would be updated without having to write any code 🍰
Cheers! -jason
Thank you for your advice and thank you for your preact project.
There are some differences between the Omi source code and the preact in order to be compatible with native, such as h method. I modified the args format of render method for ssr and store system. The hook functions of preact are not enough to implement the existing functions of Omi. And i prefer component.update to component.setState, more free and flexible.
On the problem of code synchronization between Omi and preact, i will keep an eye on preact's progress and incorporate good features into Omi.
Cheers! -dntzhang
I guess that makes sense - just when we make substantial changes in the next version, it will be become quite difficult to port those over to Omi.
I actually think it might be possible to do most of what Omi needs on top of Preact.
Here's an example that implement's Omi's changes to render, h and Component.
It's worth noting - doing things this way would let you alias Preact components for use within Omi, and they could access Omi's store as this.context.$store 💯
import { preactH, PreactComponent, preactRender } from 'preact';
export function h() {
let p = preactH.apply(null, arguments);
p.nodeName = options.isWeb?p.nodeName:map[p.nodeName];
if (typeof p.children[0]=== 'string'&& !options.isWeb) {
if (p.attributes) {
p.attributes.value = p.children[0];
} else {
p.attributes = { value: p.children[0] };
}
}
if (options.vnode) options.vnode(p);
return p;
}
export function render() {
merge = Object.assign({
store: {}
}, merge);
if (typeof window === 'undefined') {
if (vnode instanceof Component&&merge){
vnode.$store = merge.store;
}
return;
}
options.staticStyleRendered = false;
parent = typeof parent === 'string' ? document.querySelector(parent) : parent;
if (merge.merge){
merge.merge = typeof merge.merge === 'string' ? document.querySelector(merge.merge) : merge.merge;
}
if (merge.empty){
while (parent.firstChild){
parent.removeChild(parent.firstChild);
}
}
merge.store.ssrData = options.root.__omiSsrData;
options.$store = merge.store;
if (vnode instanceof Component) {
if (window && window.Omi){
window.Omi.instances.push(vnode);
}
vnode.$store = merge.store;
if (vnode.componentWillMount) vnode.componentWillMount();
if (vnode.install) vnode.install();
const rendered = vnode.render(vnode.props, vnode.state, vnode.context);
//don't rerender
if (vnode.staticStyle){
addScopedAttrStatic(rendered,vnode.staticStyle(),'_style_'+getCtorName(vnode.constructor));
}
if (vnode.style){
addScopedAttr(rendered,vnode.style(),'_style_'+vnode._id,vnode);
}
vnode.base = preactRender(rendered, parent, merge.merge);
if (vnode.componentDidMount) vnode.componentDidMount();
if (vnode.installed) vnode.installed();
options.staticStyleRendered = true;
return vnode.base;
}
let result = preactRender(preactH(Provide, { $store: merge.store }, vnode), parent, merge.merge);
options.staticStyleRendered = true;
return result;
}
class Provide {
getChildContext() {
return { $store: this.props.$store }
}
render(props) {
return props.children[0];
}
}
export class Component extends PreactComponent {
constructor(props, context) {
super(props, context);
this._id = getId();
this._preStyle = null;
this.$store = this.context.$store;
}
forceUpdate(callback) {
super.forceUpdate(callback);
if (options.componentChange) options.componentChange(this, this.base);
}
update(callback) {
this.setState(null, callback);
}
}
Pretty good way! You know preact better than I do :), wait for me to try and give you feedback these days.
I figured it was easier to show code than explain haha. If you are looking into things, feel free to ping me on slack 👍