Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Preact as a Dependency? #55

Open
developit opened this issue May 21, 2018 · 4 comments
Open

Use Preact as a Dependency? #55

developit opened this issue May 21, 2018 · 4 comments

Comments

@developit
Copy link

developit commented May 21, 2018

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

@dntzhang
Copy link
Collaborator

dntzhang commented May 22, 2018

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

@developit
Copy link
Author

developit commented May 22, 2018

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);
	}
}
@dntzhang
Copy link
Collaborator

Pretty good way! You know preact better than I do :), wait for me to try and give you feedback these days.

@developit
Copy link
Author

I figured it was easier to show code than explain haha. If you are looking into things, feel free to ping me on slack 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
2 participants