How we tried to create a frontend framework which can be learned in 5 minutes and which is the result

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MyrinNew
    Senior Member
    • Feb 2024
    • 5168

    #1

    How we tried to create a frontend framework which can be learned in 5 minutes and which is the result

    Hi!


    I will tell you about my experience of creating a front-end framework. The goal was to create a framework that can be learned in 5 minutes by a front-end developer who has experience with React, Vue, or Angular.


    How to create a component

    In React, a component is a function; in Vue, it is a file; and in Angular, a component consists of several files. Personally, I prefer the possibility to create a helper component in a component file. Because of this, I decided that a component will be a function declared in the following way:






    export const MyComponent = component(() => {
    // component logic here
    });







    Reactive states

    To save states, there are variables in Javascript, so we will it.


    The rules are simple:

    1. If the variable name starts with $ than it will be reactive.
    2. If the variable name does not start with $ than it will be just a variable.


    If a derived/computed state is needed, then a constant is declared and initialized with the required value. When let is used, the linter can switch automatically to const, so constant is canonical.


    Example of code:






    export const MyComponent = component(() => {
    let $a = 2;
    let $b = 3;
    const $sum = $a + $b;
    const $sum2 = sum($a, $b);
    });







    Side effects

    The component function is executed once, so the following side effects are present in the next functions:
    • watch executes a function each time when a reactive value from the body is updated.
    • beforeMount executes a function after data initialization and before DOM nodes mount.
    • afterMount executes a function after the DOM nodes mount.
    • beforeDestroy executes a function before the DOM nodes removing.


    The next code






    export const MyComponent = component(() => {
    let $state = 'init';
    watch(() => { console.log($state) });
    beforeMount(() => { $state = "before" });
    afterMount(() => { $state = "after" });
    });







    Will print in console:






    init
    before
    after







    DOM

    To declare DOM nodes, HTML code is used; it is written directly to the component function body, and it works via JSX. The event handlers like onclick/onpress accept functions as value.


    Nodes declarations

    Example of button with counter:






    export const MyComponent = component(() => {
    let $count = 'init';
    function inc() {
    $count++;
    }

    You clicked {$count} times
    ;
    });







    The class attribute accepts a string array as a value; the style one accepts objects as a value.


    Callbacks

    To connect third-party libraries or to access DOM nodes directly, the callbacks are used. A callback is a function that is called when the element and all its children are mounted in DOM.


    Example of callback usage:






    export const MyComponent = component(() => {
    function sideEffect(input: HTMLInputElement) {
    input.showPicker();
    }
    ;
    });







    Share data between compoents

    The data can be shared between components in the next ways:
    • from parent to children via properties;
    • from children to parent via callbacks;
    • from children to parent and from parent to children via slots;


    Sharing data via properties

    Properties are an object; the field names can match the same rules as variable names, so if the field name starts with $ then the field is reactive; otherwise, it is not reactive.


    Example of sharing data via properties:






    interface Props {
    userId: string;
    $userName: string;
    }
    const Child = component(({userId, $userName}: Props) => {
    {userId} is named {$userName}
    ;
    });
    const Parent = component(() => {
    const id = 1;
    let $name = "First";

    // When the name is updated here
    // it will be automatically updated in the child component
    ;
    });







    Sharing data via callbacks

    The component function can return data; the returned data can be accessed in the parent component via callback.


    Example of using callbacks as an alternative for forwardRef from React:






    const Child = component(() => {
    let input: HTMLInputElement|null = null;
    input = element}/>;
    return input;
    });
    const Parent = component(() => {
    { console.log(input) }}/>;
    });







    Sharing data via slots

    The slots are sending data to the parent component data via properties, and the parent is sharing a DOM description with the child component:






    interface Props {
    $title: string;
    slot?(props: { $name: string }): void;
    }
    const Child = component(({$title, slot}: Props) => {



    ;
    });
    const Parent = component(() => {
    let $title = "MyApp";
    {
    {$name};
    })/>;
    });







    When the child is not sharing data with the parent, the DOM description can be included in the child tag: Text.


    Also, inside the Slot tag can be present a DOM description, which will be used if the parent does not fill the slot.


    The slot is not just a function; it is a component. The reactive states, derived/computed value, and watch, beforeMount, afterMount and beforeDestroy can be used in a slot.


    Logic and loops

    There are building components that operate the logic and loops: If, Else ElseIf and For.


    Example of conditional text:






    const MyComponent = component(() => {
    let $count = 0;
    2}>
    Count is too big!
    ;
    });







    Example of loop;






    const MyComponent = component(() => {
    const arr = [1, 2, 3];
    {
    Number is {number}

    }}/>;
    });







    The property name rules are applied to built-in components. The If will react to updates of $condition, but For will not react to updates of the model; the model must be updated via push, pull and similar methods.


    Conclusions

    There is a minimal set of functions to create an SPA. All this is already working; the component styling library is already ready, and scripts for building component libraries and applications are ready. The last updates added the SSG compiling option and a React-like condition for conditional tags as an alternative to If/Else; it fixes some TypeScript errors.


    The project is open-source. For volunteers who want to help, we have a Google Form for Customer Development Interview: https://docs.google.com/forms/d/e/1F...orm?usp=header


    Thanks for your attention!




    More...
Working...