بهینه سازی اپلیکیشن‌ های انگولار (Angular) — به زبان ساده

۱۹۱ بازدید
آخرین به‌روزرسانی: ۱۱ شهریور ۱۴۰۲
زمان مطالعه: ۶ دقیقه
بهینه سازی اپلیکیشن‌ های انگولار (Angular) — به زبان ساده

انگولار محبوب‌ترین فریمورک برای ساختن وب اپلیکیشن‌های تک‌صفحه‌ای است. با این حال منظور از تک‌صفحه‌ای این نیست که اپلیکیشن شما باید حتماً دارای یک صفحه باشد. می‌توان با استفاده از انگولار وب‌سایت‌هایی با ده‌ها صفحه ساخت. خود فریمورک (جدیدترین نسخه‌ها) به لطف تیم و جامعه خارق‌العاده‌ای که پیرامون آن شکل گرفته بهینه‌سازی زیادی یافته است؛ با این وجود زمانی که در مورد عملکرد انگولار صحبت می‌کنیم، چند نکته وجود دارد که همواره باید رعایت شوند تا اپلیکیشن‌ها سریع‌تر و بهتر اجرا شوند.

997696

در همین راستا در ادامه در مورد بهینه سازی اپلیکیشن‌ های انگولار به صورت مفصل‌تری صحبت خواهیم کرد.

بهینه‌سازی بسته اصلی با Lazy Loading

زمانی که اپلیکیشن در مرحله Production بدون گزینه «بارگذاری با تأخیر» (Lazy Loading) ساخته شود، این احتمال بالا است که این فایل‌ها در پوشه dist ایجاد شوند:

  • polyfills.js
  • scripts.js
  • runtime.js
  • styles.css
  • main.js

polyfills.js برای ساختن اپلیکیشن‌هایی طراحی شده است که با مرورگرهای مختلف سازگاری داشته باشند. چون ما کد خود را با جدیدترین ویژگی‌ها می‌نویسیم و ممکن است همه مرورگرها از برخی از این ویژگی‌ها پشتیبانی نکنند.

scripts.js شامل اسکریپتی است که در بخش اسکریپت‌های فایل angular.json اعلان می‌شود.

1"scripts": [
2   "myScript.js",
3]

runtime.js بارگذار webpack است. این فایل شامل ابزارهای webpack است که برای بارگذاری فایل‌های دیگر مورد نیاز است. Style.css شامل همه استایل‌هایی است که در بخش styles فایل angular.json اعلان می‌شوند.

1"styles": [
2  "src/styles.css",
3  "src/my-custom.css"
4],

main.js همه کدها شامل کامپوننت‌ها (کدهای ts، Html و CSS) همچنین pipe-ها، directive-ها، سرویس‌ها و دیگر ماژول‌های ایمپورت شده از جمله انواع شخص ثالث را در بر می‌گیرد.

همان طور که می‌بینید main.js در طی زمان بزرگ و بزرگ‌تر شده است و این وضعیت خود یک معضل از دید مرورگر است که باید آن را دانلود، تجزیه، اجرا و رندر کند. این وضعیت نه تنها برای کاربران موبایل با سرعت اینترنت محدود؛ بلکه حتی برای کاربران دسکتاپ نیز مشکل عمده‌ای محسوب می‌شود.

ساده‌ترین روش برای حل این مشکل، افراز کردن اپلیکیشن به چند ماژول lazy است. زمانی که از ماژول‌های lazy برای هر ماژول استفاده می‌کنیم، انگولار کد خود را به این منظور ایجاد می‌کند و این کد نیز تا زمانی که نیازی به آن نباشد (معمولاً از طریق یک route مطلع می‌شود) بارگذاری نخواهد شد.

برای نشان دادن این موضوع دو کامپوننت ایجاد کرده‌ایم که یکی app.component و دیگری second.component نام دارد. هر دو آن‌ها در app.madule قرار دارند و از این رو هیچ چیز lazy در اینجا وجود ندارد. App.component بسیار ساده است و دو دکمه برای ناوبری به Second.componen بازگشت به App.component دارد.

optimize Angular applications

با این وجود کامپوننت دوم شامل متن بسیار زیادی (در حدود 1 مگابایت) در قالب خود است.

optimize Angular applications

از آنجا که از هیچ خصوصیت lazy استفاده نشده است زمانی که این اپلیکیشن build شود با یک فایل main.js بزرگ مواجه می‌شویم که شامل همه کد از هر دو فایل app.component و second.component است.

اینک اگر به برگه network در بخش ابزارهای توسعه‌دهنده مرورگر کروم بروید، می‌بینید که main.js بسیار بزرگ است و اندازه‌ای در حدود 1.3 مگابایت دارد.

optimize Angular applications

مشکل این است که در اغلب موارد، کاربران از صفحه اصلی بازدید می‌کنند و نه از یک صفحه خاص و از این رو بارگذاری همه صفحه‌های دیگر راه‌حل مناسبی محسوب نمی‌شود. ما می‌توانیم یک ماژول lazy برای کامپوننت دوم تولید کنیم که تنها در مواقع نیاز فعال شود. یعنی صرفاً زمان‌هایی بارگذاری شود که کاربر به آن صفحه مراجعه می‌کند. بدین ترتیب فایل main.js ما بسیار کوچک‌تر می‌شود و سرعت بارگذاری صفحه اصلی کاهش می‌یابد.

هنگامی که از بارگذاری با تأخیر استفاده می‌کنیم، پس از فرایند buid یک فایل جدید مانند 4.386205799sfghe4.js ایجاد می‌شود. این آن بخشی است که ماژول lazy ساخته است و در آغاز کار بارگذاری نخواهد شد. در ادامه وقتی که اپلیکیشن باز شود، می‌بینیم که main.js بسیار کوچک (266 کیلوبایت) است.

optimize Angular applications

و تنها زمانی که به صفحه دوم برویم فایل جدید (1 مگابایت) بارگذاری می‌شود.

optimize Angular applications

با این وجود بارگذاری هر بخش به این ترتیب روی عملکرد ناوبری نیز تأثیر می‌گذارد، چون کندتر شده است. خوشبختانه انگولار روشی برای حل این مشکل نیز ارائه کرده است که با استفاده از راهکار PreloadingStrategy اجرا می‌شود. ما می‌توانیم به انگولار بگوییم که ماژول اصلی (main.js) ما را بارگذاری کند و وقتی که بارگذاری کامل و اجرا شد، بلافاصله اقدام به بارگذاری ماژول‌های lazy در پس‌زمینه بکند و بدین ترتیب زمانی که کاربران به صفحه‌های lazy می‌روند، همه چیز از قبل دانلود شده است. کد مثال برای پیش-بارگذاری همه ماژول‌ها به صورت زیر است:

1import { PreloadAllModules, RouterModule } from '@angular/router';
2RouterModule.forRoot(
3[
4 {
5    path: 'second',
6    loadChildren: './second/second.module#SecondModule'
7 } 
8], {preloadingStrategy: PreloadAllModules})

بنابراین همواره باید در نظر داشته باشید که تا آنجایی که امکان دارد از ماژول‌های lazy بیشتری با نوعی راهبرد پیش–بارگذاری استفاده کنید. بدین ترتیب فایل main.js شما کوچک می‌ماند و این به آن معنی است که سرعت دانلود افزایش یافته و صفحه اصلی سریع‌تر رندر می‌شود.

دیباگ کردن بسته‌ها با Webpack Bundle Analyzer

حتی اگر پس از افراز منطق اپلیکیشن به ماژول‌های lazy همچنان اندازه‌ی بسته اصلی شما بالا بود، می‌توانید از Webpack Bundle Analyzer برای بهینه‌سازی بیشتر آن استفاده کنید. دقت کنید که منظور ما از اندازه بزرگ، در واقع حجم بالاتر از 1 مگابایت برای اپلیکیشن‌های کوچک رو به متوسط است. این بسته npm امکان بصری‌سازی اندازه فایل‌های خروجی Webpack را با یک نقشه درختی قابل بزرگنمایی تعامل‌پذیر می‌دهد. قبل از هر چیز این افزونه را به عنوان یک وابستگی dev در پروژه انگولار خود نصب کنید:

npm install --save-dev webpack-bundle-analyzer

سپس فایل package.json را با افزودن این خط زیر بخش scripts تغییر دهید:

1"bundle-report": "ng build --prod --stats-json && webpack-bundle-analyzer dist/stats.json"

توجه داشته باشید که dist/stats.json در پروژه شما ممکن است متفاوت باشد. برای نمونه اگر فایل‌های بسته شما در مسیر dist/browser ایجاد شده باشند، می‌توانید دستور را به صورت زیر اصلاح کنید:

dist/browser/stats.json

در نهایت دستور زیر را اجرا کنید:

npm run bundle-report

بدین ترتیب یک build پروداکشن ایجاد می‌شود که آماری در مورد هر بسته ارائه می‌کند و به کمک webpack bundle analyzer می‌توانیم یک بصری‌سازی از فایل‌های خود به صورت یک نقشه درختی قابل بزرگنمایی و تعامل‌پذیر داشته باشیم:

در این نقشه می‌بینیم که کدام ماژول یا فایل‌ها در هر بسته مورد استفاده قرار گرفته‌اند. این وضعیت موجب می‌شود که بتوانیم به سرعت متوجه شویم چه چیزهایی باید در بسته‌ها قرار گیرند یا حذف شوند.

ایجاد چند ماژول مشترک کوچک

داشتن ماژول‌های مشترک با توجه به اصل DRY یعنی «عدم تکرار کد» رویه مناسبی محسوب می‌شود؛ اما در پاره‌ای موارد ماژول مشترک نیز می‌تواند بزرگ و بزرگ‌تر شود. برای نمونه اگر یک SharedModule داشته باشیم که شامل ماژول/کامپوننت/pipe-های زیاد دیگری باشد، ایمپورت کردن آن در app.module موجب افزایش اندازه بسته main.js می‌شود، چون ما نه تنها نیازهای ماژول اصلی را ایمپورت خواهیم کرد؛ بلکه همه موارد غیرضروری دیگر نیز همراه با SharedModule وارد پروژه می‌شوند. برای اجتناب از این وضعیت می‌توان ماژول مشترک دیگری مانند HomeSharedModule ایجاد کرد که صرفاً شامل کامپوننت‌هایی باشد که ماژول اصلی و کامپوننت‌های آن نیاز دارند.

داشتن چندین ماژول مشترک کوچک بهتر از یک ماژول مشترک بزرگ است.

استفاده از بارگذاری با تأخیر برای تصاویری که در صفحه دیده نمی‌شوند

وقتی که صفحه اصلی را برای دفعه نخست بارگذاری می‌کنیم، ممکن است تصاویری داشته باشیم که در دید کاربر نباشند و کاربر باید اسکرول کند تا بتواند این تصاویر را ببیند. با این وجود این تصاویر هم در زمان بارگذاری صفحه دانلود می‌شوند و در صورتی که تعداد آن‌ها زیاد باشد، می‌تواند موجب تأثیر منفی روی عملکرد شود. برای جلوگیری از این مشکل می‌توانیم تصاویر را به صورت lazy بارگذاری بکنیم تا صرفاً زمانی که کاربر به آن‌ها می‌رسد دانلود شوند. یک API جاوا اسکریپت به نام Intersection Observer API وجود دارد که امکان بارگذاری با تأخیر محتوا را به سادگی ارائه می‌کند. به علاوه می‌توانیم یک دایرکتیو برای ایجاد قابلیت استفاده مجدد بسازیم.

استفاده از اسکرول مجازی برای لیست‌های بزرگ

نسخه 7 فریمورک انگولار قابلیت اسکرول مجازی را در CDK ارائه کرده است. اسکرول مجازی عناصر را بر اساس بخش‌های قابل مشاهده یک لیست بارگذاری کرده یا از بارگذاری خارج می‌کند و بدین ترتیب اپلیکیشن بسیار سریع‌تر می‌شود.

به جای بارگذاری و نمایش لیست کامل، می‌توانیم تنها چند آیتم را که هر زمان در دید کاربر هستند نمایش دهیم.
به جای بارگذاری و نمایش لیست کامل، می‌توانیم تنها چند آیتم را در معرض دید کاربر قرار دهیم.

در اغلب وب‌سایت‌ها می‌بینیم که فونت‌های زیبای سفارشی به جای فونت‌های معمول مورد استفاده قرار گرفته‌اند. با این وجود استفاده از فونت‌های سفارشی یا ارائه شده از سوی سرویس‌های دیگر موجب می‌شود که وقتی کاربر از صفحه بازدید می‌کند، مرورگر آن‌ها را دانلود کرده و تجزیه کند. در این زمان اگر از فونت‌های ارائه شده از سوی سرویس‌های شخص ثالث مانند گوگل استفاده کنیم، دو حالت متصور است:

مرورگر منتظر می‌ماند تا دانلود فونت پایان یابد، آن را تجزیه می‌کند و تنها در آن زمان متن صفحه را نمایش می‌دهد. در این وضعیت، متن روی صفحه تا زمانی که فونت دانلود و تجزیه نشده است، قابل مشاهده نخواهد بود. این همان رویکرد FOIT یا Flash of Invisible Text است.
مرورگر در ابتدا متن را با فونت معمول نمایش می‌دهد و تلاش می‌کند تا سبک‌های فونت بیرونی را واکشی کند. زمانی که فونت دانلود و تجزیه شد، فونت جدید به جای فونت قبلی جایگزین می‌شود. متن روی صفحه در این حالت در همان ابتدا با فونت معمولی رندر می‌شود و در عین حال مرورگر شروع به دانلود فونت خارجی می‌کند و زمانی که آن را آماده کرد فونت متن را جایگزین می‌کند. این رویکرد به نام FOUT یا Flash of Unstyled Text شناخته می‌شود.

اغلب مرورگرها از FOIT استفاده می‌کنند و تنها اینترنت اکسپلورر از FOUT استفاده می‌کند. برای حل این مشکل باید از یک descriptor به نام font-display برای @font-face استفاده کنید و به مرورگر بگویید که آیا می‌خواهید از فونت معمول استفاده کنید و سپس آن را جایگزین کنید یا این که متن در ابتدا قابل مشاهده نباشد.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۱ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
itnext
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *