<?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: Oats〜i</title>
    <description>The latest articles on Forem by Oats〜i (@oatsi).</description>
    <link>https://forem.com/oatsi</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%2F1884126%2F3eb906fb-18a5-41df-ae73-a49db72c2c2e.png</url>
      <title>Forem: Oats〜i</title>
      <link>https://forem.com/oatsi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/oatsi"/>
    <language>en</language>
    <item>
      <title>The first official docs page for Oats~i, the open web framework, has dropped</title>
      <dc:creator>Oats〜i</dc:creator>
      <pubDate>Tue, 03 Sep 2024 13:07:24 +0000</pubDate>
      <link>https://forem.com/oatsi/the-first-official-docs-page-for-oatsi-the-open-web-framework-has-dropped-406m</link>
      <guid>https://forem.com/oatsi/the-first-official-docs-page-for-oatsi-the-open-web-framework-has-dropped-406m</guid>
      <description>&lt;p&gt;The first official docs page for Oats~i, the open web framework, has dropped. Check it out here: &lt;a href="https://oats-i.github.io/Oats-i-Docs/" rel="noopener noreferrer"&gt;https://oats-i.github.io/Oats-i-Docs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out the open source code here: &lt;a href="https://github.com/Oats-i/Oats-i" rel="noopener noreferrer"&gt;https://github.com/Oats-i/Oats-i&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow Oats~i on YouTube: &lt;a href="https://www.youtube.com/@Oatsi" rel="noopener noreferrer"&gt;https://www.youtube.com/@Oatsi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow Oats~i on X: &lt;a href="https://x.com/Oatsi_js" rel="noopener noreferrer"&gt;https://x.com/Oatsi_js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Get up to speed with our previous articles, posts, and videos, and stay subscribed for more. Let's build with Oats~i!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Oats~i is now on YouTube</title>
      <dc:creator>Oats〜i</dc:creator>
      <pubDate>Wed, 28 Aug 2024 16:57:49 +0000</pubDate>
      <link>https://forem.com/oatsi/oatsi-is-now-on-youtube-23m7</link>
      <guid>https://forem.com/oatsi/oatsi-is-now-on-youtube-23m7</guid>
      <description>&lt;p&gt;Oats~i videos are now available on YouTube, making learning the web framework much easier for folks who hate reading documentation 😜&lt;/p&gt;

&lt;p&gt;Give us a like and subscribe here: &lt;a href="https://www.youtube.com/@Oatsi" rel="noopener noreferrer"&gt;https://www.youtube.com/@Oatsi&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Web App with Oats~i – Lesson 2: Reactivity and Data Manager</title>
      <dc:creator>Oats〜i</dc:creator>
      <pubDate>Sat, 24 Aug 2024 19:01:47 +0000</pubDate>
      <link>https://forem.com/oatsi/build-a-web-app-with-oatsi-lesson-2-reactivity-and-data-manager-p66</link>
      <guid>https://forem.com/oatsi/build-a-web-app-with-oatsi-lesson-2-reactivity-and-data-manager-p66</guid>
      <description>&lt;p&gt;Welcome to the second lesson of the Build a Web App with Oats~i series, where we’re now building a real project using Oats~i and learning some of the core concepts of the web framework.&lt;/p&gt;

&lt;p&gt;In the previous lesson, we built a simple web app with two fragments, one for showing random cat images and another for searching movies using publicly available APIs. We only wired the interfaces, and left the reactivity bit for today’s lesson.&lt;/p&gt;

&lt;p&gt;If you didn’t read the previous tutorial, &lt;a href="https://dev.to-web-app-with-oatsi-lesson-1-fragments-routing-and-default-routes-2en0"&gt;find it here&lt;/a&gt;. This is a continuation of that lesson.&lt;/p&gt;

&lt;p&gt;Also, I strongly recommend you clone and run the final project beforehand. This helps shorten the written tutorial and have it focus mostly on explaining what’s happening as far as Oats~i is concerned.&lt;/p&gt;

&lt;p&gt;Find the completed project for lesson 2 here: &lt;a href="https://github.com/Ian-Cornelius/Lesson-2---Reactivity-and-Data-Manager" rel="noopener noreferrer"&gt;https://github.com/Ian-Cornelius/Lesson-2---Reactivity-and-Data-Manager&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run npm install, then npm run dev to run it. &lt;/p&gt;

&lt;p&gt;In the http cats fragment, click on “meeow” to get a new random cat image based on http status codes. In the movies fragment, search for a movie and see the results get populated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting the API Key for Movies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To run the movies API, you need to get a key from themoviedb.org. This video will help you do this in under five minutes &lt;a href="https://www.youtube.com/watch?v=FlFyrOEz2S4" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=FlFyrOEz2S4&lt;/a&gt; (Use the access token instead, and replace it at the getReqBody method, where we have &lt;code&gt;${\_CONFIG.MoviesAPIKey}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now, let’s get into it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Adding Reactivity to Our Web App
&lt;/h1&gt;

&lt;p&gt;We add reactivity to an Oats~i web app using the data manager. This is a built-in utility that allows you to perform data mutations and have the process and result of these mutations broadcasted to only the views you want to respond to these changes.&lt;/p&gt;

&lt;p&gt;That means, instead of data and views being strongly coupled together as long as they’re defined in the same file, Oats~i allows you to choose which views you want to bind to what data, whether they’re defined in the same file or not.&lt;/p&gt;

&lt;p&gt;Let’s look at it practically using the example project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The http_cats_main_fragment.js File
&lt;/h2&gt;

&lt;p&gt;Open the http_cats_main_fragment.js file and look for the following bits of code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Definition of the HTTP Cats Data Model
&lt;/h3&gt;

&lt;p&gt;Just above where we define the HTTPCatsMainFragment class, we have the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
 * @typedef HTTPCatsModel
 * @property {string} img
 */

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above uses JSDoc to define a type called HTTPCatsModel, with a property img of type string. Doing this is &lt;strong&gt;very&lt;/strong&gt; &lt;strong&gt;important&lt;/strong&gt; if we are to have the data manager accurately interpret and represent our types as we use it. &lt;/p&gt;

&lt;p&gt;You’ll see this application shortly.&lt;/p&gt;

&lt;p&gt;(A typescript type definition exported from a typescript declaration file [d.ts] will also work)&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up Our Data Manager in the Constructor
&lt;/h3&gt;

&lt;p&gt;It’s highly recommended that you set up your data manager in the constructor of an Oats~i fragment or view panel. This ensures that other functions of the data manager, such as server-side hydration, happen right before the fragment renders its view, so that any attached view managers find it ready.&lt;/p&gt;

&lt;p&gt;We’ll handle server side rendering later.&lt;/p&gt;

&lt;p&gt;For now, inside the HTTPCatsMainFragment class definition, let’s look at the following lines 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;
constructor(args){

        super(args);

        //set up list of random codes
        this.randomCodesList = [100, 101, 102, 103, 200, 201, 202, 203, 204, 205, 206, 207, 208, 214, 226, 
                                300, 301, 302, 303, 304, 305, 307, 308, 400, 401, 402, 403, 404, 405, 406,
                                407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 420, 421, 422,
                                423, 424, 425, 426, 428, 429, 431, 444, 450, 451, 497, 498, 499, 500, 501,
                                502, 503, 504, 506, 507, 508, 509, 510, 511, 521, 522, 523, 525, 530, 599];

        //create data manager instance
        /**
         * @type {DataManager&amp;lt;HTTPCatsModel&amp;gt;}
         */
        this.httpCatsDataManager = new DataManager({

            primaryLifeCycleObject: this.getLifeCycleObject(),
            masterAPIOptions: {

                reqUtils: new LifecycleRemoteRequestUtils(this.getLifeCycleObject())
            }
        });

        //set up the data manager
        this.setUpDataManager();

        //set up the view manager
        /**
         * @type {StandardViewManager&amp;lt;HTTPCatsModel, "MODEL_ROOT"&amp;gt;}
         */
        this.httpCatsStandardViewManager = null;
        this.setUpViewManager();
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break this code down, looking into the important lines of code concerning reactivity and data management.&lt;/p&gt;

&lt;p&gt;The instance variable randomCodesList just holds a list of all valid codes we can use for our http cats API. It’s only for supporting the app’s “business” logic.&lt;/p&gt;

&lt;p&gt;The instance variable httpCatsDataManager is the first important bit of code as far as reactivity is concerned. It holds the instance of our data manager, which manages data specifically of the type HTTPCatsModel that we had defined earlier in JSDoc format.&lt;/p&gt;

&lt;p&gt;We help intellisense understand this using the JSDoc directive&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
  * @type {DataManager&amp;lt;HTTPCatsModel&amp;gt;}
  */

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Placed right above the httpCatsDataManager definition. This is a very important step that will make using the data manager, at least in a JavaScript environment, much easier for you. All methods will now be able to infer the right types, making performing data mutations within various scopes much easier, improving the developer experience. &lt;/p&gt;

&lt;p&gt;To create this data manager instance, we invoke new on the DataManager class, and pass in the lifecycle object and request utils instance that the data manager will use.&lt;/p&gt;

&lt;h4&gt;
  
  
  Lifecycle Awareness
&lt;/h4&gt;

&lt;p&gt;Data managers in Oats~i are lifecycle aware. This means that they operate only when the fragment or view panel they’re attached to is active/alive. If we are to navigate away from our http cats main fragment, the data manager, using the lifecycle object/instance, will notice the destruction of its attached fragment and perform the necessary clean up to ensure we don’t have any null pointers or undesired side effects from ongoing mutations. &lt;/p&gt;

&lt;p&gt;So, you don’t have to worry about lifecycle management.&lt;/p&gt;

&lt;h4&gt;
  
  
  Request Utils
&lt;/h4&gt;

&lt;p&gt;The final crucial constructor argument for data manager is the request utils instance, where we use the LifecycleRemoteRequestUtils class to give the data manager a request util that is also lifecycle aware, in context of the attached fragment.&lt;/p&gt;

&lt;p&gt;A request util in Oats~i is a utility that makes network requests, using XMLHttpRequest. It wraps up most of the boiler plate, making network calls much easier to invoke.&lt;/p&gt;

&lt;p&gt;You can use the Standard or Lifecycle variant of remote request utils, with the Lifecycle variant being the most recommended because it automatically handles lifecycle events for you, aborting running network calls or skipping their callbacks in case it notices the attached fragment is no longer running.&lt;/p&gt;

&lt;p&gt;Next, we call the setUpDataManager() method, which we’ll break down next.&lt;/p&gt;

&lt;h4&gt;
  
  
  Define and Implement the setUpDataManager() Method
&lt;/h4&gt;

&lt;p&gt;Just after the constructor definition, we have setUpDataManager() method. This method is user defined, not a standard method provided in Oats~i. We’re using it to finalize setting up our data manager, specifically, adding the necessary network interface that will allow us to access our API from the data manager.&lt;/p&gt;

&lt;p&gt;The code looks something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
setUpDataManager(){

        const getDataManager = () =&amp;gt; this.httpCatsDataManager;
        this.httpCatsDataManager.setScopedAPIOptions("MODEL_ROOT", {

            MODEL_ROOT: {

                networkInterface: {

                    async getReqBody(reqAddr, updatedModel, mutation, completeOldModel){

                        return {

                            reqMethod: "GET",
                            responseType: "blob"
                        }
                    },
                    async onDataLoadPostProcess(reqAddr, response, newData, oldData, mutation, mappedDataId, extras){

                        //create url from blob
                        const url = URL.createObjectURL(response)
                        const finalData = {};
                        getDataManager().spawnPartialShellModel("img", url, finalData, null);
                        return {

                            data: finalData,
                            response: response
                        }
                    },
                    onDataLoadError(reqAddr, response, newData, oldData, mutation){

                        return {

                            response: response
                        }
                    }
                }
            }
        });
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break down this code.&lt;/p&gt;

&lt;p&gt;Oats~i’s data manager assumes that the data it manages must have an external resource its sourced from, and other CRUD operations are performed at. To access this resource, the data manager uses a combination of the request utils instance we gave it and a network interface to make the appropriate requests that the developer needs.&lt;/p&gt;

&lt;p&gt;This network interface allows the request utils to get the request body and other information such as headers and request method, post process the response, and communicate the API errors in case of a problem.&lt;/p&gt;

&lt;p&gt;In our project, we set up a network interface that will allow us to make the right request to our http cats api, and have the desired result returned.&lt;/p&gt;

&lt;p&gt;To do this, we use the data manager method setScopedAPIOptions which allows us to set a network interface for a given scope of our data (more on scopes later).&lt;/p&gt;

&lt;p&gt;So, we invoke this method and provide our network interface, within which we implement three methods: getReqBody, onDataLoadPostProcess, and onDataLoadError. &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;getReqBody&lt;/strong&gt; method gets the parameters of our network request. This includes the request body, headers, response type, request method, and any other parameter needed to make a successful request. &lt;/p&gt;

&lt;p&gt;In our case, we need to specify the request method as “GET” and tell XMLHttpRequest that the expected response type is a blob.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;onDataLoadPostProcess&lt;/strong&gt; method allows us to post process the response from our server/API, and turn it into our data manager’s scoped model. In our case, the API responds with an image blob which we have to transform into an image url that we’ll use to show the image in our view.&lt;/p&gt;

&lt;p&gt;After creating a local url from the blob, we use the data manager method spawnPartialShellModel() to create an object of type HTTPCatsModel that has the img key set to the url value.&lt;/p&gt;

&lt;p&gt;This method is powerful for creating and expanding a model based on values of its specific keys. We’ll explore it and many other methods in the advanced lessons involving the data manager. For now, that’s all you need to know.&lt;/p&gt;

&lt;p&gt;Finally, onDataLoadError captures any API error responses and allows us to format it in a way that suits our application, if we want to. In this example, we’re just providing the error response as given by the server.&lt;/p&gt;

&lt;p&gt;And that’s just about it when it comes to defining a network interface for any of your data manager instances. However, there’s one very important thing we haven’t touched on yet.&lt;/p&gt;

&lt;h5&gt;
  
  
  Scoping
&lt;/h5&gt;

&lt;p&gt;Scoping is the most important concept you need to understand if you’re to fully utilize and understand the data manager in Oats~i.&lt;/p&gt;

&lt;p&gt;The data manager treats your model as a scoped unit of data, meaning it can be broken down from its primary form to other smaller forms that represents bits of the data. Let’s take our HTTPCatsModel for instance.&lt;/p&gt;

&lt;p&gt;It’s basically an object of the type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
    img: string
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data manager views it as an object breakable into the scopes:&lt;/p&gt;

&lt;p&gt;MODEL_ROOT -&amp;gt; which represents the &lt;strong&gt;whole&lt;/strong&gt; model, ie. &lt;/p&gt;

&lt;p&gt;{ &lt;/p&gt;

&lt;p&gt;img: string&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;“img” -&amp;gt; which represents a value of string.&lt;/p&gt;

&lt;p&gt;You can view a scope as a dot connected path of keys that lead to a value in your model.&lt;/p&gt;

&lt;p&gt;So, if say my HTTPCatsModel also had another key in the main object of type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
    …
myOtherKey: {
        innerKey: string
               }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’d have new scopes defined as:&lt;/p&gt;

&lt;p&gt;myOtherKey -&amp;gt; {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    innerKey: string

       }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;myOtherKey.innerKey -&amp;gt; string&lt;/p&gt;

&lt;p&gt;So, how does this apply to our data manager, first looking at the network interface?&lt;/p&gt;

&lt;p&gt;From our example project, you’ll notice that the network interface is scoped. This means that, inherently, this interface is used to make network calls for data of the type referred to by the scope. &lt;/p&gt;

&lt;p&gt;In our case, our setScopedAPIOptions() call to the data manager uses the scope “MODEL_ROOT” to mean the network interface we’ve set up will be used for network calls affecting the MODEL_ROOT scope or our whole model.&lt;/p&gt;

&lt;p&gt;By doing this, the data manager also adjusts the type of data it expects when onDataLoadPostProcess returns, in our case, inferring it as our whole model or an array of our complete model, if our API returns a list.&lt;/p&gt;

&lt;p&gt;If we were to use “img” as our scope for the data manager, the inferred return type for our data in the method onDataLoadPostProcess would have been string (data manager doesn’t infer a string array because the scope is not MODEL_ROOT”. Only MODEL_ROOT scopes can also return an array).&lt;/p&gt;

&lt;p&gt;The data manager allows you to set a network interface for each valid scope of your model. When you request a mutation that involves network activity, it will use the network interface for that scope to get the parameters needed to make a successful request and post process the response to the expected type.&lt;/p&gt;

&lt;p&gt;So now, we have a way of accessing our http cats API, through the “MODEL_ROOT” scoped network interface, which will return results that will affect our whole model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Up Our View Manager
&lt;/h3&gt;

&lt;p&gt;With the network interface set, our data manager is ready to load data from the network and update its internal model to the returned data/response. However, there’s one bit left.&lt;/p&gt;

&lt;p&gt;How will we know when any of these mutations are happening?&lt;/p&gt;

&lt;p&gt;That’s where the view manager comes in.&lt;/p&gt;

&lt;p&gt;A view manager is an Oats~i utility that manages a set of views whose dynamicity is dependent on the state or mutation of data held by the data manager, within that scope. So, view managers are scoped as well, to give you granular control over the reactivity of your view to data changes.&lt;/p&gt;

&lt;p&gt;What this means is that if we’re to load data for the scope “MODEL_ROOT”, which will essentially get us a new cat image, the data manager will broadcast this information to any view manager attached to that scope (MODEL_ROOT) or its children or direct parent, and have these view managers trigger view updates that will tell the user what the app is doing.&lt;/p&gt;

&lt;p&gt;Let’s view this practically.&lt;/p&gt;

&lt;p&gt;In our project, after the call to setUpDataManager() in our constructor, we initialize an instance variable for httpCatsViewManager then call the setUpViewManager() method. &lt;/p&gt;

&lt;p&gt;Note the type we assign to the instance variable httpCatsViewManager. It’s a standard view manager of the same model as our http cats data manager (HTTPCatsModel), but for the scope “MODEL_ROOT”.&lt;/p&gt;

&lt;p&gt;What this means is that this view manager will only react to data changes or mutations in the MODEL_ROOT scope or its children (keys nested inside the referenced model), which in this case will be “img.”&lt;/p&gt;

&lt;p&gt;Let’s look at the setUpViewManager() method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
setUpViewManager(){

        //create the instance
        this.httpCatsStandardViewManager = new StandardViewManager(this.httpCatsDataManager, {

            scope: "MODEL_ROOT",
            id: "HTTPCatsStandardViewManager",
            viewOptions: {

                parentNodeID: "cats-results",
                reinflateContentViewNodeID: "new-cat",
                reinflateRootViewOnNewModel: true
            },
            lifecycleOptions: {

                instance: this.getLifeCycleObject()
            }
        });

        //register hooks
        this.httpCatsStandardViewManager.registerViewDataHooks({

            root: {

                builder: {

                    inflateRoot: (data) =&amp;gt; {

                        return {

                            inflatedView: require("../views/new-cat/new_cat.hbs")(data)
                        }
                    },
                    onViewAttach: (modelId, data, viewNode, mappedDataId, extras) =&amp;gt; {


                    },
                    onViewDetach: (modelId, data, viewNode, mappedDataId, completeCb) =&amp;gt; {

                        completeCb();
                    }
                },
                prePostRootAttachHooks: {

                    onMutate: (modelId, mutation, newData, oldData, parentNode, extras) =&amp;gt; {

                        //Show loading
                        //@ts-expect-error
                        parentNode.insertAdjacentHTML("beforeend", require("../views/loading-ui/loading_ui.hbs")({ wittyMsg: "Just a meow-ment" }));
                    },
                    onCommit: (modelId, mutation, newData, oldData, parentNode, extras) =&amp;gt; {

                        //remove loading
                        parentNode.removeChild(parentNode.querySelector("#loading-ui"));
                    },
                    onCancel: (modelId, mutation, newData, oldData, parentNode, response, extras) =&amp;gt; {

                        //remove loading
                        parentNode.removeChild(parentNode.querySelector("#loading-ui"));
                    },
                    onError: (modelId, mutation, data, failedData, response, parentNode, retryCb, extras) =&amp;gt; {

                        //not needed
                    }
                }
            }
        }, null);

        //set this view manager in data manager for the "MODEL_ROOT" scope
        this.httpCatsDataManager.setViewManager("MODEL_ROOT", this.httpCatsStandardViewManager, null);
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break this code down.&lt;/p&gt;

&lt;h4&gt;
  
  
  Instantiating the View Manager
&lt;/h4&gt;

&lt;p&gt;The first block of code creates a new instance of the StandardViewManager class. &lt;/p&gt;

&lt;p&gt;View managers in Oats~i are currently of two variants. A standard view manager and a list view manager.&lt;/p&gt;

&lt;p&gt;A standard view manager manages standard views with only one content node i.e only one main view. &lt;/p&gt;

&lt;p&gt;A list view manager manages list views with several content nodes or more than one content view. &lt;/p&gt;

&lt;p&gt;Therefore, if your data will only present and manipulate one “piece” of data, a standard view manager is an excellent choice for intercepting mutations and triggering view updates based on that.&lt;/p&gt;

&lt;p&gt;However, if your data will be an array or list, a list view manager will be the best choice to not only intercept mutations but also do so at an item-to-item level. &lt;/p&gt;

&lt;p&gt;In our http cats scenario, we’re only getting a single image from the server to update our model. Therefore, a standard view manager is more than enough for our needs.&lt;/p&gt;

&lt;p&gt;We instantiate by passing a few crucial arguments such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;scope:&lt;/strong&gt; This is the scope of data that the view manager will react to. In our case it’s the MODEL_ROOT (note how it mirrors the scope we gave in the JSDoc type definition, to allow intellisense to work properly).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;id:&lt;/strong&gt; (optional) Gives the view manager an id. If not provided, the view manager will be provided an automatic one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;viewOptions:&lt;/strong&gt; an object which contains:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;parentNodeID:&lt;/strong&gt; the ID of the parent node which encompasses our standard view, or the view within which we’ll be rendering changes based on mutations.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If you look at the markup for http_cats_fragment.hbs, we provide the id for this node: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;reinflateContentViewNodeID:&lt;/strong&gt; the ID of the actual content node that will be rendered based on data mutations/changes. For our case, this is the id of the parent node for the new_cat.hbs view that we inflate for the final loaded model. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;reinflateRootViewOnNewModel:&lt;/strong&gt; a flag which tells the view manager whether it should create a new content node if a new model is loaded. This allows us to clear data, have the old view removed, then a new view loaded after we get the new cat image. (We’ll see a different variant to this for the standard view manager later).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;lifecycleOptions:&lt;/strong&gt; an object which contains:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;lifecycleInstance:&lt;/strong&gt; the instance of the lifecycle object which will be used to listen to lifecycle changes in the hosting fragment. What this means is that view managers are also lifecycle aware, so they’ll clean up and ensure there are no side effects when the host fragment is destroyed due to route changes. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This basically sets up the standard view manager. However, there’s one more thing left. To actually get to know when model mutations are happening and update the view based on that, we need to register data hooks to the view manager. This is done by the line that invokes the view manager method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
registerDataHooks();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method takes in two arguments, the first being the root hooks and the next being the component hooks.&lt;/p&gt;

&lt;p&gt;Let’s break down each.&lt;/p&gt;

&lt;h4&gt;
  
  
  Root Hooks
&lt;/h4&gt;

&lt;p&gt;Root hooks are the primary hooks called before and after a content node or view node has been attached to the DOM by the view manager, and are also called to provide the inflated view that should constitute the view node and inform you of their attachment and detachment to the DOM.&lt;/p&gt;

&lt;p&gt;Let’s use our project as an example.&lt;/p&gt;

&lt;h5&gt;
  
  
  Builder Functions
&lt;/h5&gt;

&lt;p&gt;We provide a root hook with the builder functions inflateRoot, onViewAttach, and onViewDetach. These methods are standard across all view managers and simply mean the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;inflateRoot&lt;/strong&gt; is called to get the content view that the view manager should attach to the DOM, inside the node with the parentNodeID. This view is supplied as a html string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;onViewAttach&lt;/strong&gt; is called** after** the view manager attaches the content view is attached to the DOM. It’s viewNode parameter refers to the inflated or attached view node, from the inflateRoot method.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;onViewDetach&lt;/strong&gt; is called when the view manager is about to remove the content or view node from the DOM or more specifically, the parent node with the parentNodeID. It gives you some time to animate the detachment, if you’re running transitions.
##### Pre-Post Root Attach Hooks
This is a very special set of data hooks that allow you to perform view operations at the grand scope or context of the parent node or view managed by the view manager. This is simply the node with the id equal to the parentNodeID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These hooks avail four crucial methods which include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;onMutate –&lt;/strong&gt; Called when data affecting the view manager’s scope is being mutated or changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;onCommit –&lt;/strong&gt; Called when data affecting the view manager’s scope has been committed to the data manager’s model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;onError –&lt;/strong&gt; Called when a mutation affecting data of the view manager’s scope has failed, and the user needs to be informed to retry directly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;onCancel –&lt;/strong&gt; Called when a mutation affecting data of the view manager’s scope has failed and is being aborted (not retried). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This set of functions are great for showing UI elements such as loading screens, error messages on fail, and retry buttons to retry a failed data mutation. &lt;/p&gt;

&lt;h4&gt;
  
  
  Component Hooks
&lt;/h4&gt;

&lt;p&gt;Component hooks provide even finer grained reactivity towards data held by the larger view manager’s scope. They typically avail the same methods as pre-post root attach hooks, but the view node parameter refers to the specific content node showing the given piece of data.&lt;/p&gt;

&lt;p&gt;For instance, in our example, if we wanted to say, update the value of “img” as the property changes due to a user upload or update, we could simply implement a component hook of that scope and then make the changes to the DOM child elements of our content node showing that particular data.&lt;/p&gt;

&lt;p&gt;We’ll cover this more later. For now, let’s just understand what a view manager and hooks are. &lt;/p&gt;

&lt;p&gt;In our project, at the inflateRoot method, we get the view provided by new_cat.hbs file which will render our cat image. We attach and remove a loading ui to the parent node during onMutate and onCancel and onCommit respectively at the prePostRootAttachHooks, because they allow DOM manipulation to the parentNode of the entire view. &lt;/p&gt;

&lt;p&gt;Finally, we set this view manager as the view manager for data of the “MODEL_ROOT” scope in the data manager using the data manager method setViewManager(), passing “MODEL_ROOT” as our scope.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finishing Up
&lt;/h3&gt;

&lt;p&gt;At this point, our data manager is fully set. It has a network interface that allows it to retrieve data at the “MODEL_ROOT” scope from the network (so, our cat image), and has a view manager set up at the same scope to react to these mutations, so the user can see when we’re loading new data and the new data that we’ve loaded.&lt;/p&gt;

&lt;p&gt;We put everything together by attaching listeners to our “get-cat” button and trigger data loading from the data manager.&lt;/p&gt;

&lt;p&gt;Oats~i provides the onUIBind method in fragments in which you can bind event listeners and do other view binding work to your fragment once its view has been rendered.&lt;/p&gt;

&lt;p&gt;Our code in onUIBind looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
/**
     * @type {AppMainFragment['onUIBind']}
     */
    onUIBind(isServerSide){

        //set up click listener on "meeow" button
        document.getElementById("get-cat").addEventListener("click", (e) =&amp;gt; {

            //clear existing data
            if(this.httpCatsDataManager.hasData()){

                this.httpCatsDataManager.flushAllData();
            }
            //load new random cat
            const statusCode = this.randomCodesList[RandomNumberCharGenUtils.generateRandomInteger(0, this.randomCodesList.length)];
            //move headers code to main repo. Then, finish here
            this.httpCatsDataManager.loadData("MODEL_ROOT", null, {}, null, `/api/cats/${statusCode}`).catch((err) =&amp;gt; {

                //do this to avoid seeing the uncaught error in promise error
                //Something cool - uncomment the line below and see the error you get at times when you click on "meeow" in quick succession
                // console.error(err);
            });
        });
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We simply attach a click listener to the “get-cat” button, and use it to trigger a data load through the data manager.&lt;/p&gt;

&lt;p&gt;We do this using the data manager method loadData() which takes several arguments. The most important ones for this project are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;scope:&lt;/strong&gt; The scope of the load operation. In our case, this is the “MODEL_ROOT” scope. This value is important because, by default, it dictates which network interface will be used for the network operation (which in this case, will be the “MODEL_ROOT” scope network interface).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;overrideLoadNewAddr:&lt;/strong&gt; the address we’ll use for this load operation. You can always override this address in the getReqBody of our network interface for various purposes such as cache bursting or adding new parameters or queries depending on your API design. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The loadData() method will use the network to load the new data, using your network interface of the “MODEL_ROOT” scope, and update the appropriate view managers for the scope as the mutation happens and commits.&lt;/p&gt;

&lt;p&gt;Also, if we had loaded and committed some data before, which we can know using the data manager method hasData(), we can clear this data using the flushAllData() method then load a fresh image/data. &lt;/p&gt;

&lt;p&gt;And that’s just about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Movies Main Fragment
&lt;/h2&gt;

&lt;p&gt;I won’t get deep into explaining what’s happening in the movies main fragment as far as data management and reactivity is concerned because the concept is exactly the same.&lt;/p&gt;

&lt;p&gt;The only difference is, instead of a standard view manager, we use a list view manager which uses classes to query the content view nodes instead of an id, because it will load several of these (and ids in html MUST be unique).&lt;/p&gt;

&lt;p&gt;Everything else works the same.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sign Up and Follow for the Next Tutorial
&lt;/h1&gt;

&lt;p&gt;That’s just about it for lesson 2. In the next lesson, we’ll look into view panels and their usefulness in spawning new view elements in your fragment that are either directly invoked or triggered by queries in your route.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5wwd4rpyalkeoyjyu0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5wwd4rpyalkeoyjyu0g.png" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See you then.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support Oats~i&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can support the development of Oats~i through &lt;a href="https://www.patreon.com/IanOmondi" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;*** or &lt;a href="https://buymeacoffee.com/oats_i" rel="noopener noreferrer"&gt;buy me a coffee&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Web App with Oats~i – Lesson 1: Fragments, Routing, and Default Routes</title>
      <dc:creator>Oats〜i</dc:creator>
      <pubDate>Tue, 20 Aug 2024 21:18:50 +0000</pubDate>
      <link>https://forem.com/oatsi/build-a-web-app-with-oatsi-lesson-1-fragments-routing-and-default-routes-2en0</link>
      <guid>https://forem.com/oatsi/build-a-web-app-with-oatsi-lesson-1-fragments-routing-and-default-routes-2en0</guid>
      <description>&lt;p&gt;Today, we’re not talking theory or starter projects. We’re building our very own, first ever, Oats~i web app in a tutorial. &lt;/p&gt;

&lt;p&gt;If you’re reading this for the first time, briefly check out &lt;a href="https://dev.to/oatsi/build-a-web-app-with-oatsi-setting-up-53al"&gt;the start&lt;/a&gt; of the “Build a Web with Oats~i” series to learn what Oats~i is, a bit of how it works and how to set it up in your frontend development environment.&lt;/p&gt;

&lt;p&gt;In this tutorial, we’re going to build our very own Oats~i web app that will have two pages, one where we’ll show random cat pictures and another where we’ll search and show movies based on titles, all using publicly available APIs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tcdpeh2765xr0vx8oac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tcdpeh2765xr0vx8oac.png" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmeak7v87vt2gvf9rdl7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmeak7v87vt2gvf9rdl7m.png" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, with so much to learn, we’ll be taking things one step at a time. So, in lesson 1, our objective is to set up our routing and fragments and showcase how to set up a default route.&lt;/p&gt;

&lt;p&gt;Our final project for today’s lesson will look something like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslwy1bn6pq7kn765b5w4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslwy1bn6pq7kn765b5w4.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmztqiogk6z8zg6wojcy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmztqiogk6z8zg6wojcy.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to run the final code before we get started, or want to follow along directly, find the source code here: &lt;a href="https://github.com/Ian-Cornelius/Oats-i-Lesson-1---Fragments-Routes-and-Default-Route" rel="noopener noreferrer"&gt;https://github.com/Ian-Cornelius/Oats-i-Lesson-1---Fragments-Routes-and-Default-Route&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Clone the repo, navigate to the project’s root folder, open the terminal, then run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait for the installation to complete, then run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm run dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the url given in the terminal in your browser, navigate around, then follow along.&lt;/p&gt;

&lt;p&gt;Also, in this whole series, I’ll assume you’re familiar with html and css in general, to ensure we only stick to the bits of code that matter when creating an Oats~i web app. There are no advanced HTML or CSS knowledge needed to get started with Oats~i. Just the basics.&lt;/p&gt;

&lt;p&gt;Also, I assume you have node and npm installed already.&lt;/p&gt;

&lt;p&gt;Now, let’s dive in!&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting Up
&lt;/h1&gt;

&lt;p&gt;We’ll quickly set up our project using the Oats~i cli. Create a new folder where you want to run Oats~i, navigate to it, open the terminal, then run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npx oats-i-cli

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts and wait for the installation to complete.&lt;/p&gt;

&lt;p&gt;You’ve just set up a complete Oats~i development environment. Now let’s get to deleting and editing the files in the starter project that we don’t need.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deleting Files
&lt;/h1&gt;

&lt;p&gt;First, navigate to src -&amp;gt; app -&amp;gt; index -&amp;gt; assets and delete all files under that folder.&lt;/p&gt;

&lt;p&gt;Then, navigate to src -&amp;gt; app -&amp;gt; fragments and delete the about and home folders.&lt;/p&gt;

&lt;h1&gt;
  
  
  Create the Cats and Movies Fragments
&lt;/h1&gt;

&lt;p&gt;Oats~i renders views or pages primarily through a fragment system. A fragment is basically a view unit, comprising of components or elements necessary to show visual detail or data.&lt;/p&gt;

&lt;p&gt;Let’s take the case of our tutorial project.&lt;/p&gt;

&lt;p&gt;We’ll have a page where a user can click on a button and have random cat images shown to them based on randomly selected http codes, using the http-cat API. This will be the home page or “/” route.&lt;/p&gt;

&lt;p&gt;On the other page, the user will have a search bar and button where they can input a movie title and search for it using the movies API. This is the movies page or “/movies” route.&lt;/p&gt;

&lt;p&gt;We want the user to be able to navigate between these two pages, with the right view being shown when in the home page or “/” route and movies page or “/movies” route respectively.&lt;/p&gt;

&lt;p&gt;These views are our fragments. Here’s a visualization to help make this concept clearer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnz54r8jbvwlrwaolelos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnz54r8jbvwlrwaolelos.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F51i7mzl4eyzdhfkvbdl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F51i7mzl4eyzdhfkvbdl7.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By this logic, our Oats~i web app for this project will have two fragments. Let’s create these two, each having its own folder where its complete code is contained.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cats Fragment Folder
&lt;/h2&gt;

&lt;p&gt;Navigate to src -&amp;gt; app -&amp;gt; fragments then create a new folder named “http-cats”. This folder will hold the source code for the http-cats fragment in our Oats~i app, shown when the user navigates to the &lt;br&gt;
“/” route.&lt;/p&gt;

&lt;p&gt;Inside the “http-cats” folder, create new folders named views, styles, assets, and scripts.&lt;/p&gt;

&lt;p&gt;The views folder will hold the view templates for our http-cats fragment. The styles folder will hold the css files, the assets folder will hold the asset files (images, etc), and the scripts folder will hold our javascript files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/strong&gt; These folder structures are not a strict enforcement by Oats~i but rather a logical project structure that I find to work best for most cases.&lt;/p&gt;

&lt;p&gt;Now, let’s write the JavaScript source file that will actually render our http-cats fragment.&lt;/p&gt;
&lt;h3&gt;
  
  
  Write the Http-Cats Fragment Source File
&lt;/h3&gt;

&lt;p&gt;Inside the scripts folder, create a new file named http_cats_main_fragment.js. Paste the following code inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
//import styles
import "../styles/http_cats.css";

import AppFragmentBuilder from "oats-i/fragments/builder/AppFragmentBuilder";
import AppMainFragment from "oats-i/fragments/AppMainFragment"

class HTTPCatsMainFragment extends AppMainFragment{

    async initializeView(cb){

        //@ts-expect-error cannot find module (for view)
        const uiTemplate = require("../views/http_cats_fragment.hbs")();
        this.onViewInitSuccess(uiTemplate, cb);
    }
}

const httpCatsMainFragmentBuilder = new AppFragmentBuilder(HTTPCatsMainFragment, {

    localRoutingInfos: null,
    viewID: "http-cats-main-fragment",
});
export default httpCatsMainFragmentBuilder;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s break it down.&lt;/p&gt;

&lt;h4&gt;
  
  
  Importing CSS Files (Styling)
&lt;/h4&gt;

&lt;p&gt;The first line imports our css file, used to style our http-cats fragment view. Webpack handles loading this file into our final HTML file using the css loader, style loader, and html webpack plugin we’d configured before.&lt;/p&gt;

&lt;h4&gt;
  
  
  AppMainFragment, AppFragmentBuilder (and AppChildFragment Classes - Fragment Classes)
&lt;/h4&gt;

&lt;p&gt;The next lines import the AppMainFragment class and the AppFragmentBuilder class.&lt;/p&gt;

&lt;p&gt;When building Oats~i fragments, you’ll be extending from either of two fragment classes. These are the main fragment or child fragment class. &lt;/p&gt;

&lt;p&gt;The main fragment is the parent fragment view of your page or route. Its content is encapsulated within a div element, given the id passed in as the viewID when instantiating the AppFragmentBuilder class. This content is then placed inside the  tag which you put inside the  tag.&lt;/p&gt;

&lt;p&gt;There can only be one main fragment per route or page. Any other view that will be rendered by a fragment afterwards must be from a child fragment. You can picture it this way using a HTML markup tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;app-root&amp;gt;
    &amp;lt;main-fragment&amp;gt;
        &amp;lt;div id=”{viewID}”
            &amp;lt;!-- main fragment content --&amp;gt;
            &amp;lt;child-fragment id=”{childFragmentID}”&amp;gt;
                &amp;lt;div id=”{viewID (childfragment)}”&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;/child-fragment&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/main-fragment&amp;gt;
&amp;lt;/app-root&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s why, as you’ll observe later when looking at setting up routes, we define a target which builds a main fragment, then supply nested child fragments which build child fragments in order of their rendering in the HTML tree, from the main-fragment.&lt;/p&gt;

&lt;p&gt;This way, Oats~i can sequentially render your fragments and therefore views, without conflict, and swap them easily based on their position in the tree.&lt;/p&gt;

&lt;p&gt;We’ll add a child fragment to this project later. For now, let’s just grasp the base concept of a fragment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementing the AppMainFragment Class
&lt;/h4&gt;

&lt;p&gt;What you’ll learn here and in more tutorials involving fragments will be exactly how you’ll implement any fragment class, regardless of whether it’s inherited from a main or child fragment class.&lt;/p&gt;

&lt;p&gt;In our example, we’re only interested in overriding one method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
async initializeView(cb)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method is called by Oats~i when it’s building a fragment to retrieve its view template as a html string. In our case, we require our view template file for the http-cats fragment using the line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const uiTemplate = require("../views/http_cats_fragment.hbs")();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The view file is a handlebars template. We’ll create and implement it shortly.&lt;/p&gt;

&lt;p&gt;After templating our view into a html string, we now pass it to the internal method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
this.onViewInitSuccess(uiTemplate, cb);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling this method informs the fragment that we’ve completed templating our view and it can proceed to the next build phase.&lt;/p&gt;

&lt;p&gt;And for our purposes in this tutorial, that’s just about it. Our fragment now has a view to attach, and we don’t have any buttons or listeners to bind yet. We’ll handle that in our next tutorial. But for now, this fragment is set to go. &lt;/p&gt;

&lt;p&gt;Except for one tiny step.&lt;/p&gt;

&lt;h4&gt;
  
  
  AppFragmentBuilder
&lt;/h4&gt;

&lt;p&gt;Oats~i builds fragments by first instantiating them when they’re needed for a specific route. It does this through the AppFragmentBuilder class. &lt;/p&gt;

&lt;p&gt;We instantiate this class with the class definition of our fragment and it’s constructor arguments that will be passed to it on instantiation.&lt;/p&gt;

&lt;p&gt;Therefore, in our project, we create an instance of AppFragmentBuilder, passing in the HttpCatsMainFragment class, and constructor arguments including localRoutingInfos and viewID.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const httpCatsMainFragmentBuilder = new AppFragmentBuilder(HTTPCatsMainFragment, {

    localRoutingInfos: null,
    viewID: "http-cats-main-fragment",
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The constructor argument you should pay attention to for now is the viewID. &lt;/p&gt;

&lt;p&gt;As mentioned before, the view you render from initializeView() is wrapped inside a parent div element, which is assigned this viewID as its id. Doing this makes it easier for Oats~i to track whether your fragment’s view has been loaded, and remove it from the DOM when the fragment is being destroyed.&lt;/p&gt;

&lt;p&gt;Finally, we export this builder, as that is what will be passed as the target, and in the case of a child fragment, one of the nested child fragments when providing the app’s routing info.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
export default httpCatsMainFragmentBuilder;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implement the View Template for Http-Cats Fragment
&lt;/h4&gt;

&lt;p&gt;Now, let’s implement the view template file we imported as the view for our http-cats fragment. Oats~i uses handlebars by default for templating view files. However, since Oats~i only cares about the view being provided as a html string, you can modify the templating engine to whichever suits you and your project, as long as it can be used with webpack.&lt;/p&gt;

&lt;p&gt;In the http-cats folder, open the views folder and create a new file named http_cats_fragment.hbs.&lt;/p&gt;

&lt;p&gt;Open the file and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;section class="section"&amp;gt;
    &amp;lt;h1 class="frag-header mont-txt"&amp;gt;&amp;lt;span&amp;gt;Get Me a Random Cat&amp;lt;/span&amp;gt;&amp;lt;/h1&amp;gt;
    &amp;lt;button class="b-cta mont-txt" id="get-cat"&amp;gt;Meeeow&amp;lt;/button&amp;gt;
&amp;lt;/section&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implement the Styling for Http-Cats Fragment’s View
&lt;/h4&gt;

&lt;p&gt;Now lets implement the styling for the http-cats fragment’s view we’ve just templated. &lt;/p&gt;

&lt;p&gt;Inside the http-cats folder, navigate to styles and create a file named http_cats.css. Paste the following code inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
.section {

    padding: 0 40px;
}

.frag-header {

    font-size: 32px !important;
    font-weight: 700 !important;
    display: flex;
    flex-direction: column;
    justify-content: end;
    min-height: 120px;
}

.b-cta {

    padding: 11px 12px;
    background-color: #7da464;
    border: none;
    cursor: pointer;
    color: white !important;
}

#get-cat {

    margin-top: 25px;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these files set up, our imported files in the http-cats main fragment, specifically the styling and views, have now been implemented.&lt;/p&gt;

&lt;p&gt;You might be probably itching to see how the web app looks like already. So, instead of implementing our second fragment, let’s just put everything together and see what our current web app looks like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement Our Root View
&lt;/h2&gt;

&lt;p&gt;From our previous part of this series, where we talked about starting an Oats~i app, I mentioned that Oats~i expects that you give it a template for the app root view or have it already implemented in your main html file before it can start rendering your route and fragments.&lt;/p&gt;

&lt;p&gt;This app root view is basically the primary view of your entire web app, encapsulating bits of it that will never change.&lt;/p&gt;

&lt;p&gt;In our case, we’ll write this in our main html file, that is the home.sv.hbs file that is always served by the server whenever the web app is initially loaded.&lt;/p&gt;

&lt;p&gt;Navigate to src -&amp;gt; server -&amp;gt; home and open the home.sv.hbs file. Delete its content and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Build a Web App with Oats~i: Lesson 1&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;app-root id="my-app"&amp;gt;
        &amp;lt;div id="nav"&amp;gt;
            &amp;lt;div id="logo"&amp;gt;&amp;lt;p class="mont-txt"&amp;gt;&amp;lt;span&amp;gt;&amp;amp;lt;/&amp;amp;gt;&amp;lt;/span&amp;gt;Public APIs&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
            &amp;lt;div id="links"&amp;gt;
                &amp;lt;a href="/" class="nav-link mont-txt http-cats-link"&amp;gt;HTTP Cats&amp;lt;/a&amp;gt;
                &amp;lt;a href="/movies" class="nav-link mont-txt movies-link"&amp;gt;Movies&amp;lt;/a&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;main-fragment&amp;gt;

        &amp;lt;/main-fragment&amp;gt;
    &amp;lt;/app-root&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of this code looks like your typical html markup. However, pay close attention to the start and end of the  tag.&lt;/p&gt;

&lt;p&gt;Oats~i app root view begins with the app-root tag. Within it, you can markup bits of your view that will never change. In our instance, this is the navigation that will be rendered at the left of the screen. Then, we finally include a single  tag and leave it as is. &lt;/p&gt;

&lt;p&gt;This is where Oats~i will start loading our fragments, starting with the main fragment then its children.&lt;/p&gt;

&lt;p&gt;Now, navigate to src -&amp;gt; app -&amp;gt; index -&amp;gt; styles -&amp;gt; index.css and let’s code the styling for our app root view.&lt;/p&gt;

&lt;p&gt;Before doing that, delete the adjacent index_responsive.css file. That was for the starter project that comes in default with Oats~i, so we don’t need it.&lt;/p&gt;

&lt;p&gt;Now, for our index.css file, I’ve put the styling in that folder because it more represents the base or “index” styling of the app. You can always place this file wherever it suits you best as long as the import is right.&lt;/p&gt;

&lt;p&gt;Open the index.css file, delete its content, and replace it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
@import url('https://fonts.googleapis.com/css2?family=Archivo+Black&amp;amp;family=Montserrat:ital,wght@0,100..900;1,100..900&amp;amp;family=Mulish:ital@0;1&amp;amp;family=Open+Sans:ital,wght@0,300..800;1,300..800&amp;amp;display=swap');

/* Crucial styling to allow specially structured A links to still have clicks intercepted by router. */
/* Carry over to your project */
a *:not([click-override=true]){ 

    pointer-events: none 
}

body {

    margin: 0;
    background-color: white;
    box-sizing: border-box;
    overflow-x: hidden;
    --body-padding: 24px;
    --color-primary: #6b929a;
}

.mont-txt {

    font-family: "Montserrat", sans-serif;
    font-weight: 400;
    font-style: normal;
    color: black;
    margin: 0;
    font-size: 16px;
}

#my-app {

    position: relative;
    display: grid;
    grid-template-columns: auto 1fr;
}

#nav {

    box-sizing: border-box;
    height: 100lvh;
    background: var(--color-primary);
    min-width: 332px;
    width: max-content;
}

#logo {

    padding-left: var(--body-padding);
    min-height: 120px;
    width: 100%;
    position: relative;
    display: flex;
    flex-direction: row;
    align-items: center;
}

#logo::before {

    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 3px;
    background-color: white;
}

#logo &amp;gt; p {

    color: white;
    font-weight: 700;
    font-size: 12px;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 8px;
}

#logo &amp;gt; p &amp;gt; span {

    display: inline-block;
    width: 42px;
    height: 42px;
    border: 1px white solid;
    background-color: #486970;
    border-radius: 500px;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
}

#links {

    margin: 40px var(--body-padding);
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.nav-link {

    text-decoration: none;
    color: black;
    font-weight: 400;
}

.nav-link[navigation-state=active] {

    font-weight: 700;
    color: white;
}

.nav-link[navigation-state=active]::before {

    content: "~ ";
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of this code is just project-specific, so unrelated to how Oats~i works. Except for a few directives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
a *:not([click-override=true]){ 

    pointer-events: none 
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned in the previous part of this series, this directive ensures you can write unique markup inside your A tags and have Oats~i still intercept its clicks correctly. This is just a quirk with how events bubble in js.&lt;/p&gt;

&lt;p&gt;Also, another directive that I want you to pay attention to is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
.nav-link[navigation-state=active] {

    font-weight: 700;
    color: white;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above directive, and its counterpart that immediately follows for the pseudoelement ::before, allows us to change the look of our links or navigation buttons when Oats~i has detected we’ve clicked on it and the requested routing has been initiated. &lt;/p&gt;

&lt;p&gt;As mentioned in the previous part of the series, Oats~i uses an array of navigation info to know which elements are the main navigational buttons or links in your app, automatically attach listeners to them, and tell you when each is active.&lt;/p&gt;

&lt;p&gt;Therefore, in this case, our work is to only apply unique styling to our navigational links when they’re active, using the attribute navigation-state=”active”, which adds a tilde, increases the font weight, and changes the color to white for our specific link. &lt;/p&gt;

&lt;p&gt;The only thing left to ensure Oats~i updates this attribute is to just supply the right main navigation info, which we’ll do shortly.&lt;/p&gt;

&lt;p&gt;Now, let’s implement the index.js file where we start our Oats~i app, create our routing info, and main navigation info.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement Index.js
&lt;/h2&gt;

&lt;p&gt;Our Oats~i app starts at the index.js file. If you’re familiar with webpack configuration, you’ll notice that this is our entry point for our configuration and the chunk we inject into the home.sv.hbs file when emitting it as a hbs file using html webpack plugin.&lt;/p&gt;

&lt;p&gt;Navigate to src -&amp;gt; app -&amp;gt; index -&amp;gt; scripts, and open the index.js file. Delete all content and replace it with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
import AppStateManager from "oats-i/base-history/app_state_manager";
import appRoot from "oats-i/bin/app_root"
import AppRoutingInfo from "./routing-info/app_routing_info";
import MainRouter from "oats-i/router/main_router";
import AppMainNavInfo from "./routing-info/app_main_nav_info";

//import styles
import "../styles/index.css";

function initApp(){

    const appStateManager = new AppStateManager(AppRoutingInfo);
    appRoot.initApp(appStateManager, new MainRouter(AppRoutingInfo, appStateManager, (args) =&amp;gt; {}, "", async (url) =&amp;gt; {

        return {

            canAccess: true,
            fallbackRoute: "/"
        }
    }), { template: null, mainNavInfos: AppMainNavInfo }, "");
}

initApp();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of what’s happening here was explained in the previous part of this series, so I once again encourage you to read it if you haven’t. The only important line of code here is the style import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import "../styles/index.css";

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, we’re just simply importing our styling file for index or more specifically, our app root view, and our css loaders and html webpack plugin will take care of packaging it in our final view template (home.hbs).&lt;/p&gt;

&lt;p&gt;The other crucial bits of this code are the AppRoutingInfo and AppMainNavInfo imports. From the previous part of the series, I explained that these two provide the routing information for the web app and the main navigation info. &lt;/p&gt;

&lt;p&gt;Let’s implement them specifically for our project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement AppRoutingInfo
&lt;/h2&gt;

&lt;p&gt;Navigate to src -&amp;gt; app -&amp;gt; index -&amp;gt; scripts -&amp;gt; routing-info and open the app_routing_info.js file. Delete its content and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
import RoutingInfoUtils from "oats-i/router/utils/routing-info/routing_info_utils";
import AppMainNavInfo from "./app_main_nav_info";
import httpCatsMainFragmentBuilder from "../../../fragments/http-cats/scripts/http_cats_main_fragment";

const AppRoutingInfo = RoutingInfoUtils.buildMainRoutingInfo([

    {
        route: "/",
        target: httpCatsMainFragmentBuilder,
        nestedChildFragments: null
    }

], AppMainNavInfo);

export default AppRoutingInfo;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of what you see here was previously explained in the previous part of this series. What I’ll touch on are the specific routing info we provide.&lt;/p&gt;

&lt;p&gt;In this case, we only have one routing info provided as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
        route: "/",
        target: httpCatsMainFragmentBuilder,
        nestedChildFragments: null
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This directs Oats~i that for the route “/” or our home page, we start building from the target or main fragment provided by httpCatsMainFragmentBuilder. Our nestedChildFragments is null, meaning Oats~i will not render any child fragments inside the main fragment because they’re not provided. &lt;/p&gt;

&lt;p&gt;So, when the user navigates to “/”, or the page loads from “/”, Oats~i will match this routing info, emit an instance of the HttpCatsMainFragment from its builder, the httpCatsMainFragmentBuilder, and render it by invoking its rendering functions, initializeView() being one of them.&lt;/p&gt;

&lt;p&gt;We’ll add routing info for our movies fragment later on. For now, let’s implement the AppMainNavInfo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement AppMainNavInfo
&lt;/h2&gt;

&lt;p&gt;Inside the routing-info folder, open the app_main_nav_info.js file. Delete the content and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
import MainNavigationInfoBuilder from "oats-i/router/utils/nav-info/main_nav_info_builder";

const AppMainNavInfo = MainNavigationInfoBuilder.buildMainNavigationInfo([

    {
        selector: "http-cats-link",
        defaultRoute: "/",
        baseActiveRoute: "/",
    }
]);

export default AppMainNavInfo;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of this code had been explained in the previous part of the series. What’s of importance here is the nav info we provide for our app at this stage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
        selector: "http-cats-link",
        defaultRoute: "/",
        baseActiveRoute: "/",
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oats~i interprets this as our navigation button or link is identified by the dot selector http-cats-link (therefore has the class attribute of the same) and it should navigate to the defaultRoute “/” and it will be labelled as active for the base route “/” and any that starts with it, as long as it’s the best match/fit.&lt;/p&gt;

&lt;p&gt;We’d already templated our nav link with this selector and route in the app root view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;a href="/" class="nav-link mont-txt http-cats-link"&amp;gt;HTTP Cats&amp;lt;/a&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s just about it.&lt;/p&gt;

&lt;p&gt;Let’s test what our app looks like now.&lt;/p&gt;

&lt;h1&gt;
  
  
  Running the Project for The First Time
&lt;/h1&gt;

&lt;p&gt;Open the terminal, ensure you are at the project’s root folder, and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm run dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the address shown in the terminal in your browser (often is localhost:8080) and look at your first Oats~i web app in action. You should have a view like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mblmttciyppvgapqpqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mblmttciyppvgapqpqs.png" alt="Image description" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, to experience routing and fragments switching in action, let’s quickly implement the movies fragment. This should be faster because you now understand what’s happening.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implement the Movies Fragment
&lt;/h1&gt;

&lt;p&gt;Navigate to src -&amp;gt; app -&amp;gt; fragments and create a new folder named movies. Inside the movies folder, create new folders named exactly as in the http-cats folder, that is assets, scripts, styles, and views.&lt;/p&gt;

&lt;p&gt;Open the scripts folder, and create a file named movies_main_fragment.js. Paste the following code inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
//import styles
import "../styles/movies.css";

import AppFragmentBuilder from "oats-i/fragments/builder/AppFragmentBuilder";
import AppMainFragment from "oats-i/fragments/AppMainFragment"

class MoviesMainFragment extends AppMainFragment{

    async initializeView(cb){

        //@ts-expect-error cannot find module (for view)
        const uiTemplate = require("../views/movies_fragment.hbs")();
        this.onViewInitSuccess(uiTemplate, cb);
    }
}

const moviesMainFragmentBuilder = new AppFragmentBuilder(MoviesMainFragment, {

    localRoutingInfos: null,
    viewID: "movies-main-fragment",
});

export default moviesMainFragmentBuilder;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate back to the movies folder, open the views folder, create a file named movies_fragment.hbs and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;section class="section logo-section"&amp;gt;
    &amp;lt;h1 class="frag-header mont-txt"&amp;gt;&amp;lt;span&amp;gt;I Love This Movie&amp;lt;/span&amp;gt;&amp;lt;/h1&amp;gt;
    &amp;lt;form class="mont-txt" id="movie-form"&amp;gt;
        &amp;lt;input type="text" id="movie-search" placeholder="What's the title?"&amp;gt;
        &amp;lt;button class="b-cta mont-txt" id="find-movie"&amp;gt;Find it&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
&amp;lt;/section&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, navigate back to the movies folder, open the styles folder and create a movies.css file. Paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
#movie-form {

    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    margin-top: 25px;
}

#movie-search {

    padding: 11px 16px;
    background-color: #7da464;
    width: 414px;
    color: white !important;
    border: none;
}

#find-movie {

    background-color: black;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our movies fragment is done. We have the JavaScript source file, our view template, and its styling, all of which have been imported in our source file. Now, we just have to add a new routing info and main nav info for these, rerun the app, and see our complete project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update AppRoutingInfo
&lt;/h2&gt;

&lt;p&gt;Open the app_routing_info.js file and add the following bits of code.&lt;/p&gt;

&lt;p&gt;At the top of the file, just under the current imports, import our exported builder for the movies main fragment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import moviesMainFragmentBuilder from "../../../fragments/movies/scripts/movies_main_fragment";

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, inside the array of routing infos, add the info for our movies fragment. It will be for the route “/movies”, matching the link we’ve used in our navigational link that initiates the routing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
        route: "/movies",
        target: moviesMainFragmentBuilder,
        nestedChildFragments: null
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PS: Don’t forget the comma separating the two 😉&lt;/p&gt;

&lt;p&gt;Now, let’s finalize by updating our AppMainNavInfo, so that our navigational link for movies is styled correctly when we’re in that route.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update AppMainNavInfo
&lt;/h2&gt;

&lt;p&gt;Open the app_main_nav_info.js file and add the following nav info inside the array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
        selector: "movies-link",
        defaultRoute: "/movies",
        baseActiveRoute: "/movies",
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PS: Remember that comma. Saving you some hairs 😉&lt;/p&gt;

&lt;p&gt;Remember, our navigation link matches this selector and default route, as we described it inside our home.sv.hbs file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;a href="/movies" class="nav-link mont-txt movies-link"&amp;gt;Movies&amp;lt;/a&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it. If you’d stopped the app, just run npm run dev again.&lt;/p&gt;

&lt;p&gt;If not, webpack would have automatically picked up the changes and refreshed the browser. So just give the web app a look.&lt;/p&gt;

&lt;p&gt;You should now be able to navigate between the http-cat route “/” and the movies route “/movies” with our nav links updating based on which one is currently active.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus – Default Routes
&lt;/h1&gt;

&lt;p&gt;Here’s a bonus that might help you curate your Oats~i web app experiences in your future projects.&lt;/p&gt;

&lt;p&gt;In the previous part of the series, I talked about how Oats~i allows you to define a default route that the app should launch in in case the initial route is not a validly defined option in the routing info.&lt;/p&gt;

&lt;p&gt;For our project as is, the home route “/”, which is the base route our app will load in first, is already defined in our routing info. But what if we wanted to start at the route “/http-cats”, which will now define the build for the http-cats main fragment?&lt;/p&gt;

&lt;p&gt;We can change the routing info entry for http-cats to have the route as “/http-cats” then in the startup script, provide that route as the default route.&lt;/p&gt;

&lt;p&gt;Your updated routing info should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
        route: "/http-cats",
        target: httpCatsMainFragmentBuilder,
        nestedChildFragments: null
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the startup script should be updated to look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
appRoot.initApp(appStateManager, new MainRouter(AppRoutingInfo, appStateManager, (args) =&amp;gt; {}, "", async (url) =&amp;gt; {

        return {

            canAccess: true,
            fallbackRoute: "/"
        }
    }), { template: null, mainNavInfos: AppMainNavInfo }, "/http-cats"); //note the change from “” to “/http-cats”


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you run the app and load it from the home route “/”, Oats~i will attempt to find a matching route info for the route, which it will fail, then fallback to the default, and update the address to our defined default, which is “/http-cats”.&lt;/p&gt;

&lt;p&gt;So, our web app will now default to /http-cats whenever its loaded from home or a url that is not explicitly defined in the web app’s routing info. (So, not just home “/” but even “/someRandomUrl”)&lt;/p&gt;

&lt;h1&gt;
  
  
  Sign Up and Follow for the Next Tutorial
&lt;/h1&gt;

&lt;p&gt;That’s it for lesson 1. Quite some concepts to learn and grasp but I hope it was exciting nonetheless. In the next lesson and part of this series, we’ll actually implement these APIs and add data management and reactivity to our Oats~i app. &lt;/p&gt;

&lt;p&gt;If you have any questions, feel free to comment them below. Also, consider supporting with a like, follow, or donation.&lt;/p&gt;

&lt;p&gt;See you in the next one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support Oats~i&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can support the development of Oats~i through &lt;a href="https://www.patreon.com/IanOmondi" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt;*** or &lt;a href="https://buymeacoffee.com/oats_i" rel="noopener noreferrer"&gt;buy me a coffee&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Web App with Oats~i – Starting an Oats~i App</title>
      <dc:creator>Oats〜i</dc:creator>
      <pubDate>Mon, 19 Aug 2024 12:47:30 +0000</pubDate>
      <link>https://forem.com/oatsi/build-a-web-app-with-oatsi-starting-an-oatsi-app-2pd</link>
      <guid>https://forem.com/oatsi/build-a-web-app-with-oatsi-starting-an-oatsi-app-2pd</guid>
      <description>&lt;p&gt;Welcome to the second part of the Build a Web App with Oats~i tutorial series. In the first part, we went through installing Oats~i in your development environment. In case you missed that one, &lt;a href="https://dev.to/oatsi/build-a-web-app-with-oatsi-setting-up-53al"&gt;check it out here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In this part of the series, we’ll go through how to start an Oats~i app. This will cover all instances where you want to start an Oats~i app and have the framework run on the front end.&lt;/p&gt;

&lt;p&gt;Instead of building a whole project from scratch, we’ll use the inbuilt starter project that comes with Oats~i when you set it up using the Oats~i cli. We’ll open the important bits of the code necessary for this tutorial and use that to explain how Oats~i loads up when it gets to the client/browser and starts running your web app.&lt;/p&gt;

&lt;p&gt;Let’s dive in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can follow on video instead, if that's your preference: &lt;a href="https://youtu.be/bsTFn9Sx9Lw" rel="noopener noreferrer"&gt;https://youtu.be/bsTFn9Sx9Lw&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Install the Starter Project Using Oats~i CLI
&lt;/h1&gt;

&lt;p&gt;Create a new folder where you want to install the Oats~i starter project and open the terminal. Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npx oats-i-cli

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts.&lt;/p&gt;

&lt;p&gt;This will install Oats~i and the starter project bundled with it to your current working directory. &lt;/p&gt;

&lt;p&gt;Finally, to run the starter project, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm run dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to the address provided in the terminal (often localhost:8080) and see the starter project in action. Navigate back and forth between the available pages to see Oats~i handle routing and build views through fragments.&lt;/p&gt;

&lt;p&gt;Now let’s get to the code that brings Oats~i to life in the client/browser.&lt;/p&gt;

&lt;h1&gt;
  
  
  Index.js
&lt;/h1&gt;

&lt;p&gt;Open the index.js file found in src -&amp;gt; app -&amp;gt; index -&amp;gt; scripts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvedi3vqwkxbr72vtxmex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvedi3vqwkxbr72vtxmex.png" alt="Image description" width="244" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This file contains the code that starts Oats~i for the starter project bundled in the cli. This is more or less the same code you’d write to start Oats~i in your own project.&lt;/p&gt;

&lt;p&gt;Let’s break it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The App Root
&lt;/h2&gt;

&lt;p&gt;Oats~i is typically initialized from the appRoot module through the appRoot.initApp() method.&lt;/p&gt;

&lt;p&gt;appRoot is a singleton instance of the AppRoot class that manages the initialization of an Oats~i web app, main navigation, and loading the root view if its template is provided.&lt;/p&gt;

&lt;p&gt;The initApp() method takes several arguments, including an instance of the AppStateManager, MainRouter, AppRootView object, a default route, and optional extra options that currently allow you to define the app’s external link interception behavior.&lt;/p&gt;

&lt;p&gt;Let’s break these down.&lt;/p&gt;

&lt;h3&gt;
  
  
  AppStateManager
&lt;/h3&gt;

&lt;p&gt;The app state manager is a module responsible for managing the route states of an Oats~i app. Primarily, it helps Oats~i understand whether a history pop event is a click on the forward or back button on the browser by the user.&lt;/p&gt;

&lt;p&gt;This information is not obvious using the history API as is.&lt;/p&gt;

&lt;p&gt;Having this information is crucial because Oats~i saves fragment states as the web app is navigated by the user. Therefore, if they are to go back or forward to a page they were in before, the fragment(s) responsible for rendering and running those pages will “remember” their state and show the right information and automatically be scrolled to the right position the user was at.&lt;/p&gt;

&lt;p&gt;Knowing whether the pop event is a forward or back movement makes retrieving state information accurate. &lt;/p&gt;

&lt;p&gt;You simply create an instance of the AppStateManager by invoking new, passing in the web app’s routing info.&lt;/p&gt;

&lt;p&gt;In our index.js file, we do this in the line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const appStateManager = new AppStateManager(AppRoutingInfo);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have already defined our AppRoutingInfo in a separate file (more on this later).&lt;/p&gt;

&lt;h3&gt;
  
  
  Main Router
&lt;/h3&gt;

&lt;p&gt;The main router handles routing in an Oats~i web app. You create a router instance by invoking “new”, passing in the app’s routing info, app state manager instance, an error callback, a root path, and a route consent callback.&lt;/p&gt;

&lt;p&gt;We’ve already talked about the app routing info and app state manager instance, so let’s talk about the other arguments that you pass to the main router.&lt;/p&gt;

&lt;h4&gt;
  
  
  Error Callback
&lt;/h4&gt;

&lt;p&gt;In case of a problem routing, the main router can fire the error callback and inform you of the reasons why routing has failed. As long as you’ve defined your routes well, you shouldn’t worry about implementing this method, other than merely providing it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Root Path
&lt;/h4&gt;

&lt;p&gt;The main router allows you to directly call for routing from your JavaScript code using the routeTO() method. It also determines the valid route to follow based on your app’s main routing info. &lt;/p&gt;

&lt;p&gt;Now, if you have Oats~i running in your website with a special address such as /admin, it can be repetitive having to start every routing call or routing info with the /admin root. Instead, you can supply this to the main router as the root path, and just append the rest of your route to your routing calls or routing info.&lt;/p&gt;

&lt;p&gt;So, instead of /admin/create, with the root path set to /admin, you can just have the route as /create. However, href attributes in links MUST be fully qualified.&lt;/p&gt;

&lt;h4&gt;
  
  
  Route Consent Callback
&lt;/h4&gt;

&lt;p&gt;Before the main router can trigger routing for a given path, it attempts to see whether routing for that route has been permitted. The route consent callback allows you to specify this, giving you the ability to control which sections of your web app can be accessed by a given user or based on any other business or app logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is different from fragment consenting, which we’ll cover later.&lt;/p&gt;

&lt;h2&gt;
  
  
  AppRootView Object
&lt;/h2&gt;

&lt;p&gt;The app root view object consists of the root view template and array of main navigation infos.&lt;/p&gt;

&lt;p&gt;Every Oats~i app has a root view. This is the permanent section of the view which the user will always see regardless of the path they’re navigating to. The root view is wrapped within an  tag and will typically contain elements such as your navbar and footer. &lt;/p&gt;

&lt;p&gt;Here’s an example, sourced from home.sv.hbs in the Oats~i starter project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;app-root id="my-app"&amp;gt;
        &amp;lt;div id="nav"&amp;gt;
            &amp;lt;a href="/" class="nav-link open-sans-txt home-link"&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;Home&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;
            &amp;lt;a href="/about" class="nav-link open-sans-txt about-link"&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span&amp;gt;About&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div id="site-bg"&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;main-fragment&amp;gt;

        &amp;lt;/main-fragment&amp;gt;
&amp;lt;/app-root&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; As you can infer from the Oats~i starter project, you can skip passing in a template for the app root view in the initApp() method as long as you’ve provided it in the html markup sourced for your page from the server.&lt;/p&gt;

&lt;p&gt;Your root view object should also have a single  tag specified within, where the app’s fragments will be loaded. &lt;/p&gt;

&lt;p&gt;The AppRootView object also takes a main navigation info array, which contains a list of selectors and their active routes, which Oats~i will use to show you which navigation selector is active.&lt;/p&gt;

&lt;p&gt;In the Oats~i starter project, specifying the main nav info makes it possible to update the styling and looks of the navigation links when you click on it and navigate to its url. &lt;/p&gt;

&lt;p&gt;Oats~i handles the click and update boiler plate for the navigation links or buttons. All you have to do is style the links or buttons based on which one is marked as active using the attribute ‘navigation-state=”active”’&lt;/p&gt;

&lt;h2&gt;
  
  
  Default Route
&lt;/h2&gt;

&lt;p&gt;The default route is the route Oats~i will default to incase the page loads from a url that is not specified in your app’s routing info. You can use this to curate the default web app behavior especially if it results from a log in or authentication action.&lt;/p&gt;

&lt;p&gt;For instance, if the user has come in from a login page and is redirected to their admin page, but the initial page load is at “/admin”, you can specify the default route to be “/admin/dashboard”. &lt;/p&gt;

&lt;p&gt;Oats~i will reroute the web app to /admin/dashboard on load and the user will always access their dashboard every time they come from logging into the app.&lt;/p&gt;

&lt;p&gt;If you want to change this behavior to say, profile, you can simply change the default route in your web app to /admin/profile and all users logging in will have their profile page as the default page. &lt;/p&gt;

&lt;h2&gt;
  
  
  Extra Options
&lt;/h2&gt;

&lt;p&gt;Oats~i also takes in optional extra options, with the current implementation allowing you to intercept external links within your web app. This allows you to warn users of their navigation away from your site and the url they’re about to access, in case you want to build a content protection system.&lt;/p&gt;

&lt;h1&gt;
  
  
  Complete Code
&lt;/h1&gt;

&lt;p&gt;The complete code for starting an Oats~i app will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//sourced from index.js in the starter app
const appStateManager = new AppStateManager(AppRoutingInfo);
    appRoot.initApp(appStateManager, new MainRouter(AppRoutingInfo, appStateManager, (args) =&amp;gt; {}, "", async (url) =&amp;gt; {

        return {

            canAccess: true,
            fallbackRoute: "/"
        }
    }), { template: null, mainNavInfos: AppMainNavInfo }, "");

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can wrap this code within a function that is automatically invoked when your index.js file downloads in the browser to have the web app automatically started on page load. In the starter project’s case, this is the initApp() function. &lt;/p&gt;

&lt;p&gt;Now, there are two more things left to explain.&lt;/p&gt;

&lt;h2&gt;
  
  
  App Routing Info
&lt;/h2&gt;

&lt;p&gt;From the startup code, you can point out that providing routing information is mandatory for an Oats~i web app to initialize. From the example’s I’ve given, we define this info elsewhere then import it in our startup script. Defining your routing info in a separate file is not mandatory, but I find it to be good practice especially when you want to add more routes or main navigation in your web app.&lt;/p&gt;

&lt;p&gt;Here’s how routing information is defined for an Oats~i web app, using the example from the starter project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const AppRoutingInfo = RoutingInfoUtils.buildMainRoutingInfo([

    {
        route: "/",
        target: homeMainFragmentBuilder,
        nestedChildFragments: null
    },
    {
        route: "/about",
        target: aboutMainFragmentBuilder,
        nestedChildFragments: null
    }
], AppMainNavInfo);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can call the routing info any name you want, as long as you use the method RoutingInfoUtils.buildMainRoutingInfo() to build it.&lt;/p&gt;

&lt;p&gt;The method will return an array of routing information, with each info holding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;route:&lt;/strong&gt; this is the route that info is valid for. You cannot repeat a route across your routing infos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;target:&lt;/strong&gt; this is the main fragment the route should start building from. Oats~i builds its fragments from the main fragment to the child fragments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nested child fragments:&lt;/strong&gt; these are the child fragments that should also be built for the route, in order. This order typically represents the DOM structure, with the fragment that should be created first in DOM coming before it’s nested child or a child fragment in the same level with it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can notice that we also pass AppMainNavInfo to the buildMainRoutingInfo() method as well. This is the same info we passed in to the app state manager and initApp method in the starter script. Let’s look at it.&lt;/p&gt;

&lt;h2&gt;
  
  
  App Main Nav Info
&lt;/h2&gt;

&lt;p&gt;A good web app needs good navigation. And often, setting up navigation can involve a lot of boiler plate code to not only set up the click listeners for the navigation links or buttons, but also change their styling based on which one is active.&lt;/p&gt;

&lt;p&gt;Oats~i takes care of the boiler plate for you by requiring you only provide the navigation information needed by your web app. This takes the following format (example sourced from the starter project).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const AppMainNavInfo = MainNavigationInfoBuilder.buildMainNavigationInfo([

    {
        selector: "home-link",
        defaultRoute: "/",
        baseActiveRoute: "/",
    },
    {
        selector: "about-link",
        defaultRoute: "/about",
        baseActiveRoute: "/about",
    }
]);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You create a main navigation info in Oats~i using the method MainNavigationInfoBuilder.buildMainNavigationInfo(). It returns an array of navigation infos, with each containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;selector:&lt;/strong&gt; This is a dot selector that Oats~i will use to query the navigation link or button, set up listeners (for buttons only – links/A tags are automatically intercepted), and update its “navigation-state” attribute based on whether its active or not. In your markup, this is simply a class name. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;defaultRoute:&lt;/strong&gt; this is the default route Oats~i should route to if the navigation button is clicked. For links, since Oats~i automatically intercepts clicks on links/A tags, ensure this matches the value of your href attribute.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;baseActiveRoute:&lt;/strong&gt; This is the base route for which the navigation button or link should be treated as active. For instance, if you have a navigation button with defaultRoute “/profile” and baseActiveRoute “/profile” and the user navigates to /profile/update-pic, Oats~i will set this button as active since this route starts with the baseActiveRoute value. &lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Putting Everything Together
&lt;/h1&gt;

&lt;p&gt;Let’s put everything together and have the final picture of what you need to get an Oats~i app up and running. Typically, you must have defined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The app routing info&lt;/li&gt;
&lt;li&gt;The app main nav info (for main navigation links in your root view)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, simply get a new instance of the app state manager, and call appRoot.initApp passing this instance, the app routing info, app main nav info, and main router instance. Again, here’s the example code from the Oats~i starter project that comes bundled with the cli, now wrapped in a function that we call immediately the index.js file loads in the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
function initApp(){

    const appStateManager = new AppStateManager(AppRoutingInfo);
    appRoot.initApp(appStateManager, new MainRouter(AppRoutingInfo, appStateManager, (args) =&amp;gt; {}, "", async (url) =&amp;gt; {

        return {

            canAccess: true,
            fallbackRoute: "/"
        }
    }), { template: null, mainNavInfos: AppMainNavInfo }, "");
}

initApp();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As your web app grows and changes, the only bits of this code you’ll ever need to change are the app routing infos and main navigation infos (AppRoutingInfo and AppMainNavInfo). This will be typically because you’re adding new routes to your web app (thus updating the routing information) or adding new main navigation buttons or links (thus updating the main navigation infos).&lt;/p&gt;

&lt;p&gt;The rest of the code will be fine untouched.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sign Up and Follow for the Next Tutorial
&lt;/h1&gt;

&lt;p&gt;A lot of this will make sense when we build our very own small project in Oats~i. That’s what we’ll be doing in the next part of this series, to learn the next fundamental concepts around building an Oats~i web app.&lt;/p&gt;

&lt;p&gt;See you then.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support Oats~i&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can support the development of Oats~i through &lt;a href="https://www.patreon.com/IanOmondi" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/oats_i" rel="noopener noreferrer"&gt;buy me a coffee&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Web App with Oats~i – Setting Up</title>
      <dc:creator>Oats〜i</dc:creator>
      <pubDate>Sun, 18 Aug 2024 19:26:39 +0000</pubDate>
      <link>https://forem.com/oatsi/build-a-web-app-with-oatsi-setting-up-53al</link>
      <guid>https://forem.com/oatsi/build-a-web-app-with-oatsi-setting-up-53al</guid>
      <description>&lt;p&gt;In the last article, I wrote an introductory post about Oats~i, the open web framework. I talked about its core features, a bit of how it works, and what to expect. If you didn’t read that piece, give it &lt;a href="https://dev.to/oatsi/introducing-oatsi-the-open-web-framework-2ehp"&gt;a quick look.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over the past couple of days, I’ve created a few tooling around Oats~i to ensure we can quickly get up and running installing the framework, running a starter project, and seamlessly working on tutorials and learning.&lt;/p&gt;

&lt;p&gt;This piece is the first of a series called Build a Web App with Oats~i. We’ll start with setting up an Oats~i project using two methods – using the cli or manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt;: You love videos instead? Watch how to set up an Oats~i project on our YouTube channel: &lt;a href="https://youtu.be/V0Z6nxgTM2g?si=My6rUJzsCRZJvKFX" rel="noopener noreferrer"&gt;https://youtu.be/V0Z6nxgTM2g?si=My6rUJzsCRZJvKFX&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using the Oats~i CLI (Recommended)
&lt;/h1&gt;

&lt;p&gt;This is the most recommended method for setting up an Oats~i project. It saves you the time of writing boiler plate code and installing the dependencies needed to get an Oats~i project up and running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;However&lt;/strong&gt;, you should use this method only when creating a completely new project to avoid potential file conflicts between Oats~i and your current project structure.&lt;/p&gt;

&lt;p&gt;The cli comes set up with a starter project with a home and about page. You can navigate between these two pages to see Oats~i already in action, handling routing and fragments.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use the Oats~i CLI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the folder you want to create an Oats~i project&lt;/li&gt;
&lt;li&gt;Open the terminal and run
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npx oats-i-cli

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Follow the prompts and wait for the setup to complete&lt;/li&gt;
&lt;li&gt;Run
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm run dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Navigate to the address shown in the terminal at the start of the build (often is localhost:8080). That will open the starter project on your browser. (You can use the local network address to view it on your other devices connected to the same network)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Manual Installation
&lt;/h1&gt;

&lt;p&gt;If you have an existing project you want to install Oats~i to, or love being hardcore, you can set up Oats~i manually. This process is much longer, and requires more attention to ensure everything works well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Dependencies
&lt;/h2&gt;

&lt;p&gt;Now, start by navigating to your project’s directory and open the terminal.&lt;/p&gt;

&lt;p&gt;First, we install the dependencies needed to build and run Oats~i. If you’re &lt;strong&gt;starting a new project&lt;/strong&gt;, start by running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm init -y

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, follow the steps outlined below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Apart from installing Oats~i, you can skip any of the steps after it if you already have the libraries/dependencies installed in your current project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Oats~i (Core)
&lt;/h3&gt;

&lt;p&gt;Install the core Oats~i library.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install oats-i

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Webpack
&lt;/h3&gt;

&lt;p&gt;Install Webpack as a development dependency. Webpack will allow us to have better project structures among other features, with the library handling module bundling and asset management.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save-dev webpack webpack-cli

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Webpack Dev Server
&lt;/h3&gt;

&lt;p&gt;Install the webpack dev server as a development dependency. This will allow us to run a development server that will auto-update on new changes while we’re building and testing our Oats~i web app.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save-dev webpack-dev-server

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Handlebars-Loader
&lt;/h3&gt;

&lt;p&gt;It’s strongly recommended that you use a templating engine for rendering your views in Oats~i. My preferred choice is handlebars. (&lt;a href="https://handlebarsjs.com/" rel="noopener noreferrer"&gt;Learn more&lt;/a&gt; about handlebars)&lt;/p&gt;

&lt;p&gt;To work with webpack, we’ll need to install the handlebars-loader as a development dependency. That will allow us to use handlebars templates to generate and render our views in-app.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save-dev handlebars-loader

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install HTML-Loader
&lt;/h3&gt;

&lt;p&gt;To create server-side views, the base Oats~i configuration uses a combination of html-loader and html-webpack-plugin. Let’s first install the html-loader library as a development dependency.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save-dev html-loader

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install HTML-Webpack-Plugin
&lt;/h3&gt;

&lt;p&gt;The html-webpack-plugin library allows us to output server-side views for our app using webpack. It works in conjunction with html-loader. Install it as a development dependency.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save-dev html-webpack-plugin

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Babel-Loader
&lt;/h3&gt;

&lt;p&gt;Babel-loader will load and transform our JavaScript files using webpack. Install it as a development dependency.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save-dev babel-loader

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Style-Loader and CSS-Loader
&lt;/h3&gt;

&lt;p&gt;Style-loader and css-loader will inject our css imports as stylesheets in our html files produced by html-loader and html-webpack-plugin. Install these loaders as development dependencies.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save-dev style-loader

npm install --save-dev css-loader

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Webpack-Merge
&lt;/h3&gt;

&lt;p&gt;Webpack-merge will allow us to merge multiple webpack configuration files, allowing us to structure our configuration files in optimal ways for our project setup. Install this library as a development dependency.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save-dev webpack-merge

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Express-Handlebars
&lt;/h3&gt;

&lt;p&gt;Express-handlebars will allow us to emulate server-side rendering in development using handlebars view files outputted by our webpack configuration, using html-loader and html-webpack-plugin. Install this library as a development dependency.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save-dev express-handlebars

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Webpack Configuration Files
&lt;/h2&gt;

&lt;p&gt;At the root of your project’s directory, create a new folder and call it “webpack-configs”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19uqaholyqek9m2iqq3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F19uqaholyqek9m2iqq3u.png" alt="Image description" width="235" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate into this folder and create two new folders inside it named “main” and “oats~i”.&lt;/p&gt;

&lt;p&gt;Your folder structure should now look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fitmdbk2o5z1s45dquxyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fitmdbk2o5z1s45dquxyl.png" alt="Image description" width="211" height="64"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, navigate into “oats~i” and create two more folders named “default” and “main”.&lt;/p&gt;

&lt;p&gt;Your folder structure should now look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2xm8x8zt8fj73lao4r8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2xm8x8zt8fj73lao4r8.png" alt="Image description" width="204" height="105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;------&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The “default” folder will hold the default webpack configuration needed by Oats~i to have it’s webpack-dependent functions work. Currently, that is code splitting and lazy loading for fragments.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The “main” folder will hold the webpack configuration for loaders used and recommended by Oats~i. These are the loaders we installed in the “install dependencies” stage. Feel free to edit this configuration later if you want to change loaders.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;------&lt;/p&gt;

&lt;p&gt;Navigate to the “default” folder and create a new file called “webpack.config.js”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4o9934edgk59ux0zgmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4o9934edgk59ux0zgmt.png" alt="Image description" width="221" height="89"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the file and paste the following code inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
const DefaultOats_iConfig = {

    optimization: {

        splitChunks: {

            minSize: 0, //Minimum size, in bytes, for a chunk to be generated.
            minSizeReduction: 1, //Minimum size reduction to the main chunk (bundle), in bytes, needed for a chunk to be generated.
            minChunks: 2,
            cacheGroups: {

                commons: {

                    chunks: "async", //Allow chunks to be shared between sync and async
                }
            }
        }
    }
}

module.exports = DefaultOats_iConfig;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, navigate back to the “oats~i” folder and navigate into “main”.&lt;/p&gt;

&lt;p&gt;Create a new file and name it “webpack.config.js”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fci3z6yhrrt01sy44zbaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fci3z6yhrrt01sy44zbaf.png" alt="Image description" width="245" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the file and paste the following code inside.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
/**
 * Contains loaders
 */
const DefaultOats_iLoadersConfig = {

    module: {

        rules: [

            {
                test: /\.(html|sv.hbs|p.hbs)$/,
                use: [
                        {
                            loader: "html-loader",
                            options: {
                                minimize: false
                            }
                        }
                ]
            },
            {
                test: /\.(hbs)$/,
                exclude: /\.(sv.hbs|p.hbs)/,
                use: [
                    {
                        loader: "handlebars-loader",
                        options: {
                            inlineRequires: "./assets"
                        }
                    }
                ]
            },
            {
                test: /\.(js)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: "babel-loader"
                    }
                ]
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                type: 'asset/resource',
            },
            {
                test: /\.css$/,
                use: [

                    'style-loader',
                    'css-loader'
                ]
            }
        ]
    }
}

module.exports = DefaultOats_iLoadersConfig;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re done setting up the core webpack configuration for Oats~i. Now, we need to merge them in a common configuration file that we’ll use project-wide.&lt;/p&gt;

&lt;p&gt;Now, navigate back to the “oats~i” folder then back to the “webpack-configurations” folder. Now navigate into “main”.&lt;/p&gt;

&lt;p&gt;Create a new file and name it “webpack.config.js”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndx019rdvxi08be8e4tb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndx019rdvxi08be8e4tb.png" alt="Image description" width="229" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the file and paste the following code inside.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const DevServerMiddlewareConfig = require("../../proxy-server/proxy_server");
//The folder we'll have our assets emitted after build
const DIST_PATH_PUBLIC_ASSETS = "../../dist/public";
const { merge } = require("webpack-merge");
const DefaultOats_iConfig = require("../oats~i/default/webpack.config");
const DefaultOats_iLoadersConfig = require("../oats~i/main/webpack.config");

//@ts-expect-error
module.exports = merge(DefaultOats_iConfig, DefaultOats_iLoadersConfig, {

    mode: "development",
    devtool: "eval-source-map",
    output: {

        //Where we'll output public assets
        path: path.resolve(__dirname, `${DIST_PATH_PUBLIC_ASSETS}`),
        publicPath: "/",
        assetModuleFilename: 'assets/[name][ext]',
        filename: "js/[name].dev_bundle.js",
        clean: true
    },
    entry: {

        //The main entry (app)
        index: "./src/app/index/scripts/index.js",
    },
    plugins: [
        new HtmlWebpackPlugin({

            template: "./src/server/home/home.sv.hbs",
            filename: "../views/home.hbs",
            chunks: ["index"],
            minify: false
        })
    ],
    devServer: {

        devMiddleware: {

            writeToDisk: true, //Because of our configured server
        },
        setupMiddlewares: DevServerMiddlewareConfig,
    }
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we should be done setting up our webpack configurations that’s just fine to run an Oats~i project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update package.json
&lt;/h2&gt;

&lt;p&gt;Navigate back to your project’s root folder. Open package.json, look for the “scripts” line, and add the following line after “test” (remember to separate with a comma).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
"dev": "webpack-dev-server --config ./webpack-configs/main/webpack.config.js"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5128manm23wg0z3wy5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5128manm23wg0z3wy5l.png" alt="Image description" width="661" height="83"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up Dev Server Middlewares
&lt;/h2&gt;

&lt;p&gt;In our final webpack configuration file, we specified a middlewares file for the webpack dev server under&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
setupMiddlewares: DevServerMiddlewareConfig

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under normal circumstances, you don’t need this setup. You can simply write your server view files in html format, use html-loader and html-webpack-plugin to produce them, and have them directly served by webpack-dev-server during development.&lt;/p&gt;

&lt;p&gt;However, as you’ll come to learn later, this is not the best setup for building an Oats~i project that’s already primed for server-side rendering. The server-side files are already in html format, meaning they can’t be easily templated with data before being rendered to the client on the initial request.&lt;/p&gt;

&lt;p&gt;To accommodate that, the default Oats~i setup ensures you’re creating template files for your server views that will be easy to render with data from your server every time a client requests for a fresh page.&lt;/p&gt;

&lt;p&gt;Our dev server middlewares setup will allow us to mimic such as setup on the actual server, for our development environment.&lt;/p&gt;

&lt;p&gt;With its default setup, you don’t need to update it for new fragments that you add to the project, as long as you’re not interested in having them server-side rendered. However, once you get to the point where you want to have server-side rendering and test it in development, setting things up will be much easier and faster, without a change in file formats you’ve already used across the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s Set Up this Config
&lt;/h3&gt;

&lt;p&gt;At your project’s root directory, create a new folder and name it “proxy-server”. Inside this new folder, create a file and name it “proxy_server.js”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12ru1lequ6mmul27hztl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12ru1lequ6mmul27hztl.png" alt="Image description" width="237" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the file and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
const express = require("express");
const path = require("path");
const hbs = require("express-handlebars");

const DevServerMiddlewareConfig = (middlewares, devServer) =&amp;gt; {

    /**
     * @type {import("express").Application}
     */
    const app = devServer.app;

    //Configure the view engine
    app.set("views", path.resolve(__dirname, "../dist/views"));
    app.set("view engine", "hbs");
    app.engine("hbs", hbs.engine({

        extname: "hbs",
        layoutsDir: path.resolve(__dirname, "../dist/views"),
        partialsDir: path.resolve(__dirname, "../dist/views/partials")
    }));

    //for json
    app.use(express.json());
    //I think params and queries
    app.use(express.urlencoded({ extended: false }));
    //static
    app.use(express.static(path.resolve(__dirname, "../dist/public")));

    //My middlewares
    //Capture all
    app.get("/*", (req, res, next) =&amp;gt; {

        res.render("home", {
            layout: "home"
        });
    });

    return middlewares;
}

module.exports = DevServerMiddlewareConfig;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration will capture all requests to the dev server and return the home.hbs layout file. You can rename this later to your file’s actual name once you start creating your own Oats~i project and leave it as is as long as you’ll not require server-side rendering for any of your fragments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create jsconfig.json
&lt;/h2&gt;

&lt;p&gt;Oats~i is typed using a combination of typescript declaration files and JSDoc. There’s a slight issue where types may not always reflect correctly when using the framework, slightly hurting the developer experience.&lt;/p&gt;

&lt;p&gt;Instead of refactoring over 100 files and thousands of lines of code, I’ve found a way to make typescript and intellisense (at least in VSCode) to understand the JSDoc types used in Oats~i.&lt;/p&gt;

&lt;p&gt;To do this, navigate to your project’s root folder. Create a file named “jsconfig.json”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh15kn2p02ywenjiae2l3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh15kn2p02ywenjiae2l3.png" alt="Image description" width="243" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open it and paste the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
    "include": [
        "*/**/*.js",
        "**/*",
        "/**/*",
        "node_modules/oats-i" //to get type definitions for oats-i in your project
    ],
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This bit comes automatically with the cli, so don’t do this for an Oats~i project you’ve set up using the cli.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Starter Project Files
&lt;/h2&gt;

&lt;p&gt;Let’s now put everything together and create our starter project files to run an Oats~i app for the first time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server-side Base Layout
&lt;/h3&gt;

&lt;p&gt;Navigate to your project’s root folder and create a new folder named “src”. This folder will contain all of our project’s source files.&lt;/p&gt;

&lt;p&gt;Inside the “src” folder, create two folders named “app” and “server”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs81x19qfo9xoppd0fbfd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs81x19qfo9xoppd0fbfd.png" alt="Image description" width="238" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to the “server” folder and create a new folder named “home”. Inside the “home” folder, create a new file and name it “home.sv.hbs”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhq5es1y3xo2tewv29tf8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhq5es1y3xo2tewv29tf8.png" alt="Image description" width="234" height="89"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the file and paste the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Home - My Oats~i App&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;app-root id="my-app"&amp;gt;
       &amp;lt;div id="nav"&amp;gt;
            &amp;lt;a href="/" class="home-link"&amp;gt;Home&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;main-fragment&amp;gt;
        &amp;lt;/main-fragment&amp;gt;
    &amp;lt;/app-root&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  App Files
&lt;/h3&gt;

&lt;p&gt;Now navigate back to “src”. Get into the “app” folder and create two folders name “fragments” and “index”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cubqidhlgj1tqvw1cgk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cubqidhlgj1tqvw1cgk.png" alt="Image description" width="244" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate into the “index” folder and create two folders named “scripts” and “styles”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wg2845ihjolmwbzhqn0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wg2845ihjolmwbzhqn0.png" alt="Image description" width="246" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside the “scripts” folder, create a new folder called “routing-info”. Inside “routing-info” create two files named “app_main_nav_info.js” and “app_routing_info.js”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhuonxmp4k77ne2km5q5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhuonxmp4k77ne2km5q5h.png" alt="Image description" width="238" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Main Navigation info
&lt;/h4&gt;

&lt;p&gt;Open “app_main_nav_info.js” and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
import MainNavigationInfoBuilder from "oats-i/router/utils/nav-info/main_nav_info_builder";

const AppMainNavInfo = MainNavigationInfoBuilder.buildMainNavigationInfo([
    {
        selector: "home-link",
        defaultRoute: "/",
        baseActiveRoute: "/",
    }
]);

export default AppMainNavInfo;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Main Routing Info
&lt;/h4&gt;

&lt;p&gt;Now open “app_routing_info.js” and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
import RoutingInfoUtils from "oats-i/router/utils/routing-info/routing_info_utils";
import AppMainNavInfo from "./app_main_nav_info";
import homeMainFragmentBuilder from "../../../fragments/home/scripts/home_main_fragment";

const AppRoutingInfo = RoutingInfoUtils.buildMainRoutingInfo([

    {
        route: "/",
        target: homeMainFragmentBuilder,
        nestedChildFragments: null
    }
], AppMainNavInfo);

export default AppRoutingInfo;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Index.css
&lt;/h4&gt;

&lt;p&gt;We’ll create an index.css file for a special reason, which &lt;strong&gt;MUST&lt;/strong&gt; be replicated across all your Oats~i projects if you want consistent behavior.&lt;/p&gt;

&lt;p&gt;Navigate back to the “index” folder, and create a new folder named “styles”. Inside the folder, create a new file called “index.css”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5l84u0e34br8c7jhz2ex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5l84u0e34br8c7jhz2ex.png" alt="Image description" width="243" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the file and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* Crucial styling to allow specially structured A links to still have clicks intercepted by router. */
/* Carry over to your project */
a *:not([click-override=true]){ 

    pointer-events: none 
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this css code does is remove pointer events from elements nested inside an A tag, to ensure the browser doesn’t intercept it before Oats~i does. It also gives you, the developer, the freedom to override this behavior using the attribute click-override=true on any element nested within an A tag.&lt;/p&gt;

&lt;p&gt;However, expect Oats~i, at its current state, not to intercept links from an A tag with a child element having that attribute.&lt;/p&gt;

&lt;p&gt;This means that you can safely write A tags without any modification or special attributes for Oats~i to automatically intercept them and navigate your app locally. You only add special attributes when you want to stop this behavior and have the browser manually route the website.&lt;/p&gt;

&lt;p&gt;Carry over this css directive in all Oats~i projects you create. If you use the cli, you’ll find it already in index.css.&lt;/p&gt;

&lt;h4&gt;
  
  
  Index.js
&lt;/h4&gt;

&lt;p&gt;Navigate back to “scripts” (inside index) and create a new file named “index.js”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffy0xrpvcq2kkhjo4n0bv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffy0xrpvcq2kkhjo4n0bv.png" alt="Image description" width="232" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the file and paste the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
//import styles
import "../styles/index.css";
import AppStateManager from "oats-i/base-history/app_state_manager";
import appRoot from "oats-i/bin/app_root"
import AppRoutingInfo from "./routing-info/app_routing_info";
import MainRouter from "oats-i/router/main_router";
import AppMainNavInfo from "./routing-info/app_main_nav_info";

function initApp(){

    const appStateManager = new AppStateManager(AppRoutingInfo);
    appRoot.initApp(appStateManager, new MainRouter(AppRoutingInfo, appStateManager, (args) =&amp;gt; {}, "", async (url) =&amp;gt; {

        return {

            canAccess: true,
            fallbackRoute: "/"
        }
    }), { template: null, mainNavInfos: AppMainNavInfo }, "");
}

initApp();

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Fragments
&lt;/h4&gt;

&lt;p&gt;Navigate back to the “app” folder. Navigate into “fragments” and create a new folder named “home”.&lt;/p&gt;

&lt;p&gt;Inside “home”, create a new folder named “scripts”. Inside “scripts”, create a new file named “home_main_fragment.js”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcddrzkkjfmzrlbkk3wg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcddrzkkjfmzrlbkk3wg.png" alt="Image description" width="232" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the file and paste the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
//@ts-check
import AppFragmentBuilder from "oats-i/fragments/builder/AppFragmentBuilder";
import AppMainFragment from "oats-i/fragments/AppMainFragment"

class HomeMainFragment extends AppMainFragment{

    async initializeView(cb){

        //@ts-expect-error cannot find module (for view)
        const uiTemplate = require("../views/home_fragment.hbs")();
        this.onViewInitSuccess(uiTemplate, cb);
    }
}

const homeMainFragmentBuilder = new AppFragmentBuilder(HomeMainFragment, {

    localRoutingInfos: null,
    viewID: "home-main-fragment",
});
export default homeMainFragmentBuilder;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now navigate back to “home” and create a new folder called “views”. Inside “views”, create a new file and name it “home_fragment.hbs”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxwnkbrnxdhun1alcggn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxwnkbrnxdhun1alcggn.png" alt="Image description" width="242" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open file and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;h1&amp;gt;Home Fragment&amp;lt;h1/&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test the Configuration
&lt;/h2&gt;

&lt;p&gt;Navigate to your project’s root. Open the terminal and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm run dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start the webpack-dev-server which will bundle the files and run Oats~i. If you open the browser at the url shown in the terminal (often is localhost:8080) and see a page with “Home Fragment” showing, your project has been successfully set up and Oats~i is working fine.&lt;/p&gt;

&lt;h1&gt;
  
  
  Configuration Extensibility
&lt;/h1&gt;

&lt;p&gt;Regardless of whether you’ve manually set up an Oats~i project or used the cli, there are configuration flexibilities you can enjoy thanks to Oats~i running on top of Webpack.&lt;/p&gt;

&lt;p&gt;Basically, apart from the default Oats~i webpack configuration, you can change anything else to your liking as long as you understand webpack, plugins, and loaders, and how they’ll affect your project.&lt;/p&gt;

&lt;p&gt;For instance, you can have a production configuration that will use MiniCssExtractPlugin to extract your css into files that will be added to the final html-webpack-plugin output. You can use advanced babel configurations and even switch handlebars-loader for a loader that suits your favorite templating engine.&lt;/p&gt;

&lt;p&gt;However, the default setup provided by Oats~i is good enough for most projects. Later on in the tutorials, we’ll add a new configuration to create the final production build with key features such as minification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;I encourage you to &lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;learn about Webpack&lt;/a&gt;, why it’s needed, and how you can configure it, to make the most out of Oats~i and other projects you may have using Webpack as a bundler.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sign Up and Follow for the Next Tutorial
&lt;/h1&gt;

&lt;p&gt;That’s it for setting up Oats~i for your project. If you’re working on a new project, just use the cli. It’s easier, faster, and will directly load you into a beautiful starter project that you can inspect and start getting ideas of how to setup a full project with view, styling, and script files in Oats~I, before we start doing that together.&lt;/p&gt;

&lt;p&gt;In the next tutorial, we’ll create our first simple project in Oats~i, where we’ll start learning what routing infos, nav infos, and fragments are in Oats~i.&lt;/p&gt;

&lt;p&gt;Leave a like and follow to get notified when the next tutorial drops.&lt;/p&gt;

&lt;p&gt;See you then.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support Oats~i&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can support the development of Oats~i through &lt;a href="https://www.patreon.com/IanOmondi" rel="noopener noreferrer"&gt;Patreon&lt;/a&gt; or &lt;a href="https://buymeacoffee.com/oats_i" rel="noopener noreferrer"&gt;buy me a coffee&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Introducing Oats~i - The Open Web Framework</title>
      <dc:creator>Oats〜i</dc:creator>
      <pubDate>Tue, 13 Aug 2024 19:29:27 +0000</pubDate>
      <link>https://forem.com/oatsi/introducing-oatsi-the-open-web-framework-2ehp</link>
      <guid>https://forem.com/oatsi/introducing-oatsi-the-open-web-framework-2ehp</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogq1hy18878g15jc056r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogq1hy18878g15jc056r.png" alt="Oats~i Logo" width="500" height="500"&gt;&lt;/a&gt;&lt;br&gt;
I've been an active web developer for about five years now. Back in the end of 2019 when I officially started doing web development, I was surrounded by a vast ecosystem of web development tools that I could leverage to create websites for clients and any personal project I had.&lt;/p&gt;

&lt;p&gt;But I found myself going the do-it-yourself route. Not because am accustomed to pain and head-scratching moments, but rather because I wanted to learn web development from its basics, and not jump right into a framework and build my knowledge from there.&lt;/p&gt;

&lt;p&gt;Besides, that's what most experienced web developers advise. Learn HTML, CSS, and Vanilla JavaScript, and anything else on top of that will be a breeze in the park (sort of).&lt;/p&gt;

&lt;p&gt;Well, here we are, five years later and somehow, I ended up making a web framework of my own. What started out as a simple learning exercise of how the web and web APIs work ended up becoming a full-blown project with countless head scratching moments, disappointments, and eureka.&lt;/p&gt;

&lt;p&gt;Introducing Oats~i, the open web framework that also, takes you back to the basics. Oats~i provides a structure that allows you to create web apps using HTML, CSS, and Vanilla JavaScript, with powerful extensibility, server-side rendering, consent-based routing, reactivity through a data manager, view manager, and hooks, a fragment-based view system, view panels to support extra layouts, popups, and custom views on top of fragments, support for "native" web browsing features such as params, queries, and targets, pagination, code splitting, and lazy loading for JavaScript and view bundles.&lt;/p&gt;

&lt;p&gt;All these come natively with the framework, running on top of Webpack as the preferred module bundler.&lt;/p&gt;

&lt;p&gt;Oats~i doesn't care about your server environment because it's a purely client-side based system. There's no running JS on the server, so no extra special server setup is needed to deploy an Oats~i app.&lt;/p&gt;

&lt;p&gt;But before we get into the details, where is it running now?&lt;/p&gt;

&lt;p&gt;Here: &lt;a href="https://www.vertesolutions.com" rel="noopener noreferrer"&gt;https://www.vertesolutions.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That site is a production site for a client dealing in eco-consultancy and eco-business. The business is called Verte Environmental Solutions, so if you find me referencing "Verte's website," that's the site am referring to.&lt;/p&gt;

&lt;p&gt;Oats~i currently runs in no other place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; The source code is also public. &lt;a href="https://github.com/Oats-i/Oats-i" rel="noopener noreferrer"&gt;https://github.com/Oats-i/Oats-i&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before getting to this point, I've been developing the framework on the site's admin panel (which is custom made), testing, updating, and adding new features over the years. So, if you miss some of what I'll talk about here on the client site, be sure they're running on the admin.&lt;/p&gt;

&lt;p&gt;Also, what I'm introducing is a rather fleshed-out piece of framework, with a couple of features to talk about. So be warned, this is going to be a long piece. And I've tried to edit it as much as I can to make it shorter. However, I've touched the gist of it all with this intro. The rest of the piece, is a scrape of the surface before we start getting deeper in future posts.&lt;/p&gt;

&lt;p&gt;So, enough of this intro.&lt;/p&gt;

&lt;p&gt;Let's get a little bit deeper into Oats~i, as I've built it so far, and look at some of what it offers out of the box and what am planning with it moving forward.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt;: You love videos instead? Watch this intro instead on our YouTube channel: &lt;a href="https://youtu.be/6E_Q25YfQYc?si=U4GjREyvERIP72i-" rel="noopener noreferrer"&gt;https://youtu.be/6E_Q25YfQYc?si=U4GjREyvERIP72i-&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  An Open Web Framework
&lt;/h2&gt;

&lt;p&gt;By calling Oats~i an open web framework, I mean that Oats~i is a simple yet extensible framework whose code can be written in simple HTML and Vanilla JavaScript, with CSS of course being the de-facto styling tool. From this simple setup, you can add your own, third-party or custom templating engines, css libraries, and other tools, as long as Webpack allows it and you can configure it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fragment-Based System
&lt;/h2&gt;

&lt;p&gt;Oats~i works through a build system that spawns up fragments as "components" or core pieces of the web app. Take these simple views for instance:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe325e85o7tfswkbt0ipn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe325e85o7tfswkbt0ipn.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhft3wiu7wxh8q80o8pw3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhft3wiu7wxh8q80o8pw3.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both images have the "root view" of the app, which is the main view of the app that the user will always see. Then there are the other views (fragments) will be rendered dynamically within.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywuqo6myp3xe5m1hxp2j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywuqo6myp3xe5m1hxp2j.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmmg46bnv1mwxq62pf2i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmmg46bnv1mwxq62pf2i.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The root view can contain the primary navigation links or buttons, and other views that the user will always see on the app, and will typically not change.&lt;/p&gt;

&lt;p&gt;The rest of the views inside the root view will change, and this will be based on fragments being loaded and offloaded off the app, based on the user's routing. Fragments go through a build process that primarily gets the view to be rendered, places it in the targeted parent node, and then allows you to wire the rest of your app and business logic.&lt;/p&gt;

&lt;p&gt;An Oats~i build process will typically trigger the following core methods in your fragment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//gets the view for your fragment
async initializeView(cb){
}

//triggers after the fragment view has been attached to the DOM
onUIBind(serverSideRendered){
}

//triggers after the fragment has completed building and anytime its rebuilt for the same route
async onQueryParamsDataUpdate(changedParams, data, savedState, routeParams, isServerSide){
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's basically it.&lt;/p&gt;

&lt;p&gt;With such a skeletal structure you have a couple of flexibilities, such as:&lt;/p&gt;

&lt;h3&gt;
  
  
  Rendering Simple HTML or Loading Complex Views Using Templating Engines (Of Your Choice)
&lt;/h3&gt;

&lt;p&gt;The first method you override (initializeView()) can be completed like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async initializeView(cb){

  const viewAsString = `&amp;lt;p class="text"&amp;gt;My view&amp;lt;/p&amp;gt;`;
  this.onViewInitSuccess(viewAsString, cb);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get our view as a HTML string and pass it to the internal method (onViewInitSuccess()) that also takes the callback that is passed to the original method.&lt;/p&gt;

&lt;p&gt;Calling onViewInitSuccess() triggers the build process to continue to the next steps.&lt;/p&gt;

&lt;p&gt;Writing HTML as a string within JS is simple and Oats~i allows for it but, it can often get problematic. However, instead of building a new syntax or system for writing views for Oats~i, Oats~i allows you to plug in whatever templating engine works best for your use case, wire it up in your webpack config, and let it work its magic.&lt;/p&gt;

&lt;p&gt;For Verte's case, I use handlebars, combined with handlebars-loader to write separate view files in hbs format and simply require them in my code.&lt;/p&gt;

&lt;p&gt;So, instead of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const viewAsString = `&amp;lt;p class="text"&amp;gt;My view&amp;lt;/p&amp;gt;`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My views are now provided as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const viewAsString = require("./relative/path/to/view.hbs")(myTemplatingData);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I want to use ejs instead, for instance, I just have to update my webpack config and use the right import syntax for that use case.&lt;/p&gt;

&lt;p&gt;Oats~i only cares that the view passed to it is a HTML string.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network-Sourcing Views
&lt;/h3&gt;

&lt;p&gt;Oats~i goes as far as allowing you to source your views over network. That's partially why the async exists on the initializeView() method.&lt;/p&gt;

&lt;p&gt;Oats~i also expects you to possibly make network calls at this stage, either for a complete view based on user type or other factors, or get templating data based on your view and business logic.&lt;/p&gt;

&lt;p&gt;What you do here is totally dependent on your business and technical reasons.&lt;/p&gt;

&lt;p&gt;**NOTE: **There's a good reason why the build system doesn't wait for promises at the build stage to resolve using await or then(), but instead uses a callback passed to the relevant methods. That will be clear when we'll be diving deep into how Oats~i works, in a later piece.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vanilla JavaScript or a Compatible JS Library for App or Business Logic
&lt;/h2&gt;

&lt;p&gt;Oats~i code is in vanilla JavaScript, the "native" language web browsers understand. However, there are a few flexibilities that you can have when writing your business logic.&lt;/p&gt;

&lt;p&gt;For instance, you can port jQuery in your project, for whatever reason, and use it to write part of your logic. I actually did this a long while back, even before Oats~i had been built to its current state, to write about five lines of code for smooth scrolling effects in Verte's website. (TLDR, I was lazy to think beyond Stack Overflow, lol).&lt;/p&gt;

&lt;p&gt;You can theoretically use Oats~i in a TypeScript environment, but am yet to test this. The only use I had for TypeScript was its typing system, in conjuction with JSDocs, to document types within the framework, a method which I documented about a while back.&lt;/p&gt;

&lt;p&gt;You can read about integrating JSDocs and TypeScript for typing purposes, without the build process, here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Splitting and Lazy Loading
&lt;/h2&gt;

&lt;p&gt;Webpack is a powerful web development tool that allows for massively complex project configurations, giving development teams the flexibility that they need to build a project to its unique spec. &lt;/p&gt;

&lt;p&gt;Oats~i runs on top of Webpack, with the framework primarily relying on Webpack's code splitting and lazy loading feature to support async fragment chunks and bundles.&lt;/p&gt;

&lt;p&gt;This means your fragments can be loaded in one bundle or split using webpack into multiple chunks, optimizing initial load speeds for your Oats~i web app. Pair this with network-sourced views, if your app needs them, and there are multiple ways you can optimize your app in Oats~i to ensure the best user experience as far as loading times are concerned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Project Configurations Using Webpack
&lt;/h2&gt;

&lt;p&gt;Perhaps the biggest advantage of having webpack as a base for Oats~i is the large configuration left at your disposal, allowing you to craft your app as you need it.&lt;/p&gt;

&lt;p&gt;That's why you can set up templating engines that suit your view rendering process, configure babel and other loaders/plugins for your app, and simply build something that is fully-specced to your project's specifics.&lt;/p&gt;

&lt;p&gt;Oats~i runs a simple base webpack configuration that sets up handlebars-loader, html-loader, css loader, asset loader, and HTMLWebpackPlugin to create your server-side views or templates. Using webpack-merge, you can extend these configurations and architect your web app as you want it.&lt;/p&gt;

&lt;p&gt;This makes Oats~i works a lot like a plug-and-play system. It gives you a skeleton, and you can wrap and configure your app around it as you like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing
&lt;/h2&gt;

&lt;p&gt;Routing is a default feature in Oats~i. In fact, to run the app, you must provide routing information that the app will use to initialize itself and manage user navigation and fragment rendering.&lt;/p&gt;

&lt;p&gt;A simple routing information looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Const MyRoutingInfos = [
  {
    route: "/my-route",
    target: myMainFragmentBuilder,
    nestedChildFragments: [
      myNestedChildFragmentBuilder
    ]
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When Oats~i loads from the server, it checks the current url and finds a match for it in the provided routing info. In Verte's case, when you load "/", Oats~i searches for the routing info with that that route as a match and then inflates the fragments in order from "target" to each nested child fragment.&lt;/p&gt;

&lt;p&gt;You can also provide a default route that Oats~i will try to start the app from, unless the client had sourced the page from a valid route given in your routing info.&lt;/p&gt;

&lt;h3&gt;
  
  
  Params in Routing
&lt;/h3&gt;

&lt;p&gt;Oats~i also supports the use of params in routes, using the colon syntax commonly used in express.&lt;/p&gt;

&lt;p&gt;Therefore, a route defined like /:myParams is valid, and will map for routes such as /user-1, /user-2, /user-3.&lt;/p&gt;

&lt;p&gt;Oats~i goes a step farther and parses these params for you.&lt;br&gt;
When setting up your fragment, you have the option of setting up params it should watch out for. The name of the param should be an EXACT match to the name used in your routing info.&lt;/p&gt;

&lt;p&gt;When building the fragment, Oats~i will parse the value, note any changes, and pass two arguments to your onQueryParamsDataUpdate() method. These are an object of all watched params that have changed, and the current value of all watched params.&lt;/p&gt;

&lt;p&gt;Therefore, if you have a fragment that shows user information, defined under the route /:userID, and the client first navigates to /user-xyz, you'll be able to read the value of userID as user-xyz. If the client routes again and this time the route is /user-abc, you'll immediately know that the value of userID has changed to user-abc and you can respond appropriately.&lt;/p&gt;
&lt;h3&gt;
  
  
  Queries Support
&lt;/h3&gt;

&lt;p&gt;Queries are also a core part of web browsing and urls. Oats~i also parses queries for you, as long as you tell the fragment to watch them, using their keys.&lt;/p&gt;

&lt;p&gt;For instance, if your route /:userID maps to /user-3?promptUpgrade=true, and you specify in your fragment that you want to watch updates for the query with the key "promptUpgrade", these will be parsed and sent to the method onQueryParamsDataUpdate() as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;However:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You cannot write routes in your routing info using queries. Only params are supported. Oats~i looks for the valid routing info for a given url after truncating any queries and targets. The parsing will be done afterwards.&lt;/p&gt;

&lt;p&gt;Verte's website already uses this mechanism when rendering views for blog articles at the &lt;a href="https://www.vertesolutions.com/blog" rel="noopener noreferrer"&gt;blog article page&lt;/a&gt;. The route for each article is parameterized and we only respond to a change in the watched param.&lt;/p&gt;
&lt;h3&gt;
  
  
  Consent-Based Routing
&lt;/h3&gt;

&lt;p&gt;This is perhaps a very unique feature from Oats~i. Consent-based routing gives you power over the user experience, allowing you to warn users about navigating away from a crucial page in case there are any pending processes, all controlled in-app.&lt;/p&gt;

&lt;p&gt;Instead of using the provided standard browser API that pops up a dialog box, Oats~i uses a mix of History API and state management to detect a pop or navigation, ask the current rendered fragments for consent, halt subsequent navigation attempts, and proceed only if the user grants it permission.&lt;/p&gt;

&lt;p&gt;If the user chooses to remain in their current view, Oats~i restores the browser's navigation path to the original state.&lt;/p&gt;

&lt;p&gt;Of course, having users click on "ok" every time they want to navigate around your app is a bad idea. So, by default, Oats~i fragments and view panels (more on these later) consent to a navigation attempt by default.&lt;/p&gt;

&lt;p&gt;Verte internally uses this to safeguard the admin when curating blog content, in case the current draft has not yet been picked up by the autosave script within its time delta. In case the admin wants to navigate away from the blog editor and there are unsaved drafts, they'll get a warning through a dialog and choose to either continue navigating away or stay on the page and manually save their work.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pop-Ups, Dialogs, and More Layouts Using View Panels
&lt;/h2&gt;

&lt;p&gt;In Oats~i, the framework will primarily render a route through fragments. However, there's an extra utility called view panels that allows you to render other views that your fragment may need on the fly. These include dialog boxes, hamburger panels, or even loading screens with bespoke information that the user may need.&lt;/p&gt;

&lt;p&gt;To spawn a view panel, you have to request for it through the view panels manager. Oats~i self manages views for fragments and view panels, meaning you never have to write logic to bind your primary fragment views to the DOM or remove them once a view panel or its associated fragment is being destroyed due to a change in navigation.&lt;/p&gt;

&lt;p&gt;A view panel, spawned by a view panels manager is also automatically wired into the consent-routing process of the fragment, allowing you to extend fragment functionality.&lt;/p&gt;

&lt;p&gt;View panels can also watch params and queries.&lt;/p&gt;
&lt;h3&gt;
  
  
  Route-Triggered and Direct-Triggered View Panels
&lt;/h3&gt;

&lt;p&gt;View panels can be triggered either by route changes or directly via a call to the fragment's view panels manager. For the former, this is where having queries in your route and linking them to a view panel within the fragment can come in handy.&lt;/p&gt;

&lt;p&gt;If you have a route "/:post-id" which is currently represented in the browser as "/nice-post?showComments=true", you can use a route-triggered view panel within the fragment to automatically pop a side panel that loads the post comments and allows the user to read through them.&lt;/p&gt;

&lt;p&gt;This feature is typically accessible through the onQueryParamsDataUpdate() method. Calling super (in case you've overridden it) will invoke the fragment's view panels manager to attempt to render any route-triggered view panels.&lt;/p&gt;

&lt;p&gt;The biggest advantage of this kind of setup is that your view panel's rendering and behavior is now tied to the navigation, making the user experience more natural.&lt;/p&gt;

&lt;p&gt;So, given our example, if the user navigated to "/nice-post?showComments=true", read the comments, and pressed back, the route will change back to "/nice-post", the view panels manager will note this change, and automatically trigger the destruction process for the view panel as long as consent has been granted.&lt;/p&gt;

&lt;p&gt;Just like fragments, view panels also grant consent by default. Therefore, you should override the consent method ONLY when necessary.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reactivity and Data Management
&lt;/h2&gt;

&lt;p&gt;A modern web framework is not complete without a good touch of reactivity and data management. And here's where perhaps the most crucial difference between Oats~i and other web frameworks comes in.&lt;/p&gt;

&lt;p&gt;Oats~i doesn't automatically couple views to a piece of data or state. &lt;/p&gt;

&lt;p&gt;Instead, this is left entirely to the developer to do it based on their app or business logic.&lt;/p&gt;

&lt;p&gt;As is, you can use Oats~i to build a web app with multiple static pages rendered under fragments and view panels and end it at that. The app will just work. If you want to add data, network calls, and reactivity, the data manager utility covers everything, and only to the scope that you determine, without affecting any surrounding views or data.&lt;/p&gt;

&lt;p&gt;Let's look at the data manager and its supporting utilities: the network interface and view managers.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Data Manager
&lt;/h3&gt;

&lt;p&gt;The data manager is an Oats~i utility that allows you to tie data, server-resources, and client views together. The data manager holds an array of models, a model being the core piece or type of data associated with a section of your app and its selected views.&lt;/p&gt;

&lt;p&gt;Currently, I've designed it to take a model as an object with arrays nested within, as it's the most common format for passing data around client and server resources (as Json).&lt;/p&gt;

&lt;p&gt;Therefore, a simple model can look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  my: string,
  simple: number,
  obj: {
    ofArrays: number[],
    objArrays: { objKey: string }[]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data manager works by scoping its model. This means that every bit of the model can be treated as a unit, creating a set of dot-separated keys that define a specific value or type in your data.&lt;/p&gt;

&lt;p&gt;For instance, in the example above, the data manager will break down the model into the following scopes: "MODEL_ROOT | my | simple | obj | obj.ofArrays | obj.objArrays | obj.objArrays.array.objKey "&lt;/p&gt;

&lt;p&gt;These scopes represent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MODEL_ROOT -&amp;gt; {
  my: string,
  simple: number,
  obj: {
    ofArrays: number[],
    objArrays: { objKey: string }[]
  }
}

my -&amp;gt; string,

simple -&amp;gt; number

obj -&amp;gt; {
  ofArrays: number[],
  objArrays: { objKey: string }[]
}

obj.ofArrays -&amp;gt; number[]

obj.objArrays -&amp;gt; { objKey: string }[]

obj.objArrays.array.objKey -&amp;gt; string

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can treat these scopes as dot-separated paths to a distinct piece of data.&lt;/p&gt;

&lt;p&gt;With these scopes, the data manager then gives you, the developer, fine-grained control of your data, allowing to assign a network interface or view manager(s) to any of these data.&lt;/p&gt;

&lt;p&gt;Let's shallowly dive into what these two are.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbg8byrq5dh4sdnu0jp4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbg8byrq5dh4sdnu0jp4.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Network Interface
&lt;/h3&gt;

&lt;p&gt;In most apps (native or web), the data shown to the user is sourced from an outside resource, a server. Therefore, the internal model often needs an API interface that sits between itself and the external resource.&lt;/p&gt;

&lt;p&gt;In Oats~i's case, the network interface will perform the CRUD operation you need in relation to the data held by the data manager and ensure both ends are in sync.&lt;/p&gt;

&lt;p&gt;The network interface is defined as an object with three methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getReqBody()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method gets the body of the request and other data such as method, address, headers, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onDataLoadPostProcess()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the type of response data and the type of your internal model may vary, the network interface allows you to post-process the response and provide the final data in the data manager's model type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onDataLoadError()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method allows you to format the error response in case the network call fails.&lt;/p&gt;

&lt;h4&gt;
  
  
  Network Interface Scoping
&lt;/h4&gt;

&lt;p&gt;API designs are varied, meaning, the addresses or routes used to make CRUD operations for a given piece of data can be different.&lt;/p&gt;

&lt;p&gt;For instance, a social media app can have a different API for loading all posts, and each post running unique APIs to repost, like, or report the post.&lt;/p&gt;

&lt;p&gt;Assuming such an architecture, using scoping within the data manager allows you to specify unique network interfaces for each scope.&lt;/p&gt;

&lt;p&gt;For instance, you can have a network interface for the MODEL_ROOT network call (which will load the posts), "repost" network call, and any other call that can be scoped out of the structure of the model the data manager holds.&lt;/p&gt;

&lt;p&gt;This gives you a whole unique way of viewing your data, breaking it down from one large resource with a common end point, to a collection of multiple data units that can be handled independently through the data manager.&lt;/p&gt;

&lt;p&gt;A key thing to note here is that you can only have one network interface per scope, creating a single "endpoint" for every scoped piece of data in your model.&lt;/p&gt;

&lt;h3&gt;
  
  
  View Manager
&lt;/h3&gt;

&lt;p&gt;Through the network interface, the data manager can now keep data in sync between its model and the server. Now what about displaying it to the user and, more importantly, showing them when it's changing?&lt;/p&gt;

&lt;p&gt;That's where the view manager comes in.&lt;/p&gt;

&lt;p&gt;View managers respond to mutations or changes happening to data held by the data manager, through a network operation or a direct in-app change.&lt;/p&gt;

&lt;p&gt;Oats~i currently supports two types of view managers - a standard view manager and a list view manager.&lt;/p&gt;

&lt;p&gt;A standard view manager is ideal for simple views with components that are not duplicated over a list. On the other hand, a list view manager is best for "complex" views with view components duplicated over a list.&lt;/p&gt;

&lt;p&gt;Regardless of the type, a view manager will tell you of the following changes within a model or its scoped types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onMutate()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method fires when a data type of the scope is changing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onCommit()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method fires when a mutation of the data type of the scope has been completed, thus committed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onCancel()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method fires when a mutation of the data type of the scope has been cancelled&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onError()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method fires when a mutation of the data type of the scope has encountered an error, allowing you to retry&lt;/p&gt;

&lt;p&gt;There's also the builder set of methods, which allow you to pass in a view (as a HTML string) inflated with your data. These methods also inform you of when the view has been attached or about to be detached, depending on the mutation.&lt;/p&gt;

&lt;p&gt;These three methods are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inflateRoot()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gets the templated view as a string for the data provided&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onViewAttach()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calls when the view has been attached to the DOM&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onViewDetach()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calls when the view is about to be detached from the DOM&lt;br&gt;
You can see the results of these interactions in the blog pages of Verte's website.&lt;/p&gt;

&lt;p&gt;Using the combination of builder methods, root hooks, and component hooks, the data-driven dynamic views of the blog and blog article fragments can show loading animations when we're sourcing data from the network, show error messages in case of a failure, and populate the views once the new data from the network interface has been committed.&lt;/p&gt;

&lt;p&gt;A view manager will also have component hooks which allow for even finer grained reactivity, with the elements of each view node.&lt;/p&gt;

&lt;p&gt;For instance, using the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  my: string,
  simple: number,
  obj: {
    ofArrays: number[],
    objArrays: { objKey: string }[]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a view manager of the scope "MODEL_ROOT" (therefore the whole model), we can assume that the main view component showing the data of the MODEL_ROOT scope, has components within it that my show the specific data held in "my", "simple", "obj", or generally the child scopes of MODEL_ROOT.&lt;/p&gt;

&lt;p&gt;Therefore, you can set up a component or element of your view to react to changes in these "child" values.&lt;/p&gt;

&lt;p&gt;All these hook methods get a viewNode parameter passed to them by the view manager, so you always have a reference of which view node these data changes are associated with and query its components as you need.&lt;/p&gt;

&lt;p&gt;However, you should not bother with removing these core view elements once they're no longer needed. The view manager handles that for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  No Virtual DOM
&lt;/h2&gt;

&lt;p&gt;Oats~i doesn't operate through a virtual DOM. Instead, the fragments, view panels, and view managers directly use the DOM APIs to insert or remove DOM elements.&lt;/p&gt;

&lt;p&gt;After inserting your view component into the DOM, the view manager will provide you with its direct reference in the builder, root, and component hooks. Therefore, you can just directly add listeners, change attributes, or simply manipulate the DOM element using the direct DOM apis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lifecycle Management
&lt;/h2&gt;

&lt;p&gt;A core bit of a complex web app is lifecycle management. Oats~i has its own lifecycle management process for fragments and view panels, whose functions are extended to other utilities such as the data manager, view managers, and remote request util (the actual utility the data manager uses in conjunction with the network interface to make network calls).&lt;/p&gt;

&lt;p&gt;Therefore, straight off the bat, using Oats~i and its core utilities will have lifecycle automatically managed for you.&lt;/p&gt;

&lt;p&gt;For instance, if you're using the data manager within a fragment to make a CRUD operation, and the user navigates away from the fragment, the data manager and remote request util will be able to cancel all network operations, skip updating view managers, and unregister them, because your fragment or view panel no longer exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listening to Lifecycle Events
&lt;/h3&gt;

&lt;p&gt;As an Oats~i developer, you can make use of a fragment or view panel's lifecycle management to create robust lifecycle-aware libraries that will work well in an Oats~i environment.&lt;/p&gt;

&lt;p&gt;You just have to grab the lifecycle object using the internal method,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getLifeCycleObject()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and attach listeners to it. These listeners typically include four methods for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onFragmentRunning()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Called when the fragment has been created and is running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onFragmentCancelled()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Called when the fragment's build has been cancelled&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onFragmentDestroyed()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Called when the fragment has been destroyed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onViewReady()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Called when the fragment's view has been attached to DOM&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Note: *&lt;/em&gt;"Fragment" here also applies to view panels.&lt;/p&gt;

&lt;p&gt;The main calls you need to watch out for are onFragmentRunning(), onViewReady(), and onFragmentDestroyed(). If your library adds functionality that is not UI-related, you can enable the library after getting the onFragmentRunning() call.&lt;/p&gt;

&lt;p&gt;If the library manipulates views (such as an animation library), you can enable its functionality after receiving the onViewReady() call.&lt;br&gt;
Once you get the onFragmentDestroyed() call, pack up, and stop everything.&lt;/p&gt;
&lt;h2&gt;
  
  
  OOP-Based Core
&lt;/h2&gt;

&lt;p&gt;We have talk about a lot about some core features of Oats~i but we haven't talked about paradigm. How will you write core Oats~i code?&lt;/p&gt;

&lt;p&gt;Well, Oats~i is an OOP-based web framework. That means most utilities are provided as classes. A fragment is created from an AppMainFragment or AppChildFragment class. The data manager is a class. View managers are classes and so on.&lt;/p&gt;

&lt;p&gt;I chose OOP because of its reusability, garbage collection, and a much cleaner way of managing functions and processes within Oats~i.&lt;/p&gt;

&lt;p&gt;For instance, no pun intended, having the fragment as a class allows Oats~i to do something clever. It never reconstructs the fragment class if it determines that its being reused. Instead, the build process just goes directly to firing onQueryParamsDataUpdate(), and doesn't re-render the fragment's main view or update that section of the DOM, since it's unnecessary.&lt;/p&gt;

&lt;p&gt;Another advantage of doing this is that your fragment can retain part of its state amidst related route calls.&lt;/p&gt;

&lt;p&gt;For instance, in Verte's case, when you're in the fragment that renders a blog article, clicking on another article under the "Other stories" list doesn't reconstruct the fragment. Instead, the original view is untouched, and only the dynamic, data-driven views, ran by the data manager in conjunction with the view manager, update based on the new param value obtained from onQueryParamsDataUpdate().&lt;/p&gt;
&lt;h3&gt;
  
  
  Exploiting Functional Programming
&lt;/h3&gt;

&lt;p&gt;Just because the Oats~i core uses OOP, doesn't mean you're fully restricted to creating libraries that follow the OOP paradigm. Simply making them lifecycle aware is enough.&lt;/p&gt;

&lt;p&gt;This will allow them to capture and free resources from the fragment as Oats~i renders and destroys them.&lt;/p&gt;

&lt;p&gt;When porting Verte's client to Oats~i, I've used this exact strategy to reuse some functional scripts I'd written for the original webpages.&lt;/p&gt;

&lt;p&gt;Therefore, I expect very few bottlenecks and paradigm strictness for developers seeking to use their functional scripts in an Oats~i project, as long as they're lifecycle aware.&lt;/p&gt;
&lt;h2&gt;
  
  
  Server-Side Rendering (Views and Data)
&lt;/h2&gt;

&lt;p&gt;Finally, a big part of modern web frameworks - server-side rendering.&lt;br&gt;
Oats~i natively supports server-side rendering, with no need for running JavaScript on the server.&lt;/p&gt;

&lt;p&gt;Using HTMLWebpackPlugin, you can extract the views you use for each fragment in your Oats~i app into their own .html/.hbs files that you can send to the client when they request for a page on a fresh load.&lt;/p&gt;

&lt;p&gt;The only requirement is your view structure from the server is the same as the app would have rendered it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn06ie3zvg5o2xd92lwjn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn06ie3zvg5o2xd92lwjn.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But we're not done yet.&lt;/p&gt;
&lt;h3&gt;
  
  
  Data Manager Hydration
&lt;/h3&gt;

&lt;p&gt;The views you'll render from your server most likely will represent some state of data. How does Oats~i handle this and proceed from the server-side rendered state?&lt;/p&gt;

&lt;p&gt;You'll ideally be using the data manager to manage dynamic or data-driven views in your Oats~i app. Now, using it, you can can leverage server-side hydration that uses a script rendered in the head tag from the server to help the data manager understand the data state from the server, save it, and have attached view managers also update their states based on it, and continue running the app from there.&lt;/p&gt;

&lt;p&gt;Here's how it works.&lt;/p&gt;

&lt;p&gt;In your markup's head, at the server, you can add a script of the following format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script id="hydrator_id"&amp;gt;
  const DataManagerHydrationInfo = {
    "info_key": {
      info: model[]
      extras: *
    }
  }
  window.DataManagerHydrationInfo = DataManagerHydrationInfo;
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script provides important information for the data manager from the server, that gives it the full picture or an idea of the data state.&lt;/p&gt;

&lt;p&gt;Each data manager will have an "info_key" that it will read its data state from. Once you set the data manager to hydrate from server side, it will find the script with the id you provide, get the exposed variable DataManagerHydrationInfo, and read the value of "info_key".&lt;/p&gt;

&lt;p&gt;This value should be an array, ideally of the same type as the data manager's model. However, it can be different.&lt;/p&gt;

&lt;p&gt;That's because the data manager runs a multi-step hydration process.&lt;/p&gt;

&lt;h4&gt;
  
  
  Validation
&lt;/h4&gt;

&lt;p&gt;Reading from a script can have its own issues and vulnerabilities. You can run a validation check on the data stored in the hydration script before the data manager commits it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Preprocessing
&lt;/h4&gt;

&lt;p&gt;Depending on your business logic and web app design, the data format sourced from your server can be different from the model you run in your data manager. Oats~i's data manager runs an optional preprocessing step during hydration, that allows you to convert the data from the hydrator to your model's format.&lt;/p&gt;

&lt;h4&gt;
  
  
  Network Step
&lt;/h4&gt;

&lt;p&gt;This step permits you to be cautious with the data you let free in your hydration script, open to web scrapers, robots, and search engines.&lt;/p&gt;

&lt;p&gt;You can run an optional network step where you can get private or hidden data that your data manager's model needs, but should never be privy to web scrapers or robots scouring the web.&lt;/p&gt;

&lt;p&gt;For instance, if you're hydrating a shopping cart, you can have the hydration script from the server contain only general information about the products, with public ids that when passed to your secure backend, will return more secret information that you'll use to check-out the user.&lt;/p&gt;

&lt;p&gt;So, your hydration script can hold information as basic as what is already rendered in the html, have the data manager commit that immediately internally, then source everything else from the network cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Next for Oats~i?
&lt;/h2&gt;

&lt;p&gt;If you've managed to read up to this point, kudos, you're a champ! That's the best I could do to try and squeeze roughly four years of work into a small "introductory" blog post.&lt;/p&gt;

&lt;p&gt;Oats~i has been a massive learning project for me and am both anxious and excited to let the tech community know about it. There's a lot to unpack, teach, learn, and debug.&lt;/p&gt;

&lt;p&gt;My plan at the moment is to open source Oats~i. I'm working on the specifics and hopefully the whole codebase will drop in the next few days and we can all dig in, build actual web apps through the framework, and take it up its paces.&lt;/p&gt;

&lt;p&gt;For now, I'll appreciate your feedback, comments, and questions concerning Oats~i, if you have any.&lt;br&gt;
Check out &lt;a href="http://www.vertesolutions.com/" rel="noopener noreferrer"&gt;Verte Environmental Solution's website&lt;/a&gt; and see it in action.&lt;/p&gt;

&lt;p&gt;I'm available on &lt;a href="https://www.linkedin.com/in/ian-omondi-c/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, so drop by and say hi.&lt;/p&gt;

&lt;p&gt;See you soon, when we'll, hopefully, start building with Oats~i.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; The source code is now public. &lt;a href="https://github.com/Oats-i/Oats-i" rel="noopener noreferrer"&gt;https://github.com/Oats-i/Oats-i&lt;/a&gt;&lt;/p&gt;

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