من از دهه 90 به نوشتن بکاند و فرانتاند وب پرداختم. در نهایت: نشانه گذاری دکلراتیو و پویا به درستی انجام شد

من از دهه 90 به نوشتن بکاند و فرانتاند وب پرداختم. CGI، ISAPI، AJAX – شما نام ببرید، TLA وجود ندارد که من برای نوشتن خدمات با کیفیت تولید، زمان واقعی و پویا در مرورگرها استفاده نکرده باشم.
CGI کار می کند، اما ارائه یک صفحه یا فریم کامل برای سرورها و مدیران جلسه کار زیادی بود و فاقد تعاملی بود که کاربران انتظار داشتند. React یک تعریف ثابت برای عناصر وب ماژولار و قابل استفاده مجدد ارائه کرد، اما وقتی از اجزای ساده فراتر رفتید، اندازه و پیچیدگی بسیار زیاد اجرای آن کمی دردناک می شود. کتابخانههایی مانند raw.js به این موضوع پرداختهاند، اما آنها اساسا درخت تعاملی رابط کاربری را مدیریت نمیکنند، بلکه صرفاً راههای جایگزینی برای ایجاد نشانهگذاری ارائه میکنند.
چه front-end (React و چارچوبهای مشابه) و چه باطن (CGI، سیستمهای قالببندی)، شرط اساسی همیشه این است که مقداری HTML را با جایگزینهای پویا اعلام کنید:
Hello ${name}!
Here is the news...
${newsItems}
فرقی نمیکند که سرور جانشینها را بهطور مستقیم پر میکند یا کلاینت این کار را از طریق یک DOM مجازی انجام میدهد، هدف این است که محتوا را چیدمان کند و امکان بهروزرسانی خودکار آن را برای برخی فرآیند جادویی فراهم کند.
مرورگرهای مدرن برخی از فناوریهای کلیدی را برای انجام این کار به صورت بومی و بدون نیاز به فرآیند ساخت آنقدر پیچیده و درخت وابستگی آنقدر متراکم ارائه میکنند که خوششانس خواهید بود که از جنگل به مناطق مرتفع آفتابی تحویل واقعی پروژه فرار کنید!
AI-UI “Async Iterator UI” این کار را در یک ماژول کوچک و متمرکز سمت مشتری، بدون وابستگی، با استفاده از ساختارهای جاوا اسکریپت بومی انجام می دهد.
مشکل قالب ها
مشکل اساسی بیشتر ابزارهای قالب این است که متغیرهای زیربنایی خود مقادیر ثابتی در زمان پردازش الگو هستند. ابزار یا چارچوب باید به نحوی تغییرات را دوباره بخواند یا ردیابی کند ${variables}
و ${expressions}
در طرحبندی خود (یا بدتر از آن، باید از دستور یا تابع محرمانه برای تنظیم و دریافت «وضعیت» استفاده کنید)، و سپس به معنای آن برای نشانهگذاری نهایی بیابید.
در AI-UI، متغیرها و عبارات شما میتوانند خودشان «زنده» باشند – آنها میتوانند خودشان را بهروزرسانی کنند، مستقیماً DOM را بدون هیچ تفاوتی بهروزرسانی کنند و طبیعتاً حداقل بهروزرسانیها را پیادهسازی کنند.
میتوانید آنها را مانند مراجع سلولی در صفحهگسترده در نظر بگیرید: یک سلول را بهروزرسانی میکنید و بقیه سلولها را مجدداً محاسبه و ترسیم میکنند.
این به سادگی با اجازه دادن به جایگزینها در طرحبندی AI-UI به عنوان تکرارکننده یا وعدههای ناهمگام جاوا اسکریپت به دست میآید (البته، آنها فقط میتوانند عبارات ثابت عادی نیز باشند).
تکرار کننده ها، رویدادها، مؤلفه ها
برای سهولت استفاده از آن، AI-UI برخی از ویژگی های کلیدی را ارائه می دهد:
- کتابخانه ای از توابع کلیدی برای مدیریت تکرارکننده های همگام (
map
،filter
،consume
،merge
،combine
…) - ارائه رویدادهای DOM بهعنوان تکرارکنندههای ناهمگام، بنابراین میتوانید به سرعت و به راحتی عناصر DOM را به یکدیگر پیوند دهید، بدون اینکه نیازی به مدیریت کل مجموعهای از شنوندگان رویداد و حذف آنها در هنگام تغییر DOM باشد.
- محصور کردن عناصر DOM در کنار هم در یک ساختار ایمن از نظر نوع، بنابراین مصرف کنندگان اجزای شما دقیقاً می دانند چه ویژگی هایی را می توان برای کنترل اجزای شما تنظیم کرد.
- به شما اجازه می دهد تا ویژگی های عنصر DOM جدید را به عنوان تعریف کنید
iterable
، بنابراین می توانید به راحتی تغییرات را بخوانید، بنویسید و با دستور زبان جاوا اسکریپت مشترک شویدweatherChart.location = "London";
- یک برنامه افزودنی مفید Chrome Devtools برای کاوش در اجزای DOM و سلسله مراتب آنها و ثبت گزارش مفید در طول توسعه.
همه عناصر ایجاد شده توسط AI-UI عناصر DOM استاندارد هستند و از API کامل و استاندارد DOM پشتیبانی می کنند تا بتوانید آنها را با هر وب سایت یا چارچوب موجود ادغام کنید.
مشخص کردن چیدمان
از آنجایی که AI-UI یک ماژول جاوا اسکریپت است، شما طرح بندی را به عنوان یک سری فراخوانی تابع مشخص می کنید. با این حال، JSX و htm را نیز به طور کامل پشتیبانی میکند، بنابراین میتوانید از نشانهگذاری آشناتری به قیمت از دست دادن برخی از انواع ایمنی استفاده کنید. اطلاعات بیشتری در مورد این انتخاب ها در راهنمای AI-UI در اینجا وجود دارد.
در این مقاله، من از نماد عملکردی استفاده خواهم کرد زیرا ایمن ترین نوع آن است. خیلی ساده است: یک عنصر DOM با فراخوانی تابعی که نام آن عنصر است ایجاد می شود:
// AI-UI uses normal functions to create fully typed elements
const elt = div("Hello ",
span({style: 'color: green'},
" there ", name
)
);
// elt is derived from HTMLDivElement
… که دقیقاً همان نتیجه را ایجاد می کند:
// HTM uses tagged template strings to create one or more Nodes
const elt = html`
Hello
there ${name}
`;
// elt is a Node or Node[]
// JSX uses a transpiler to change the markup into function calls that return an unknown type
const elt =
<div>Hello
<span style="color: green">
there {name}
</span>
</div>;
// elt is any
توابع ایجاد عنصر همگی یک شی اختیاری دارند که هر ویژگی را مشخص میکند، و صفر یا چند گره فرزند، که میتواند رشتهها، اعداد، گرههای DOM، مجموعههایی از اینها یا وعدهها یا تکرارکنندههای غیرهمگام برای هر یک از موارد بالا باشد.
جادو اینجاست که name
، می تواند نه تنها یک مقدار مانند باشد "Mat"
یا 123
، اما همچنین یک تکرار کننده غیر همگام که این مقادیر را تولید می کند. هنگامی که تکرار کننده غیر همگام مقدار جدیدی تولید می کند، AI-UI DOM را به روز می کند تا تغییر را مستقیماً منعکس کند.
تیک تاک!
در اینجا کد کامل یک ساعت ساده است:
lang="en">
charset="UTF-8">
name="viewport" content="width=device-width, initial-scale=1.0">
"https://unpkg.com/@matatbread/ai-ui/dist/ai-ui.js">
/* Specify what base tags you reference in your UI */
const { h2, div } = AIUI.tag();
/* Define a _new_ tag type, called `App`, based on the standard "" tag,
that is composed of an h2 and div elements. It will generate markup like:
Hello World
{some content goes here}
*/
const App = div.extended({
constructed() {
// When constructed, this "div" tag contains some other tags
return [
// h2(...) is "tag function". It generates an "h2" DOM element with the specified children
h2("Hello World"),
// div(...) is also "tag function". It generates an "div" DOM element with the specified children
div(clock())
]
}
});
/* Add add it to the document so the user can see it! */
document.body.appendChild(
// App(...) is also a "tag function", just like div()
// and h2(), created by extended() which generates a "div"
// containing the DOM tree returned by constructed().
App({
style:{
color: 'blue'
}
},
'Tick Tock')
);
/* A simple async "sleep" function */
function sleep(seconds) {
return new Promise(resolve => setTimeout(resolve, seconds * 1000))
}
/* The async generator that yields the time once a second */
async function *clock() {
while (true) {
yield new Date().toString();
await sleep(1);
}
}
You can specify attributes, content, children - in fact anything you can insert into a DOM - using native JavaScript async iterators, generators or promises.
Where next?
The above example just demonstrates the first step unleashed by the power of async iterators in UI.
The AI-UI when(...)
function creates iterators from other DOM elements, so you can make one element control another, and the iterable
member of an extended
component allows you to implement "hot" properties in your own components, which can be used to update your components with a simple assignment.
There's a guide on GitHub together with some examples, like this weather chart (open dev tools to see how it works).
The underlying concepts in AI-UI have been used in projects for over a decade, both public and private, with hundreds of thousands of users. After 10 years of refinement, the time is right to share it.
Given AI-UI is new to open source, it'd be great to get your feedback and I'm actively looking for collaborators to help hone the API and set the direction for future developments.
I look forward to seeing your comments or questions here, or on the Github repo.