כדי לשפר את ביצועי האפליקציה, אפשר להשתמש בפיצול קוד ברמת המסלול.
בפוסט הזה נסביר איך להגדיר פיצול קוד ברמת המסלול באפליקציה Angular. ההגדרה הזו יכולה להקטין את גודל החבילה של JavaScript ולשפר משמעותית את הזמן עד לפעילות מלאה.
אפשר למצוא את דוגמאות הקוד במאמר הזה ב-GitHub. הדוגמה לניתוב eager זמינה בהסתעפות eager. הדוגמה לפיצול קוד ברמת המסלול נמצאת בהסתעפות מדורגת.
למה חשוב לפצל קוד
המורכבות ההולכת וגדלה של אפליקציות אינטרנט הובילה לעלייה משמעותית בכמות של קוד ה-JavaScript שנשלח למשתמשים. קובצי JavaScript גדולים יכולים לעכב באופן משמעותי את האינטראקטיביות, ולכן הם יכולים להיות משאב יקר, במיוחד בנייד.
הדרך היעילה ביותר לכווץ חבילות JavaScript מבלי לוותר על תכונות באפליקציות היא להפעיל פיצול קוד אגרסיבי.
פיצול קוד מאפשר לחלק את קוד ה-JavaScript של האפליקציה למספר מקטעים שמשויכים לתכונות או למסלולים שונים. הגישה הזו שולחת למשתמשים את ה-JavaScript הדרוש להם רק במהלך הטעינה הראשונית של האפליקציה, תוך שמירה על זמני טעינה קצרים.
טכניקות לפיצול קוד
אפשר לפצל את הקוד בשתי רמות: רמת הרכיב ורמת המסלול.
- בפיצול קוד ברמת הרכיב, מעבירים רכיבים למקטעי JavaScript משלהם וטוענים אותם באופן מדורג כשיש צורך.
- בפיצול קוד ברמת המסלול, כוללים את הפונקציונליות של כל מסלול במקטע נפרד. כשמשתמשים מנווטים באפליקציה, הם מאחזרים את המקטעים שמשויכים למסלולים הספציפיים ומקבלים את הפונקציונליות שמשויכת כשהם צריכים אותה.
הפוסט הזה מתמקד בהגדרה של פיצול ברמת המסלול ב-Agular.
אפליקציה לדוגמה
לפני שנתעמק בפיצול הקוד ברמת המסלול ב-Agular, נבחן אפליקציה לדוגמה:
מומלץ לבדוק את ההטמעה של המודולים של האפליקציה. בתוך AppModule
הוגדרו שני מסלולים: מסלול ברירת המחדל שמשויך אל HomeComponent
ומסלול nyan
שמשויך אל NyanComponent
:
@NgModule({
...
imports: [
BrowserModule,
RouterModule.forRoot([
{
path: '',
component: HomeComponent,
pathMatch: 'full'
},
{
path: 'nyan',
component: NyanComponent
}
])
],
...
})
export class AppModule {}
פיצול קוד ברמת המסלול
כדי להגדיר פיצול קוד, צריך לארגן מחדש את המסלול של nyan
.
גרסה 8.1.0 של Angular CLI יכולה לעשות הכול עם הפקודה הבאה:
ng g module nyan --module app --route nyan
הפעולה הזו תיצור:
- מודול ניתוב חדש בשם NyanModule
- מסלול בAppModule
בשם nyan
שיטען באופן דינמי את NyanModule
- מסלול ברירת מחדל בNyanModule
- רכיב בשם NyanComponent
שיוצג כשהמשתמש יגיע למסלול ברירת המחדל
נבצע את השלבים האלה באופן ידני כדי שנבין טוב יותר את ההטמעה של פיצול קוד באמצעות Angular!
כשהמשתמש מנווט למסלול nyan
, הנתב יעבד את הערך NyanComponent
בשקע החשמל של הנתב.
כדי להשתמש בפיצול קוד ברמת המסלול ב-Agular, צריך להגדיר את המאפיין loadChildren
בהצהרת המסלול ולשלב אותה עם ייבוא דינמי:
{
path: 'nyan',
loadChildren: () => import('./nyan/nyan.module').then(m => m.NyanModule)
}
יש שני הבדלים עיקריים מהמסלול של eager:
- הגדרת
loadChildren
במקוםcomponent
. כשמשתמשים בפיצול קוד ברמת המסלול, צריך להצביע על מודולים שנטענים באופן דינמי, במקום על רכיבים. - ב-
loadChildren
, אחרי שההבטחה תיפתר, תקבלי אתNyanModule
במקום להפנות אלNyanComponent
.
קטע הקוד שלמעלה מציין שכאשר המשתמש מנווט אל nyan
, מערכת Angular צריכה לטעון באופן דינמי את nyan.module
מהספרייה nyan
ולעבד את הרכיב שמשויך למסלול ברירת המחדל שמוצהר במודול.
אפשר לשייך את נתיב ברירת המחדל לרכיב באמצעות ההצהרה הזו:
import { NgModule } from '@angular/core';
import { NyanComponent } from './nyan.component';
import { RouterModule } from '@angular/router';
@NgModule({
declarations: [NyanComponent],
imports: [
RouterModule.forChild([{
path: '',
pathMatch: 'full',
component: NyanComponent
}])
]
})
export class NyanModule {}
הקוד הזה מעובד ל-NyanComponent
כשהמשתמש מנווט אל https://example.com/nyan
.
כדי לבדוק שהנתב Angular מוריד את nyan.module
באופן מדורג בסביבה המקומית:
- מקישים על 'Control+Shift+J' (או על 'Command+Option+J' ב-Mac) כדי לפתוח את כלי הפיתוח.
לוחצים על הכרטיסייה רשתות.
לוחצים על NYAN באפליקציה לדוגמה.
חשוב לזכור שהקובץ
nyan-nyan-module.js
מופיע בכרטיסייה 'רשת'.
אפשר לראות את הדוגמה הזו ב-GitHub.
הצגת סימן גרפי שפעולה מתבצעת
כרגע, כשהמשתמש לוחץ על הלחצן NYAN, האפליקציה לא מציינת שהיא טוענת את JavaScript ברקע. מומלץ להוסיף סימן גרפי שפעולה מתבצעת כדי לתת למשתמש משוב בזמן טעינת הסקריפט.
לשם כך, צריך קודם להוסיף תגי עיצוב למחוון בתוך הרכיב router-outlet
ב-app.component.html
:
<router-outlet>
<span class="loader" *ngIf="loading"></span>
</router-outlet>
לאחר מכן צריך להוסיף מחלקה AppComponent
כדי לטפל באירועי ניתוב. הכיתה loading
תגדיר את הדגל true
כשהיא תזהה את האירוע RouteConfigLoadStart
, ותגדיר את הדגל ל-false
כשהוא ישמע את האירוע RouteConfigLoadEnd
.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
loading: boolean;
constructor(router: Router) {
this.loading = false;
router.events.subscribe(
(event: RouterEvent): void => {
if (event instanceof NavigationStart) {
this.loading = true;
} else if (event instanceof NavigationEnd) {
this.loading = false;
}
}
);
}
}
בדוגמה הבאה הצגנו זמן אחזור מלאכותי של 500 אלפיות השנייה, כך שתוכל לראות את הבועה בפעולה.
סיכום
כדי לכווץ את גודל החבילה של אפליקציות ב-Agular, אפשר להחיל פיצול קוד ברמת המסלול:
- שימוש במחולל המודולים עם טעינה מדורגת של Angular CLI כדי לאסוף באופן אוטומטי מסלול שנטען באופן דינמי.
- אפשר להוסיף אינדיקטור לטעינה כשהמשתמש מנווט למסלול איטי כדי להראות שיש פעולה מתמשכת.