<div id="root1">
</div>
<div id="root2">
</div>
<div id="root3">
</div>
class FeactDOMComponent {
  	constructor(element) {
    		this._currentElement = element;
  	}

  	mountComponent(container) {
    		const domElement = document.createElement(this._currentElement.type);
    		const textNode = document.createTextNode(this._currentElement.props.children);

    		domElement.appendChild(textNode);
    		container.appendChild(domElement);
  	}
}

class FeactCompositeComponentWrapper {
  	constructor(element) {
    		this._currentElement = element;
  	}

  	mountComponent(container) {
    		const compositeComponentInstance = new this._currentElement.type(this._currentElement.props);
        console.log("compositeComponentInstance",compositeComponentInstance)
            
    		let renderedElement = compositeComponentInstance.render();
        console.log("renderedElementBefore",renderedElement);

    		while (typeof renderedElement.type === 'function') {
      			renderedElement = new renderedElement.type(renderedElement.props).render();
            console.log("renderedElementAfter",renderedElement);
    		}

    		const domComponentInstance = new FeactDOMComponent(renderedElement);
    		domComponentInstance.mountComponent(container);
  	}
}

const TopLevelWrapper = function(props) {
		this.props = props;
};

TopLevelWrapper.prototype.render = function() {
  return this.props;
};

const Feact = {
	  createClass(spec) {
      	function Constructor(props) {
        		this.props = props;
      	}

      	Constructor.prototype.render = spec.render; 
      
      	return Constructor;
    },
  
    createElement(type, props, children) {
        const element = {
            type,
            props: props || {}
        };

        if (children) {
            element.props.children = children;
        }
        
        console.log("Create Element", element);

        return element;
    },

    render(element, container) {
    		const wrapperElement = this.createElement(TopLevelWrapper, element);
        console.log("Wrapper Element", wrapperElement);
      	const componentInstance = new FeactCompositeComponentWrapper(wrapperElement);
      	return componentInstance.mountComponent(container);
    }
};

const MyH1 = Feact.createClass({
  	render() {
    		return Feact.createElement('h1', null, this.props.message);
  	}
});

const MyMessage = Feact.createClass({
  	render() {
    		if (this.props.asTitle) {
    				return Feact.createElement(MyH1, { message: this.props.message });
    		} else {
      			return Feact.createElement('p', null, this.props.message);    
    		}
  	}
});

Feact.render(
		Feact.createElement(MyMessage, { asTitle: true, message: 'this is an h1 message' }),
  	document.getElementById('root1')
);

Feact.render(
		Feact.createElement(MyMessage, { asTitle: false, message: 'and this is just a paragraph' }),
  	document.getElementById('root2')
);

Feact.render(
		Feact.createElement('button', null, 'i\'m a primitive element'),
    document.getElementById('root3')
);

Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.