首頁  >  文章  >  web前端  >  Oats 簡介~i - 開放式 Web 框架

Oats 簡介~i - 開放式 Web 框架

王林
王林原創
2024-08-14 10:34:32985瀏覽

Introducing Oats~i - The Open Web Framework
我作為一名活躍的網頁開發人員已經大約五年了。早在 2019 年底,當我正式開始進行 Web 開發時,我周圍就有一個龐大的 Web 開發工俱生態系統,我可以利用這些工具為客戶和我擁有的任何個人專案創建網站。

但我發現自己走的是自己動手的路線。不是因為我習慣了痛苦和令人頭痛的時刻,而是因為我想從基礎知識開始學習 Web 開發,而不是直接跳入框架並從那裡建立我的知識。

此外,這是大多數經驗豐富的 Web 開發人員的建議。學習 HTML、CSS 和 Vanilla JavaScript,以及除此之外的任何其他內容(某種程度上)都會變得輕而易舉。

好了,五年後,不知何故,我最後製作了一個自己的 Web 框架。最初只是一個關於 Web 和 Web API 如何運作的簡單學習練習,最終成為一個成熟的項目,其中有無數令人頭痛的時刻、失望和頓悟。

隆重推出 Oats~i,這是一個開放式 Web 框架,它也可以帶您回​​到基礎知識。 Oats~i 提供了一種結構,可讓您使用HTML、CSS 和Vanilla JavaScript 建立Web 應用程序,具有強大的可擴展性、伺服器端渲染、基於同意的路由、透過資料管理器、視圖管理器和鉤子的反應性、片段基於視圖系統、視圖面板支援額外的佈局、彈出視窗和片段頂部的自訂視圖,支援「本機」Web 瀏覽功能,例如參數、查詢和目標、分頁、程式碼分割以及JavaScript 和延遲加載查看捆綁包。

所有這些都是框架本身自帶的,作為首選模組捆綁器運行在 Webpack 之上。

Oats~i 不關心你的伺服器環境,因為它是純粹基於客戶端的系統。伺服器上沒有運行 JS,因此不需要額外的特殊伺服器設定來部署 Oats~i 應用程式。

但是在我們了解詳細資訊之前,它現在在哪裡運行?

這裡:https://www.vertesolutions.com

該網站是一家從事生態諮詢和生態業務的客戶的生產網站。該公司名為 Verte Environmental Solutions,因此如果您發現我引用“Verte 的網站”,那就是我所指的網站。

Oats~i目前沒有在其他地方運行。

編輯:原始碼也是公開的。 https://github.com/Oats-i/Oats-i

在達到這一點之前,多年來我一直在網站的管理面板(定制的)上開發框架、測試、更新和添加新功能。因此,如果您錯過了我將在客戶端網站上討論的一些內容,請確保它們在管理員上運行。

此外,我要介紹的是一個相當充實的框架,有幾個功能值得討論。所以請注意,這將會是一篇很長的文章。我已盡力對其進行編輯以使其更短。然而,我已經透過這個介紹觸及了這一切的要點。在我們開始深入了解未來的文章之前,本文的其餘部分只是表面的粗淺。

所以,這個介紹已經夠了。

讓我們更深入地了解 Oats~i,因為我到目前為止已經建造了它,並看看它提供的一些開箱即用的功能以及未來的計劃。

開放的 Web 框架

透過將Oats~i 稱為開放式Web 框架,我的意思是Oats~i 是一個簡單但可擴展的框架,其程式碼可以用簡單的HTML 和Vanilla JavaScript 編寫,當然CSS 是事實上的樣式工具。透過這個簡單的設置,您可以添加自己的、第三方或自訂的模板引擎、CSS 庫和其他工具,只要 Webpack 允許並且您可以配置它。

基於片段的系統

Oats~i 透過建置系統工作,該系統產生片段作為 Web 應用程式的「元件」或核心部分。以這些簡單的視圖為例:

Introducing Oats~i - The Open Web Framework

Introducing Oats~i - The Open Web Framework

這兩個圖像都有應用程式的“根視圖”,這是用戶將始終看到的應用程式的主視圖。然後還有其他視圖(片段)將在其中動態渲染。

Introducing Oats~i - The Open Web Framework

Introducing Oats~i - The Open Web Framework

根視圖可以包含主導航連結或按鈕,以及使用者將始終在應用程式上看到的其他視圖,並且通常不會更改。

根視圖中的其餘視圖將發生變化,這將基於根據使用者的路由從應用程式載入和卸載的片段。片段會經歷一個建置過程,該過程主要獲取要渲染的視圖,將其放置在目標父節點中,然後允許您連接應用程式的其餘部分和業務邏輯。

Oats~i 建造過程通常會觸發片段中的以下核心方法:

//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){
}

基本上就是這樣。

有了這樣的骨架結構,你就有了一些彈性,例如:

使用模板引擎(由您選擇)渲染簡單的 HTML 或載入複雜的視圖

您重寫的第一個方法(initializeView())可以像這樣完成:

async initializeView(cb){

  const viewAsString = `<p class="text">My view</p>`;
  this.onViewInitSuccess(viewAsString, cb);
}

我們以 HTML 字串的形式取得視圖,並將其傳遞給內部方法 (onViewInitSuccess()),該方法也接受傳遞給原始方法的回呼。

呼叫 onViewInitSuccess() 會觸發建置過程以繼續後續步驟。

在 JS 中將 HTML 編寫為字串很簡單,Oats~i 允許這樣做,但它經常會出現問題。然而,Oats~i 不會為Oats~i 建立新的語法或系統來編寫視圖,而是允許您插入最適合您的用例的任何模板引擎,將其連接到您的webpack 配置中,並讓它發揮其魔力.

對於Verte的情況,我使用handlebars,結合handlebars-loader以hbs格式編寫單獨的視圖文件,並在我的程式碼中簡單地需要它們。

所以,而不是

const viewAsString = `<p class="text">My view</p>`;

我的觀點現提供如下:

const viewAsString = require("./relative/path/to/view.hbs")(myTemplatingData);

例如,如果我想使用 ejs,我只需更新我的 webpack 配置並針對該用例使用正確的導入語法。

Oats~我只關心傳遞給它的視圖是一個 HTML 字串。

網路採購觀點

Oats~i 甚至允許您透過網路取得您的觀點。這就是為什麼在initializeView()方法中存在非同步的部分原因。

Oats~i 還希望您在這個階段可能進行網絡調用,要么根據用戶類型或其他因素獲得完整的視圖,要么根據您的視圖和業務邏輯獲取模板資料。

您在這裡所做的事情完全取決於您的業務和技術原因。

**注意:**建置系統不等待建置階段的 Promise 使用 wait 或 then() 進行解析,而是使用傳遞給相關方法的回調,這是有充分理由的。當我們在後面的文章中深入探討 Oats~i 的工作原理時,這一點就會很清楚。

適用於應用程式或業務邏輯的 Vanilla JavaScript 或相容的 JS 程式庫

Oats~i 程式碼採用普通 JavaScript,即網頁瀏覽器可以理解的「本機」語言。但是,在編寫業務邏輯時,您可以擁有一些靈活性。

例如,無論出於何種原因,您都可以將 jQuery 移植到您的專案中,並使用它來編寫部分邏輯。實際上,我很久以前就這樣做了,甚至在 Oats~i 構建到當前狀態之前,就為 Verte 網站中的平滑滾動效果編寫了大約五行程式碼。 (長話短說,我懶得去思考 Stack Overflow 以外的事情,哈哈)。

理論上你可以在 TypeScript 環境中使用 Oats~i,但我還沒有對此進行測試。我對 TypeScript 的唯一用途是它的類型系統,與 JSDocs 結合使用,在框架內記錄類型,這是我不久前記錄的一種方法。

您可以在此處閱讀有關整合 JSDocs 和 TypeScript 以進行打字的信息,而無需建置流程。

程式碼分割和延遲載入

Webpack 是一個功能強大的 Web 開發工具,允許進行大規模複雜的專案配置,為開發團隊提供了根據其獨特規格建立專案所需的靈活性。

Oats~i 運行在 Webpack 之上,該框架主要依靠 Webpack 的程式碼分割和延遲載入功能來支援非同步片段區塊和捆綁。

這表示您的片段可以載入到一個套件中,也可以使用 webpack 拆分成多個區塊,從而優化 Oats~i Web 應用程式的初始載入速度。如果您的應用程式需要,請將其與網路來源的視圖配對,並且您可以透過多種方式在 Oats~i 中優化您的應用程序,以確保就加載時間而言提供最佳的用戶體驗。

使用 Webpack 的高階專案配置

也許以 webpack 作為 Oats~i 基礎的最大優勢是您可以使用的大型配置,讓您可以根據需要製作應用程式。

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.

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.

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.

Routing

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.

A simple routing information looks like this:

Const MyRoutingInfos = [
  {
    route: "/my-route",
    target: myMainFragmentBuilder,
    nestedChildFragments: [
      myNestedChildFragmentBuilder
    ]
  }
]

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.

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.

Params in Routing

Oats~i also supports the use of params in routes, using the colon syntax commonly used in express.

Therefore, a route defined like /:myParams is valid, and will map for routes such as /user-1, /user-2, /user-3.

Oats~i goes a step farther and parses these params for you.
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.

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.

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.

Queries Support

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.

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.

However:

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.

Verte's website already uses this mechanism when rendering views for blog articles at the blog article page. The route for each article is parameterized and we only respond to a change in the watched param.

Consent-Based Routing

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.

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.

If the user chooses to remain in their current view, Oats~i restores the browser's navigation path to the original state.

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.

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.

Pop-Ups, Dialogs, and More Layouts Using View Panels

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.

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.

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.

View panels can also watch params and queries.

Route-Triggered and Direct-Triggered View Panels

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.

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.

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.

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.

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.

Just like fragments, view panels also grant consent by default. Therefore, you should override the consent method ONLY when necessary.

Reactivity and Data Management

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.

Oats~i doesn't automatically couple views to a piece of data or state.

Instead, this is left entirely to the developer to do it based on their app or business logic.

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.

Let's look at the data manager and its supporting utilities: the network interface and view managers.

The Data Manager

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.

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).

Therefore, a simple model can look something like this:

{
  my: string,
  simple: number,
  obj: {
    ofArrays: number[],
    objArrays: { objKey: string }[]
  }
}

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.

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 "

These scopes represent:

MODEL_ROOT -> {
  my: string,
  simple: number,
  obj: {
    ofArrays: number[],
    objArrays: { objKey: string }[]
  }
}

my -> string,

simple -> number

obj -> {
  ofArrays: number[],
  objArrays: { objKey: string }[]
}

obj.ofArrays -> number[]

obj.objArrays -> { objKey: string }[]

obj.objArrays.array.objKey -> string

You can treat these scopes as dot-separated paths to a distinct piece of data.

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.

Let's shallowly dive into what these two are.

Introducing Oats~i - The Open Web Framework

Network Interface

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.

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.

The network interface is defined as an object with three methods:

getReqBody()

This method gets the body of the request and other data such as method, address, headers, etc.

onDataLoadPostProcess()

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.

onDataLoadError()

This method allows you to format the error response in case the network call fails.

Network Interface Scoping

API designs are varied, meaning, the addresses or routes used to make CRUD operations for a given piece of data can be different.

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.

Assuming such an architecture, using scoping within the data manager allows you to specify unique network interfaces for each scope.

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.

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.

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.

View Manager

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?

That's where the view manager comes in.

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.

Oats~i currently supports two types of view managers - a standard view manager and a list view manager.

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.

Regardless of the type, a view manager will tell you of the following changes within a model or its scoped types:

onMutate()

This method fires when a data type of the scope is changing

onCommit()

This method fires when a mutation of the data type of the scope has been completed, thus committed

onCancel()

This method fires when a mutation of the data type of the scope has been cancelled

onError()

This method fires when a mutation of the data type of the scope has encountered an error, allowing you to retry

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.

These three methods are:

inflateRoot()

Gets the templated view as a string for the data provided

onViewAttach()

Calls when the view has been attached to the DOM

onViewDetach()

Calls when the view is about to be detached from the DOM
You can see the results of these interactions in the blog pages of Verte's website.

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.

A view manager will also have component hooks which allow for even finer grained reactivity, with the elements of each view node.

For instance, using the model:

{
  my: string,
  simple: number,
  obj: {
    ofArrays: number[],
    objArrays: { objKey: string }[]
  }
}

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.

Therefore, you can set up a component or element of your view to react to changes in these "child" values.

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.

However, you should not bother with removing these core view elements once they're no longer needed. The view manager handles that for you.

No Virtual DOM

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.

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.

Lifecycle Management

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).

Therefore, straight off the bat, using Oats~i and its core utilities will have lifecycle automatically managed for you.

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.

Listening to Lifecycle Events

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.

You just have to grab the lifecycle object using the internal method,

getLifeCycleObject()

and attach listeners to it. These listeners typically include four methods for:

onFragmentRunning()

Called when the fragment has been created and is running

onFragmentCancelled()

Called when the fragment's build has been cancelled

onFragmentDestroyed()

Called when the fragment has been destroyed

onViewReady()

Called when the fragment's view has been attached to DOM

*Note: *"Fragment" here also applies to view panels.

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.

If the library manipulates views (such as an animation library), you can enable its functionality after receiving the onViewReady() call.
Once you get the onFragmentDestroyed() call, pack up, and stop everything.

OOP-Based Core

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?

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.

I chose OOP because of its reusability, garbage collection, and a much cleaner way of managing functions and processes within Oats~i.

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.

Another advantage of doing this is that your fragment can retain part of its state amidst related route calls.

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().

Exploiting Functional Programming

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.

This will allow them to capture and free resources from the fragment as Oats~i renders and destroys them.

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.

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.

Server-Side Rendering (Views and Data)

Finally, a big part of modern web frameworks - server-side rendering.
Oats~i natively supports server-side rendering, with no need for running JavaScript on the server.

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.

The only requirement is your view structure from the server is the same as the app would have rendered it.

Introducing Oats~i - The Open Web Framework

But we're not done yet.

Data Manager Hydration

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?

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.

Here's how it works.

In your markup's head, at the server, you can add a script of the following format:

<script id="hydrator_id">
  const DataManagerHydrationInfo = {
    "info_key": {
      info: model[]
      extras: *
    }
  }
  window.DataManagerHydrationInfo = DataManagerHydrationInfo;
</script>

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.

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".

This value should be an array, ideally of the same type as the data manager's model. However, it can be different.

That's because the data manager runs a multi-step hydration process.

Validation

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.

Preprocessing

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.

Network Step

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.

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.

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.

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.

What Next for Oats~i?

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.

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.

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.

For now, I'll appreciate your feedback, comments, and questions concerning Oats~i, if you have any.
Check out Verte Environmental Solution's website and see it in action.

I'm available on LinkedIn, so drop by and say hi.

See you soon, when we'll, hopefully, start building with Oats~i.

EDIT: The source code is now public. https://github.com/Oats-i/Oats-i

以上是Oats 簡介~i - 開放式 Web 框架的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:CSS 項目 1下一篇:CSS 項目 1