راز سرعت Linear: چرا این اپ مثل یه برنامه نیتیو حس میده؟
خلاصهٔ کاملتر
Linear یه ایشو رو در چند میلیثانیه آپدیت میکنه، در حالی که یه CRUD معمولی همین کار رو ۳۰۰ میلیثانیه طول میکشه. اما چطور؟ نه با یه ترفند جادویی، بلکه با یه سری تصمیم معماری که از روز اول کنار هم چیده شدن.
دیتابیس داخل مرورگر مهمترین قطعه پازل Linearه. به جای اینکه UI منتظر جواب سرور بمونه، دادهها مستقیم از IndexedDB (دیتابیس داخلی مرورگر) خونده میشن. وقتی کاربر یه تغییر میده، UI فوراً آپدیت میشه و تراکنش در پسزمینه به سرور فرستاده میشه. اسپینری وجود نداره چون چیزی نیست که منتظرش بمونی.
تفاوت رویکرد سنتی و Linear رو میشه در این کد دید:
// یه اپ معمولی — منتظر سرور میمونه
async function updateIssue({ issue }) {
showSpinner();
const response = await fetch(`/api/issues/${issue.id}`, {
method: "PATCH",
body: JSON.stringify({ title: issue.title }),
});
const updated = await response.json();
setIssue(updated)
hideSpinner();
}
// vs Linear — آپدیت فوری، سینک در پسزمینه
issue.title = "Faster app launch";
issue.save();خط اول یه observable از MobX رو آپدیت میکنه و UI بلافاصله ریرندر میشه. خط دوم یه تراکنش رو در صف میذاره که sync engine بعداً به سرور میفرسته. برای اپهایی که نمیخوان این معماری رو از صفر بسازن، کتابخونههایی مثل TanStack Query یا SWR با قابلیت optimistic update میتونن به نتیجه نزدیکی برسن.
اولین بارگذاری سریع هم به همین اندازه مهمه. Linear چهار بار bundler عوض کرده — از Parcel به Rollup، بعد Vite، و حالا Rolldown — و هر بار هدف کاهش حجم JavaScript و CSS بوده. نتیجه: ۵۰٪ کد کمتر، ۳۰٪ کوچکتر بعد از فشردهسازی، و بارگذاری اولیه ۱۰ تا ۳۰٪ سریعتر. مهمترین تصمیم: هدفگیری فقط مرورگرهای مدرن، بدون polyfill و بدون تبدیل به ES5. در کنار این، کد به صدها chunk کوچک تقسیم (code splitting) شده که فقط وقتی نیاز هست لود میشن.
با وجود code splitting، مشکل جدیدی پیش میاد: مرورگر تا زمانی که script اصلی رو parse نکنه نمیدونه چه chunkهایی باید لود بشن و این باعث یه آبشار از درخواستهای متوالی میشه. Linear این مشکل رو با modulepreload حل میکنه — لیست کامل chunkهای مهم رو در قرار میده تا مرورگر همه رو بهصورت موازی و قبل از اجرای هر کدی دانلود کنه.
Service Worker هم بقیه اپ رو کش میکنه. حدود ۱۲۰۰ فایل هشدار (chunkهای مسیرها، آیکونها، فونتها) بعد از اولین لود در پسزمینه کش میشن. از بار بعد، مرورگر به جای شبکه مستقیم از کش جواب میده. ترکیب این با sync engine محلی یه چیز جالب میسازه: Linear آفلاین هم کار میکنه — میشه ایشو خوند، ساخت، ویرایش کرد، و همه چیز تا وقتی اتصال برگرده در صف میمونه.
نکات کلیدی:
- دیتابیس داخل مرورگر (IndexedDB) + sync engine اصلیترین راز سرعت Linearه
- UI بلافاصله آپدیت میشه؛ درخواست شبکه در پسزمینه انجام میشه (optimistic update)
- code splitting شدید + هدفگیری فقط مرورگرهای مدرن حجم JS رو نصف کرده
- modulepreload آبشار درخواستها رو به یه بچ موازی تبدیل میکنه
- Service Worker کل اپ رو کش میکنه و امکان استفاده آفلاین رو میده
- stack سادهست: React، TypeScript، MobX، Postgres — بدون React Server Components یا edge database




