Skip to content

Instantly share code, notes, and snippets.

@tgroshon
Last active July 16, 2020 22:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tgroshon/1441acdd6812334c9edbdca3ad4f5737 to your computer and use it in GitHub Desktop.
Save tgroshon/1441acdd6812334c9edbdca3ad4f5737 to your computer and use it in GitHub Desktop.
Interesting Framework Idea

Framework Summary

  • Application:

    • An application handles routing between many pages.
    • Sets up ViewEngine
  • Pages:

    • Only one page renders at a time determined by URL.
    • Can start many controllers.
  • Controllers:

    • Can render views, but doesn't have to.
    • Is one "mount context" for a "view engine" and has it's own mount point.
  • ViewEngine:

    • Agnostic view processor for controllers
  • Views/Components/etc.

    • React code
import { ReactClassComponent, ReactHookComponent } from "./Components";
import { Page, Controller } from "./Framework";
import { ReactViewEngine } from "./ReactViewEngine";
/*
===========================
Non-react Application Code
===========================
*/
class MainController extends Controller {
views = [ReactHookComponent, ReactClassComponent];
publicFn() {
window.alert("Controller Public Function called");
}
}
class HomePage extends Page {
route = "/";
controllerClasses = [MainController];
}
class Application {
viewEngine = new ReactViewEngine();
start() {
// TODO: Start a router and only run page for current matching URL
const page = new HomePage(this);
page.mount();
}
}
const app = new Application();
app.start();
import ReactDOM from "react-dom";
import React from "react";
/*
================
React Components
================
*/
export class ReactClassComponent extends React.Component {
render() {
return <h2>Application rendered</h2>;
}
}
export function ReactHookComponent({ controller }) {
React.useEffect(() => {
console.log("Hook Component side-effect fired");
});
return (
<p>
Hook Component{" "}
<button onClick={() => controller.publicFn()}>
Trigger Controller Method
</button>
</p>
);
}
/**
* Controllers:
* - A page has many controllers. Each can render views, but doesn't have to.
* - Each controller is one "render context" for a "view engine".
* - Each controller has it's own mount point on the page. (Or none)
*/
export class Controller {
views = [];
constructor(page, viewEngine) {
this.page = page;
this.viewEngine = viewEngine;
}
get mountPoint() {
if (!this._mountPoint) {
const el = document.createElement("DIV");
document.body.appendChild(el);
this._mountPoint = el;
}
return this._mountPoint;
}
start() {
this.viewEngine.mount(this, this.views, this.mountPoint);
}
}
/**
* Pages:
* - An application has many pages. Pages integrate with router so only one
* page renders at a time determined by URL.
* - Can start many controllers.
*/
export class Page {
route = "/";
controllerClasses = []; // NOTE: Page can have multiple controllers
constructor(app) {
this.application = app;
}
get controllers() {
if (!this._controllers) {
this._controllers = this.controllerClasses.map(ControllerKlass => {
return new ControllerKlass(this, this.application.viewEngine);
});
}
return this._controllers;
}
mount() {
this.controllers.forEach(controller => controller.start());
}
}
/**
* Application
* - Handles config and routing
* - Sets the ViewEngine
*/
export class Application {
start() {
// TODO: Start a router and only run page for current matching URL
throw new Error("Needs implemented");
}
}
import React from "react";
import ReactDOM from "react-dom";
/**
* ViewEngine
* - createElement: API compatible with JSX
* - mount: proxy ReactDOM.render()
*/
export class ReactViewEngine {
createElement(...args) {
return React.createElement(...args);
}
mount(controller, views, mountPoint) {
return ReactDOM.render(
views.map((View, i) => this.createElement(View, { controller, key: i })),
mountPoint
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment