
مساء الخير أيها الزملاء. نحن ندرس ما إذا كان سيتم تحديث الكتاب بواسطة Jacob Fine و Anton Moiseev "
Angular و TypeScript. إنشاء موقع ويب للمحترفين ".
تظهر طبعة جديدة في خريف هذا العام وتتضمن مادة على الزاوي 5 و 6.
فكرنا في البداية في نشر مواد حول محرك Ivy ، والتي من المحتمل أن تكون أكثر ابتكارات مثيرة للاهتمام في Angular 6 ، ولكن بعد ذلك توقفنا عن نشر أكثر نظرة عامة من Cedric Exbright (تم إصدار الأصل في مايو).
في Angular 6 ، كان هناك الكثير من الابتكارات الجادة ، علاوة على ذلك ، أهمها لا يمكنك تسمية الميزات: هذا هو Ivy ، وهو محرك عرض جديد. نظرًا لأن المحرك لا يزال تجريبيًا ، فسنتحدث عنه في نهاية هذه المقالة ، وسنبدأ بميزات جديدة أخرى وتغييرات ثورية.
مزودي الأشجار المهتزةالآن هناك طريقة جديدة موصى بها لتسجيل الموفر مباشرة في الديكور
@Injectable()
، وذلك باستخدام السمة الجديدة
providedIn
. تأخذ
'root'
كقيمة أي وحدة نمطية في تطبيقك. عند استخدام
'root'
سيتم تسجيل الكائن الذي تم تنفيذه في التطبيق باعتباره وحيدًا ، ولن تحتاج إلى إضافته إلى المزودين في وحدة الجذر. وبالمثل ، عند استخدام
providedIn: UsersModule
يتم تسجيل الكائن الذي تم
UsersModule
كموفر
UsersModule
، ولا تتم إضافته إلى موفري الوحدة النمطية.
@Injectable({ providedIn: 'root' }) export class UserService { }
تم تقديم هذه الطريقة الجديدة لإزالة التعليمات البرمجية غير الوظيفية بشكل أفضل في التطبيق (اهتزاز الشجرة). في الوقت الحاضر ، الوضع هو أن الخدمة التي تتم إضافتها إلى موفري الوحدة ستنتهي في المجموعة النهائية ، حتى إذا لم يتم استخدامها في التطبيق - والسماح بذلك أمر محزن قليلاً. إذا كنت تستخدم التحميل البطيء ، يمكنك الوقوع في عدة مصائد في وقت واحد ، أو تجد نفسك في موقف حيث سيتم إدخال الخدمة في مجموعة خاطئة.
من غير المرجح أن يحدث مثل هذا الموقف في التطبيقات في كثير من الأحيان (إذا كتبت خدمة ، ثم استخدمها) ، لكن وحدات الجهات الخارجية تقدم أحيانًا خدمات لا نحتاجها - ونتيجة لذلك ، لدينا مجموعة كاملة من JavaScript عديمة الفائدة.
لذلك ، ستكون هذه الميزة مفيدة بشكل خاص لمطوري المكتبات ، ولكن يُنصح الآن بتسجيل الكائنات التي تم تنفيذها بهذه الطريقة - وهذا ينطبق أيضًا على مطوري التطبيقات. حتى أن CLI الجديدة تستخدم الآن السقالات
providedIn: 'root'
بشكل افتراضي عند العمل مع الخدمات.
على نفس المنوال ، يمكنك الآن الإعلان عن ميزة
InjectionToken
وتسجيلها مباشرة مع
providedIn
وإضافة
factory
هنا:
export const baseUrl = new InjectionToken<string>('baseUrl', { providedIn: 'root', factory: () => 'http://localhost:8080/' });
يرجى ملاحظة: هذا يبسط أيضًا اختبار الوحدة. لأغراض مثل هذا الاختبار ، يتم استخدامها لتسجيل الخدمة مع موفري وحدة الاختبار. إليك ما فعلناه من قبل:
beforeEach(() => TestBed.configureTestingModule({ providers: [UserService] }));
الآن ، إذا كانت UserService تستخدم في
providedIn: 'root'
:
beforeEach(() => TestBed.configureTestingModule({}));
فقط لا تقلق: جميع الخدمات المسجلة في
providedIn
لم يتم تحميلها في الاختبار ، ولكن يتم نسخها بتكاسل ، فقط في الحالات التي تكون فيها هناك حاجة إليها حقًا.
Rxjs 6يستخدم Angular 6 الآن RxJS 6 داخليًا ، لذلك تحتاج إلى تحديث التطبيق مع وضع ذلك في الاعتبار.
و ... RxJS 6 يغير نهج الاستيراد!
في RxJS 5 ، يمكنك كتابة:
import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/of'; import 'rxjs/add/operator/map'; const squares$: Observable<number> = Observable.of(1, 2) .map(n => n * n);
في RxJS 5.5 ، ظهرت كشوف الأنابيب:
import { Observable } from 'rxjs/Observable'; import { of } from 'rxjs/observable/of'; import { map } from 'rxjs/operators'; const squares$: Observable<number> = of(1, 2).pipe( map(n => n * n) );
وفي RxJS 6.0 ، تغيرت الواردات:
import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; const squares$: Observable<number> = of(1, 2).pipe( map(n => n * n) );
لذا ، سيتعين عليك يومًا ما تغيير عمليات الاستيراد داخل التطبيق بالكامل. أكتب "مرة واحدة" وليس "الآن" ، لأن مكتبة rxJs المتوافقة تم إصدارها في RxJS ، مما يسمح بتنزيل RxJS إلى الإصدار 6.0 ، حتى إذا كانت الإصدارات القديمة لا تزال مستخدمة في تطبيقك بالكامل أو في إحدى المكتبات المستخدمة بناء الجملة.
لقد كتب فريق Angular
مستندًا كاملاً حول هذا الموضوع ، ومن الضروري تمامًا قراءته قبل الانتقال إلى Angular 6.0.
يرجى ملاحظة: هنا مجموعة قواعد tslint رائعة جدًا تسمى
rxjs-tslint
. هناك 4 قواعد فقط ، وإذا قمت بإضافتها إلى المشروع ، فسيقوم النظام تلقائيًا بترحيل جميع عمليات الاستيراد ورمز RxJS ، ويتم ذلك عن طريق أبسط
tslint --fix
! بعد كل شيء ، إذا كنت لا تزال لا تعرف ، في
tslint
هناك خيار
fix
تلقائيًا على إصلاح جميع الأخطاء التي يجدها! يمكن استخدامه بشكل أكثر بساطة: تثبيت
rxjs-tslint
وتشغيل
rxjs-5-to-6-migrate -p src/tsconfig.app.json
. لقد جربت
rxjs-tslint
في أحد مشاريعنا وعملت بشكل جيد (قم بتشغيله مرتين على الأقل لطي جميع الواردات). تحقق من قراءة هذا المشروع لمزيد من التفاصيل:
github.com/ReactiveX/rxjs-tslint .
إذا كنت مهتمًا بمعرفة المزيد حول RxJS 6.0 ، فإنني أوصي
بتقرير Ben Lesch
التالي حول ng-conf.
i18nأهم احتمال يتعلق بـ i18n هو القدرة على إنشاء "i18n في وقت التشغيل" ، دون الحاجة إلى إنشاء التطبيق بشكل منفصل لكل نقطة محلية. هذه الميزة غير متاحة حتى الآن (هناك نماذج أولية فقط) ، وستكون هناك حاجة إلى محرك Ivy لتشغيلها (المزيد عن ذلك أدناه).
تم بالفعل إجراء تغيير آخر متعلق بـ i18n وهو متاح. تم تحسين قناة العملات بالطريقة الأكثر كفاءة: الآن تقوم بتقريب جميع العملات ليس إلى رقمين ، كما كان من قبل ، ولكن إلى العدد المطلوب من الأرقام (على سبيل المثال ، إلى 3 في حالة الدينار البحريني أو إلى 0 للبيزو التشيلي).
إذا لزم الأمر ، يمكن استرداد هذه القيمة بشكل برمجي باستخدام وظيفة i18n
getNumberOfCurrencyDigits
الجديدة.
ظهرت أيضًا وظائف تنسيق ملائمة أخرى ، مثل
formatDate
و
formatCurrency
و
formatPercent
و
formatNumber
في
formatNumber
formatPercent
.
بشكل ملائم ، إذا كنت ترغب في تطبيق نفس التحويلات التي تتم في القنوات ، ولكن قم بذلك من كود TypeScript.
الرسوم المتحركةفي Angular 6.0 ، تكون الرسوم المتحركة ممكنة بالفعل بدون polyfill
web-animations-js
، إلا إذا كنت تستخدم
AnimationBuilder
. يمكن للتطبيق الخاص بك الفوز ببعض البايتات الثمينة! في حالة عدم دعم المستعرض لواجهة برمجة التطبيقات
element.animate
، يتراجع Angular 6.0 إلى استخدام الإطارات الأساسية CSS.
العناصر الزاويةAngular Elements هو مشروع يسمح لك بلف مكونات Angular كمكونات ويب وتضمينها في تطبيق لا يستخدم Angular. في البداية ، كان هذا المشروع موجودًا فقط في "Angular Lab" (أي أنه لا يزال تجريبيًا). مع الإصدار 6 ، يأتي في المقدمة قليلاً ويتم تضمينه رسميًا في الإطار. هذا موضوع كبير يستحق مقالة منفصلة.
ElementRef <T>إذا كنت تريد أن تأخذ ارتباط عنصر في القالب الخاص بك ، يمكنك استخدام
@ViewChild
أو
@ViewChildren
، أو حتى تنفيذ
ElementRef
مباشرة. العيب في هذه الحالة هو: في Angular 5.0 أو أقل ، سيحصل
ElementRef
المحدد على النوع
any
لخاصية
nativeElement
.
في Angular 6.0 يمكنك كتابة ElementRef أكثر صرامة إذا كنت ترغب في:
@ViewChild('loginInput') loginInput: ElementRef<HTMLInputElement>; ngAfterViewInit() {
ما هو معترف به على أنه غير مرغوب فيه وما يتغير بشكل أساسيلنتحدث عما يجب عليك أخذه في الاعتبار عند الشروع في الهجرة!
preserveWhitespaces
: false
افتراضيفي قسم "المشاكل التي قد تحدث أثناء الترقية" ، نلاحظ أن preserveWhitespaces أصبح الآن
false
بشكل افتراضي. ظهر هذا الخيار في Angular 4.4 ، وإذا كنت تتساءل عما يمكن توقعه في نفس الوقت - إليك
منشور كامل حول هذا الموضوع. المفسد: كل شيء يمكن أن يفعله ، أو يمكن أن يكسر قوالبك تمامًا.
ngModel
والأشكال التفاعليةفي السابق ، كان من الممكن توفير نفس حقل النموذج مع
ngModel
و
formControl
، ولكن اليوم تعتبر هذه الممارسة غير مرغوب فيها ولن يتم دعمها بعد الآن في Angular 7.0.
هناك القليل من الارتباك هنا ، وقد عملت الآلية بأكملها ، ربما ليس كما توقعت (
ngModel
- كان هذا توجيهًا غير مألوف لك منذ فترة طويلة ، ولكن إدخال / إخراج توجيه
formControl
، والذي يؤدي نفس المهمة تقريبًا ، ولكن ليس متطابقًا).
حتى الآن ، إذا طبقنا الرمز:
<input [(ngModel)]="user.name" [formControl]="nameCtrl">
ثم نحصل على تحذير.
يمكنك تكوين التطبيق لعرض تحذير
always
(
once
) ،
once
(مرة واحدة) أو
never
(مطلقًا). الافتراضي هو
always
.
imports: [ ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }); ]
بطريقة أو بأخرى ، للتحضير للانتقال إلى Angular 7 ، تحتاج إلى تكييف الشفرة لاستخدام إما النماذج الموجهة للقالب أو النماذج التفاعلية.
مشروع اللبلاب: محرك عرض جديد (جديد) في Angularسووو ... هذا هو الإصدار الرئيسي الرابع (2 ، 4 ، 5 ، 6) ، ويتم إعادة كتابة محرك التقديم للمرة الثالثة!
تذكر: تقوم Angular بتجميع القوالب الخاصة بك في كود TypeScript مكافئ. ثم يتم تجميع TypeScript هذا مع TypeScript الذي كتبته في JavaScript ، وتكون النتيجة تحت تصرف المستخدم. وقبلنا بالفعل الإصدار الثالث من محرك العرض هذا في Angular (الأول كان في الإصدار الأولي لـ Angular 2.0 ، والثاني في Angular 4.0).
في هذا الإصدار الجديد من محرك التقديم ، لا يتغير نهج كتابة القوالب ، ومع ذلك ، فإنه يحسن عددًا من المؤشرات ، على وجه الخصوص:
كل هذا لا يزال تجريبيًا بعمق ، ويتم تشغيل محرك عرض Ivy الجديد بواسطة مربع اختيار ، والذي يجب عليك وضعه في خيارات المترجم (في ملف
tsconfig.json
) إذا كنت ترغب في تجربته.
"angularCompilerOptions": { "enableIvy": true }
يرجى ملاحظة أن هذه الآلية ربما لا تكون موثوقة للغاية ، لذلك لا تستخدمها في الإنتاج حتى الآن. ربما لا يزال لا يعمل. ولكن في المستقبل القريب سيتم قبوله كخيار افتراضي ، لذلك يجب أن تجربه مرة واحدة ، ومعرفة ما إذا كان يعمل في تطبيقك ، وما الذي تستفيد منه.
دعونا نناقش بمزيد من التفصيل كيف يختلف Ivy عن محرك العرض القديم.
الرمز الذي تم إنشاؤه بواسطة المحرك القديمدعنا
PonyComponent
على مثال صغير:
PonyComponent
مكون
PonyComponent
يأخذ نموذج
PonyModel
(مع معلمات
name
color
) ويعرض صورة المهر (اعتمادًا على البدلة) ، بالإضافة إلى اسم المهر.
يبدو هذا:
@Component({ selector: 'ns-pony', template: `<div> <ns-image [src]="getPonyImageUrl()"></ns-image> <div></div> </div>` }) export class PonyComponent { @Input() ponyModel: PonyModel; getPonyImageUrl() { return `images/${this.ponyModel.color}.png`; } }
ngfactory
محرك العرض المقدم في Angular 4 فئة تسمى
ngfactory
لكل قالب. احتوى الفصل عادة (كود مبسط):
export function View_PonyComponent_0() { return viewDef(0, [ elementDef(0, 0, null, null, 4, "div"), elementDef(1, 0, null, null, 1, "ns-image", View_ImageComponent_0), directiveDef(2, 49152, null, 0, i2.ImageComponent, { src: [0, "src"] }), elementDef(3, 0, null, null, 1, "div"), elementDef(4, null, ["", ""]) ], function (check, view) { var component = view.component; var currVal_0 = component.getPonyImageUrl(); check(view, 2, 0, currVal_0); }, function (check, view) { var component = view.component; var currVal_1 = component.ponyModel.name; check(view, 4, 0, currVal_1); }); }
من الصعب قراءتها ، ولكن الأجزاء الرئيسية من هذا الرمز موصوفة كما يلي:
- هيكل DOM الذي تم إنشاؤه ، والذي يحتوي على تعريفات العناصر (
figure
، img
، figcaption
) ، سماتها وتعاريف العقد النصية. يتم تمثيل كل عنصر من عناصر بنية DOM في صفيف تعريفات العرض بواسطة الفهرس الخاص به. - تغيير وظائف الكشف ؛ يتحقق الرمز الموجود فيها لمعرفة ما إذا كانت التعبيرات المستخدمة في القالب تؤدي إلى نفس القيم كما كانت من قبل. هنا ، يتم
getPonyImageUrl
نتيجة طريقة getPonyImageUrl
، وإذا تغيرت ، يتم تحديث قيمة الإدخال لمكون الصورة. وينطبق الشيء نفسه على لقب المهر: إذا تغير ، سيتم تحديث عقدة النص التي تحتوي على هذا اللقب.
ولدت كود اللبلابإذا عملنا مع Angular 6 ، وتم
enableIvy
علامة
enableIvy
على
true
، فلن يتم إنشاء
ngfactory
منفصل في نفس المثال ؛ سيتم تضمين المعلومات مباشرةً في الحقل الثابت للمكون نفسه (رمز مبسط):
export class PonyComponent { static ngComponentDef = defineComponent({ type: PonyComponent, selector: [['ns-pony']], factory: () => new PonyComponent(), template: (renderFlag, component) { if (renderFlag & RenderFlags.Create) { elementStart(0, 'figure'); elementStart(1, 'ns-image'); elementEnd(); elementStart(2, 'div'); text(3); elementEnd(); elementEnd(); } if (renderFlag & RenderFlags.Update) { property(1, 'src', component.getPonyImageUrl()); text(3, interpolate('', component.ponyModel.name, '')); } }, inputs: { ponyModel: 'ponyModel' }, directives: () => [ImageComponent]; });
الآن كل شيء موجود في هذا المجال الثابت. تحتوي سمة
template
على ما يعادل
ngfactory
المألوف ، مع بنية مختلفة قليلاً. سيتم تشغيل وظيفة
template
، كما كان من قبل ، عند أي تغيير ، ولكن الآن لديها وضعين:
- وضع الإنشاء: المكون يتم إنشاؤه للتو ، ويحتوي على عقد DOM الثابتة التي يجب إنشاؤها
- يتم تنفيذ باقي الوظيفة مع كل تغيير (إذا لزم الأمر ، يتم تحديث مصدر الصورة وعقدة النص).
ماذا تغير ذلك؟الآن يتم
@Injectable
جميع الديكورات مباشرة في فصولهم (نفس الشيء بالنسبة لـ
@Injectable
و
@Pipe
و
@Directive
) ،
@Directive
، ما عليك سوى معرفة الديكور الحالي. أطلق فريق Angular على هذه الظاهرة اسم "مبدأ المنطقة": لإعادة تجميع المكون ، لا تحتاج إلى إعادة تحليل التطبيق.
يتم تقليل الرمز الذي تم إنشاؤه بشكل طفيف ، ولكن الأهم من ذلك ، أنه من الممكن التخلص من عدد من التبعيات ، وبالتالي تسريع إعادة التجميع إذا تغير أحد أجزاء التطبيق. بالإضافة إلى ذلك ، مع جامعي الحديث ، على سبيل المثال ، Webpack ، يتبين أن كل شيء أجمل بكثير: يتم قطع الرمز غير الفعال بأمان ، تلك الأجزاء من الإطار التي لا تستخدمها. على سبيل المثال ، إذا لم يكن لديك قنوات في التطبيق ، فلن يتم تضمين الإطار المطلوب لتفسيرها في المجموعة النهائية.
لقد اعتدنا على جعل الكود الزاوي ثقيلًا. في بعض الأحيان لا يكون الأمر مخيفًا ، لكن Hello World تزن 37 كيلوبايت بعد التصغير والضغط كثيرًا. عندما تكون Ivy مسؤولة عن إنشاء الرمز ، يتم قطع الرمز غير الفعال بشكل أكثر فاعلية. الآن Hello World بعد ضغط التصغير إلى 7.3 كيلو بايت ، وبعد الضغط - فقط إلى 2.7 كيلو بايت ، وهذا فرق كبير. تطبيق TodoMVC بعد الضغط - 12.2 كيلو بايت فقط. هذه بيانات من فريق Angular ، ولم يتمكن الآخرون من العمل معنا ، نظرًا لأن Ivy للعمل كما هو موضح هنا ، لا تزال بحاجة إلى تصحيحه يدويًا.
لمزيد من التفاصيل ، راجع هذا
الحديث مع ng-conf.
التوافق مع المكتبات الموجودةقد تكون مهتمًا بما يلي: ماذا سيحدث للمكتبات التي تم نشرها بالفعل بالتنسيق القديم إذا تم استخدام Ivy في مشروعك؟ لا تقلق: سيقوم المحرك بعمل نسخة متوافقة مع Ivy من تبعيات مشروعك ، حتى لو تم تجميعها بدون Ivy. لن أفضح الداخل الآن ، ولكن يجب أن تكون جميع التفاصيل شفافة.
الميزات الجديدةدعونا نفكر في الفرص الجديدة التي سنحصل عليها عند العمل مع محرك العرض هذا.
الخصائص الخاصة في القوالبيضيف محرك جديد ميزة جديدة أو تغيير محتمل.
يرتبط هذا الموقف ارتباطًا مباشرًا بحقيقة أن وظيفة القالب مضمنة في المجال الثابت للمكون: الآن يمكننا استخدام الخصائص الخاصة لمكوناتنا في القوالب. كان هذا مستحيلًا في السابق ، حيث اضطررنا إلى إبقاء جميع حقول وأساليب المكون المستخدم في القالب علنية ، وقد وقعوا في فئة منفصلة (
ngfactory
). عند الوصول إلى خاصية خاصة من فئة أخرى ، سيفشل تجميع TypeScript. الآن هو في الماضي: نظرًا لأن وظيفة القالب في حقل ثابت ، يمكنها الوصول إلى الخصائص الخاصة للمكون.
لقد رأيت تعليقًا من أعضاء فريق Angular حول حقيقة أنه لا يُنصح باستخدام الخصائص الخاصة في النماذج ، على الرغم من أن هذا ممكن الآن - نظرًا لأنه قد يكون محظورًا مرة أخرى في المستقبل ... وبالتالي ، فمن الأفضل أن تستمر في استخدام الحقول العامة فقط في النماذج! على أي حال ، أصبحت اختبارات وحدة الكتابة أسهل الآن ، لأن الاختبار يمكن أن يتحقق من حالة المكون دون حتى إنشاء DOM والتحقق منه.
i18n في وقت التشغيليرجى ملاحظة: يفتح محرك العرض الجديد أخيرًا فرصة طال انتظارها لنا ويعطي "i18n في وقت التشغيل". في وقت كتابة هذا التقرير ، كانت لا تزال غير مستعدة تمامًا ، لكننا رأينا العديد من الالتزامات في وقت واحد ، وهذه علامة جيدة!
الشيء الرائع هو أنك لست مضطرًا إلى تغيير تطبيقك كثيرًا إذا كنت تعمل بالفعل مع i18n. ولكن الآن لا تحتاج إلى إعادة إنشاء التطبيق لكل لغة تخطط لدعمها - ما عليك سوى تحميل JSON مع ترجمات لكل لغة ، وستتولى Angular الباقي!
مكتبات AoTفي الوقت الحالي ، يجب أن تنشر مكتبة تم إصدارها في NPM ملف metadata.json ولا يمكنها نشر كود AoT لمكوناته. هذا أمر محزن ، حيث يتم تمرير التكاليف المرتبطة بمثل هذا التجميع إلى تطبيقنا. مع Ivy ، ليست هناك حاجة لملف البيانات الوصفية ، وسوف يتمكن مؤلفو المكتبة الآن من نشر كود AoT الخاص بهم مباشرة إلى NPM!
مسارات مكدسة محسنةالآن يجب أن تعطي الشفرة التي تم إنشاؤها آثار مكدسات محسنة ، إذا واجهت مشكلة في القوالب الخاصة بك - ينتج عن ذلك خطأ واضح يشير إلى سطر القالب الذي حدث فيه. يمكنك أيضًا تعيين نقاط توقف في القوالب وتتبع ما يحدث حقًا في Angular.
NgModule
سيختفي NgModule
؟لا يزال هذا احتمالًا بعيدًا ، ولكن ربما في المستقبل سيكون من الممكن الاستغناء عن NgModules. العلامات الأولى لمثل هذه التغييرات هي مزودو الأشجار المهتزون ، ومن المنطقي أن نفترض أن Ivy لديها جميع الكتل الأساسية الضرورية لأولئك الذين هم على استعداد للتخلي عن NgModules تدريجيًا (أو ، على الأقل ، جعلها أقل استجابة). صحيح ، كل هذا لا يزال في المستقبل ، سنكون صبورين.
لن يكون هناك العديد من الميزات الجديدة في هذا الإصدار ، لكن Ivy بالتأكيد مثيرة للاهتمام للمستقبل. جربها - أتساءل كيف ستحبها!