<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Vasille</title>
    <description>The latest articles on Forem by Vasille (@vasille).</description>
    <link>https://forem.com/vasille</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3400622%2F2cdcc4c0-1f0f-4f7e-b581-f203849721ed.jpg</url>
      <title>Forem: Vasille</title>
      <link>https://forem.com/vasille</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/vasille"/>
    <language>en</language>
    <item>
      <title>How we tried to create a frontend framework which can be learned in 5 minutes and which is the result</title>
      <dc:creator>Vasille</dc:creator>
      <pubDate>Sat, 01 Nov 2025 21:31:37 +0000</pubDate>
      <link>https://forem.com/vasille/how-we-tried-to-create-a-frontend-framework-which-can-be-learned-in-5-minutes-and-which-is-the-4je6</link>
      <guid>https://forem.com/vasille/how-we-tried-to-create-a-frontend-framework-which-can-be-learned-in-5-minutes-and-which-is-the-4je6</guid>
      <description>&lt;p&gt;Hi!&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to create a component
&lt;/h2&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const MyComponent = component(() =&amp;gt; {
    // component logic here
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reactive states
&lt;/h2&gt;

&lt;p&gt;To save states, there are variables in Javascript, so we will it.&lt;/p&gt;

&lt;p&gt;The rules are simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the variable name starts with &lt;code&gt;$&lt;/code&gt; than it will be reactive.&lt;/li&gt;
&lt;li&gt;If the variable name does not start with &lt;code&gt;$&lt;/code&gt; than it will be just a variable.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Example of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const MyComponent = component(() =&amp;gt; {
    let $a = 2;
    let $b = 3;
    const $sum = $a + $b;
    const $sum2 = sum($a, $b);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Side effects
&lt;/h2&gt;

&lt;p&gt;The component function is executed once, so the following side effects are present in the next functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;watch&lt;/code&gt; executes a function each time when a reactive value from the body is updated.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;beforeMount&lt;/code&gt; executes a function after data initialization and before DOM nodes mount.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;afterMount&lt;/code&gt; executes a function after the DOM nodes mount.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;beforeDestroy&lt;/code&gt; executes a function before the DOM nodes removing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const MyComponent = component(() =&amp;gt; {
    let $state = 'init';
    watch(() =&amp;gt; { console.log($state) });
    beforeMount(() =&amp;gt; { $state = "before" });
    afterMount(() =&amp;gt; { $state = "after" });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will print in console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;init
before
after
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  DOM
&lt;/h2&gt;

&lt;p&gt;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 &lt;code&gt;onclick&lt;/code&gt;/&lt;code&gt;onpress&lt;/code&gt; accept functions as value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nodes declarations
&lt;/h3&gt;

&lt;p&gt;Example of button with counter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const MyComponent = component(() =&amp;gt; {
    let $count = 'init';
    function inc() {
        $count++;
    }
    &amp;lt;button class="btn" onclick={inc}&amp;gt;
        You clicked {$count} times
    &amp;lt;/button&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;class&lt;/code&gt; attribute accepts a string array as a value; the &lt;code&gt;style&lt;/code&gt; one accepts objects as a value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Callbacks
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Example of callback usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const MyComponent = component(() =&amp;gt; {
    function sideEffect(input: HTMLInputElement) {
        input.showPicker();
    }
    &amp;lt;input type="date" callback={sideEffect}/&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Share data between compoents
&lt;/h2&gt;

&lt;p&gt;The data can be shared between components in the next ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;from parent to children via properties;&lt;/li&gt;
&lt;li&gt;from children to parent via callbacks;&lt;/li&gt;
&lt;li&gt;from children to parent and from parent to children via slots;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sharing data via properties
&lt;/h3&gt;

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

&lt;p&gt;Example of sharing data via properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Props {
    userId: string;
    $userName: string;
}
const Child = component(({userId, $userName}: Props) =&amp;gt; {
    &amp;lt;div&amp;gt;{userId} is named {$userName}&amp;lt;/div&amp;gt;;
});
const Parent = component(() =&amp;gt; {
    const id = 1;
    let $name = "First";

    // When the name is updated here
    // it will be automatically updated in the child component
   &amp;lt;Child userId={id} $userName={$name}/&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sharing data via callbacks
&lt;/h3&gt;

&lt;p&gt;The component function can return data; the returned data can be accessed in the parent component via callback.&lt;/p&gt;

&lt;p&gt;Example of using callbacks as an alternative for &lt;code&gt;forwardRef&lt;/code&gt; from &lt;code&gt;React&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Child = component(() =&amp;gt; {
    let input: HTMLInputElement|null = null;
    &amp;lt;input callback={element =&amp;gt; input = element}/&amp;gt;;
    return input;
});
const Parent = component(() =&amp;gt; {
   &amp;lt;Child callback={input =&amp;gt; { console.log(input) }}/&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sharing data via slots
&lt;/h3&gt;

&lt;p&gt;The slots are sending data to the parent component data via properties, and the parent is sharing a DOM description with the child component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Props {
    $title: string;
    slot?(props: { $name: string }): void;
}
const Child = component(({$title, slot}: Props) =&amp;gt; {
    &amp;lt;div&amp;gt;
        &amp;lt;Slot model={slot} $name={`${$title} is amazing`}/&amp;gt;
    &amp;lt;/div&amp;gt;;
});
const Parent = component(() =&amp;gt; {
    let $title = "MyApp";
    &amp;lt;Child $title={$title} slot=(($name) =&amp;gt; {
        &amp;lt;span&amp;gt;{$name}&amp;lt;/span&amp;gt;;
    })/&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the child is not sharing data with the parent, the DOM description can be included in the child tag: &lt;code&gt;&amp;lt;Child&amp;gt;&amp;lt;span&amp;gt;Text&amp;lt;/span&amp;gt;&amp;lt;/Child&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, inside the &lt;code&gt;Slot&lt;/code&gt; tag can be present a DOM description, which will be used if the parent does not fill the slot.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Logic and loops
&lt;/h2&gt;

&lt;p&gt;There are building components that operate the logic and loops: &lt;code&gt;If&lt;/code&gt;, &lt;code&gt;Else&lt;/code&gt; &lt;code&gt;ElseIf&lt;/code&gt; and &lt;code&gt;For&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example of conditional text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyComponent = component(() =&amp;gt; {
    let $count = 0;
    &amp;lt;If $codition={$count &amp;gt; 2}&amp;gt;
        Count is too big!
    &amp;lt;/If&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example of loop;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyComponent = component(() =&amp;gt; {
    const arr = [1, 2, 3];
    &amp;lt;For model={arr} slot={number =&amp;gt; {
        &amp;lt;div&amp;gt;Number is {number}&amp;lt;/div&amp;gt;
    }}/&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;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 &lt;code&gt;If&lt;/code&gt;/&lt;code&gt;Else&lt;/code&gt;; it fixes some TypeScript errors.&lt;/p&gt;

&lt;p&gt;The project is &lt;a href="https://github.com/vasille-js/vasille-js" rel="noopener noreferrer"&gt;open-source&lt;/a&gt;. For volunteers who want to help, we have a Google Form for &lt;a href="https://docs.google.com/forms/d/e/1FAIpQLScvoUvCRlbONheW1lu_ZnerXLz1pcGxhKV_q3EKs3d40csXTw/viewform?usp=header" rel="noopener noreferrer"&gt;Customer Development Interview&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for your attention!&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
