یک کامپایلر build-time برای UI واکنشپذیر دانهریز — بدون virtual DOM، بدون dependency.
کد تو جاوااسکریپت استاندارد است: signal بههمراه templateهای
html. بدون هیچ build در مرورگر اجرا میشود — کامپایلر یک
بهینهساز است، نه یک الزام.
// همین فایل، بدون build، در مرورگر اجرا میشود import { signal, computed, html, mount } from 'amojs'; function Counter() { const count = signal(0); const double = computed(() => count.value * 2); return html` <button onclick=${() => count.value++}> ${count} × 2 = ${double} </button>`; } mount(Counter, document.body);
هر template یک بار پارس میشود و هر نمونه با cloneNode ساخته میشود. هر hole دینامیک به یک effect کوچک وصل است — یک binding عوض شود، دقیقاً یک expression دوباره ارزیابی میشود. چیزی diff نمیشود، چون چیزی برای مقایسه وجود ندارد.
amo eject جاوااسکریپت خوانا بیرون میدهد و همهی importها را به مسیر نسبی بازنویسی میکند. تست eject خروجی را اجرا میکند و ثابت میکند هیچ specifierی به node_modules نمیرسد. یعنی حذف AmoJS واقعاً هیچ چیزی را عوض نمیکند.
هر تست golden یک fixture را دو بار اجرا میکند — یک بار خام، یک بار کامپایلشده — و رفتار باید یکی باشد. کامپایلر حق ندارد پیادهسازی دومی با تفاوتهای نامحسوس باشد.
فایل تو همین حالا اجرا میشود. یعنی hover و go-to-definition و rename و type-check، همه از امروز کار میکنند — بدون افزونه، بدون language server.
هر عدد یک gate در CI است، نه یک ادعا.
اپ counter کامپایلشده، بههمراه runtime، minify و gzip
حجم خروجی کامپایلر تقسیم بر vanilla دستنویس — identity benchmark
اندازهی Lit برای همان اپ، در کوچکترین حالت خودش
وقتی یکی از پنج binding عوض میشود: AmoJS یک expression ارزیابی میکند، Lit پنج تا
اینها تصمیمهای بستهاند، نه سؤالهای باز:
addEventListener روی خودِ element جواب است.amo build ساخته میشود — دقیقاً همان کامپایلری که
توضیحش را میدهد. هر بخش باید یک نمونهی زنده و قابلدستکاری باشد، نه متن:
صفحهی each باید شمارندهی render را نشان بدهد که تکان نمیخورد،
نه اینکه ادعا کند nodeها جابهجا میشوند.