AngularJSからAngularぞの移行芁玠を転送するための目暙、蚈画、芏則1/3


1月、Skyengでは、VimboxプラットフォヌムのAngularJSからAngular 4ぞの移行を完了したした。準備ず移行䞭に、蚈画、問題解決、新しい䜜業芏則に関する倚くのメモを蓄積し、Habréに関する3぀の蚘事で共有するこずにしたした。 私たちのメモが、動き始めたばかりのVimboxプロゞェクトず構造的に類䌌した有甚なものになるこずを願っおいたす。


なぜこれが必芁なのですか


たず、Angularはすべおにおいお、AngularJSよりも優れおいたす。より速く、簡単で、䟿利で、バグが少ないですたずえば、テンプレヌトを入力するず、それらず戊うのに圹立ちたす。 これに぀いお倚くのこずが述べられ、曞かれおいたすが、繰り返すこずには意味がありたせん。 これはAngular 2でも理解できたしたが、1幎前に移行を開始するのは怖かったですGoogleが埌方互換性なしで次のバヌゞョンですべおを逆さたにするこずを決定したらどうなるでしょうか 私たちには倧きなプロゞェクトがあり、本質的に新しいフレヌムワヌクぞの移行には深刻なリ゜ヌスが必芁であり、2幎ごずにそれをしたくありたせん。 Angular 4では、これ以䞊革呜が起こらないこずを期埅できたす。぀たり、移行の時が来たずいうこずです。


次に、プラットフォヌムで䜿甚されおいるテクノロゞヌを曎新したかった。 「䜕かが壊れおいない堎合は修埩しない」ずいう原則に埓っおこれが行われない堎合、ある時点で、プラットフォヌムがれロから曞き盎された堎合にのみそれ以䞊の進歩が可胜な境界を越えたす。 遅かれ早かれ、いずれにせよ、Angularに切り替える必芁がありたすが、これを早めるほど、移行は安くなりたすコヌドの量は垞に増加しおおり、新しいテクノロゞの利点をより早く埗るこずができたす。


最埌に、3番目の重芁な理由開発者。 AngularJS-合栌したステヌゞ。タスクを実行したすが、開発は行われず、開発もされたせん。 プラットフォヌムは垞に成長しおいたす。 匷力な開発者で構成される倧芏暡なチヌムは存圚せず、匷力な開発者は垞に新しいテクノロゞヌに関心があり、単に時代遅れのフレヌムワヌクに察凊するこずに興味はありたせん。 Angularに切り替えるず、優秀な候補者にずっお欠員がより面癜くなりたす。 次の2〜3幎で、それらは非垞に重芁になりたす。


どのように進めたすか


移行はパラレルモヌドで実行できたす。プラットフォヌムはAngularJSで実行され、最初から蚘述しお新しいバヌゞョンをテストし、ある時点でトグルスむッチを切り替えるだけです。 2番目のオプションは、AngularJSずAngularの䞡方が同時に機胜するプロダクションで盎接倉曎が発生する堎合のハむブリッドモヌドです。 幞いなこずに、このモヌドはよく考えられ、 文曞化されおいたす 。


ハむブリッド移行モヌドずパラレル移行モヌドの遞択は、補品の開発状況によっお異なりたす。 アクションプランを準備しおいた開発者は、別の䌚瀟で䞊列アプロヌチの経隓がありたしたが、その堎合、䟝存関係は少なくコヌドはほが同じでしたが、最も重芁なこずに、1か月間すべおの開発を停止し、移行のみを凊理する機䌚がありたした。 モヌドの遞択は、そのような莅沢を買う䜙裕があるかどうかに䟝存したす。


私たちにずっお、䞊行移行にはリスクがありたした新しいバヌゞョンの準備䞭に、すべおの開発が停止し、移動の期間をどれだけうたく蚈算しおも、プロセスが匕きずられる可胜性があり、䜕かに遭遇し、次に䜕をすべきか理解できたせん。 ハむブリッドモヌドでは、この状況では、停止しお゜リュヌションを穏やかに探すこずができたす。これは、珟圚の実皌働バヌゞョンがただ皌働しおいるためです。 効率的に機胜せず、少し難しくなりたすが、プロセスは停止したせん。 䞊行しお、察応する損倱を䌎うロヌルバックが発生しおいたした。 私たちの移行プロセスが本圓に匕きずられたこずに泚目する䟡倀がありたす-412時間を蚈画したしたが、実際には2倍830になりたした。 しかし、同時に、䜕も止たらず、新しい機胜が絶えず展開され、すべおが正垞に機胜したした。


䞀般的に、ハむブリッド遷移は䞍可抗力ではなく、Angular自䜓の開発者によるず、完党に通垞のデフォルトの手順であるず考える䟡倀がありたす。 圌を恐れる必芁はありたせん。


蚈画


アクションのシヌケンスは次のようになりたした。


  1. ハむブリッドアプリケヌションの初期化角床をブヌトストラップするブヌトストラップ角床。 すべおがそのたた残りたすが、ハむブリッドモヌドが機胜しおいる間遅くなり、長く開始するようになりたす。 コントロヌラヌをheadに投げる機䌚はもうありたせん。タむトル/ファビコン/メタタグのすべおの䜜業は、頭の必芁な芁玠ず盎接やり取りするサヌビスに送信されたす。
  2. アングルぞのサヌビスの転送最も簡単。 曞き換えられたサヌビスは、ただコンポヌネントを実行しおいるAngularJSからすぐに利甚可胜になりたす。 䟝存関係のない最も単玔なものから始たり、より耇雑なものぞ。
  3. フクロりの残りの郚分を描画したす基本コンポヌネントGUIおよび他のコンポヌネント/ディレクティブを䜿甚しない他のすべおを転送したす。 可胜であれば、ナニット単䜍でコンポヌネントを䞋から䞊に移動したす。
  4. 矜をずかすペヌゞのコンポヌネントを転送し、AngularJSを切り取りたす。

転送ルヌル


さお、぀いに玄束の技術的詳现に進みたしょう。 これらの蚘録を少し掃陀し、プラットフォヌムのみに関する䞍必芁な詳现を削陀したした。 これらは普遍的な゜リュヌションではありたせんが、誰かが発生する問題を解決するのに圹立぀かもしれたせん。


テキストの壁を塞がないように、ネタバレの䞋にすべおを隠したす。


個々のアむテムを転送する方法


モゞュヌル

䜕かをアップグレヌドし始めおいるモゞュヌルに角床モゞュヌルがない堎合、それを䜜成しおメむンアプリケヌションモゞュヌルにフックしたす。


 import {NgModule} from "@angular/core"; @NgModule({ // }); export class SmthModule {} @NgModule({ imports: [ ... SmthModule, ], }); export class AppModule {} 

角床モゞュヌルがただ生きおいる堎合、新しいモゞュヌルには.new接尟蟞が付けられたす。 角の叀いモゞュヌルず䞀緒に接尟蟞を切り取りたす。


サヌビス

良いケヌスでは、デコレヌタを远加し、゚クスポヌトからdefaultを削陀し、むンポヌトを線集しデフォルトを削陀したため、モゞュヌルの角床にむンポヌトし、モゞュヌルの角床でダりングレヌドしたす


 import {Injectable} from "@angular/core"; @Injectable() export class SmthService { ... } // angular module @NgModule({ providers: [ ... SmthService, ], }); // angularjs module import {downgradeInjectable} from "@angular/upgrade/static"; ... .factory("vim.smth", downgradeInjectable(SmthService)) 

サヌビスは、Angurjarsの叀い名前で匕き続き利甚でき、远加の構成は必芁ありたせん。


良いオプションは、すべおのむンゞェクションサヌビスが既にAngularに移行しおいるため、 templateCacheやcompiler特定のものは䜿甚されないこずを意味したす。


残りの95のケヌスでは、たず泚入されたものをアップグレヌドし、あらゆる皮類の奇劙なサヌビスなどを取り陀きたす。


成分

メタデヌタを䜿甚しおデコレヌタをコントロヌラに蚌明し、デコレヌタの入力/出力を配眮しお、クラスの先頭に転送したす。


 import {Component, Input, Output, EventEmitter} from "@angular/core"; @Component({ //   `-`     ,   camelCase selector: "vim-smth", //       require("./smth.html") templateUrl: "smth.html", }) export class SmthComponent { @Input() smth1: string; @Output() smthAction = new EventEmitter<void>(); ... } // angular module @NgModule({ declarations: [ ... SmthComponent, ], //         ,         exports: [ ... SmthComponent, ], }); // angularjs module import {downgradeInjectable} from "@angular/upgrade/static"; ... .directive("vimSmth", downgradeComponent({ component: SmthComponent }) as ng.IDirectiveFactory) 

泚入されたすべおのサヌビスは、すべおコンポヌネントそれらをフックする方法-Anythingの䞋を必芁ずし、テンプレヌト内で䜿甚されるすべおのコンポヌネント/ディレクティブ/フィルタヌは栌玍庫にある必芁がありたす。


テンプレヌトで䜿甚されるすべおのコンポヌネント倉数はpublicずしお宣蚀する必芁がありたす。そうでない堎合は、AoTアセンブリに分類されたす。


コンポヌネントが入力を介しお䞊蚘のコンポヌネントから出力甚のすべおのデヌタを受け取った堎合、 changeDetection: ChangeDetectionStrategy.OnPushをメタデヌタに倧胆に曞き蟌みたす。 これは、コンポヌネントの入力のいずれかが倉曎された堎合にのみテンプレヌトをデヌタず同期するこのコンポヌネントの倉曎怜出を開始するこずを角床に䌝えたす。 理想的には、ほずんどのコンポヌネントがこのモヌドになっおいる必芁がありたすただし、サヌビスを介しお出力甚のデヌタを受け取る非垞に倧きなコンポヌネントのため、ほずんどそうではありたせん。


指什

コンポヌネントず同じですが、テンプレヌトず@Directiveデコレヌタはありたせん。 そこにあるモゞュヌルにスロヌされ、他のモゞュヌルのコンポヌネントで䜿甚するために゚クスポヌトされるものは同じでなければなりたせん。


camelCaseのセレクタヌは、コンポヌネントテンプレヌトでも䜿甚されたす。


フィルタヌ

これで@Pipeなり、 PipeTransformむンタヌフェむスを実装するPipeTransformたす。 コンポヌネント/ディレクティブがあるモゞュヌルに自分自身を投げ蟌み、他のモゞュヌルで䜿甚する堎合ぱクスポヌトする必芁もありたす。


camelCaseのセレクタヌは、コンポヌネントテンプレヌトでも䜿甚されたす。


角床のディレクティブずフィルタヌは、角床のコンポヌネントテンプレヌトでは䜿甚できたせん。逆の堎合も同様です。 フレヌムワヌク間では、サヌビスずコンポヌネントのみがスロヌされたす。


゚クスポヌト/むンポヌトおよびむンタヌフェヌス

たず、゚クスポヌトのデフォルトを取り陀きたす。なぜなら、 AoTコンパむラヌはそれを䜿甚できたせん。


第二に、モゞュヌルの珟圚の構造非垞に倧きいずむンタヌフェヌスの䜿甚クラスがある同じファむルにヒヌプを眮くのために、そのようなむンタヌフェヌスのむンポヌトずデコレヌタヌでの䜿甚で面癜いバグをキャッチしたしたむンタヌフェヌスが゚クスポヌトを含むファむルからむンポヌトされた堎合むンタヌフェヌスだけでなく、たずえばクラス/定数も䜿甚されたす。このようなむンタヌフェヌスは、デコレヌタの暪の入力に䜿甚され @Input() smth: ISmth 、コンパむラはむンポヌト゚ラヌexport 'ISmth' was not found 。 これは、すべおのむンタヌフェヌスを別のファむルに転送するモゞュヌルが倧きいためにファむルが1ダヌスの画面に衚瀺されるために悪いか、むンタヌフェヌスをクラスに眮き換えるこずで修正できたす。 クラスで眮き換えるこずは機胜したせん。 耇数の芪から継承するこずはできたせん。


遞択した゜リュヌション各モゞュヌルにinterfaceディレクトリを䜜成しinterfaceディレクトリには、察応するむンタヌフェむス郚屋、ステップ、コンテンツ、ワヌクブック、宿題などを含む本質的に名前の付いたファむルが眮かれたす。 したがっお、ロヌカルではなく䜿甚されるすべおのむンタヌフェむスがそこに眮かれ、そのようなファむルディレクトリからむンポヌトされたす。


問題のより詳现な説明
https://github.com/angular/angular-cli/issues/2034#issuecomment-302666897
https://github.com/webpack/webpack/issues/2977#issuecomment-245898520


機胜transklud、パラメヌタヌの受け枡し、svgのむンポヌト


Transclub機胜

アップグレヌドされたコンポヌネントがtransglud ng-content を䜿甚する堎合、角床テンプレヌトからコンポヌネントを䜿甚するずき


  • マルチスロットのトランスクロスは機胜せず、1぀のng-content介しおすべおを1぀のピヌスに転送する機胜のみが機胜したす。
  • そのようなコンポヌネントの翻蚳では、UIビュヌをスロヌできたせん。 動䜜したせんビュヌポヌトコンポヌネントをアップグレヌドしようずするず䞭断したした。
  • コンポヌネントがこのように䜿甚される堎合、そのアップグレヌドを䜿甚されおいるすべおの堎所のアップグレヌドに延期するか、すでにアップグレヌドされたコンポヌネントの䞊列操䜜のためにそのコピヌを䜜成したす。

パラメヌタ転送の機胜

角床成分で角床成分を䜿甚する堎合、入力は通垞の角床成分のように []および()を䜿甚しお曞き蟌たれたすが、 kebab-case


 <vim-angular-component [some-input]="" (some-output)=""> </vim-angular-component> 

このようなテンプレヌトをアングルで曞き換えるずきは、camelCaseでケバブケヌスを線集したす。


写真/ svgテンプレヌトが必芁

乗車ではないので、 AoTコンパむラヌはそれを誓いたす。 したがっお、同じファむルをtsファむルにむンポヌトし、コンポヌネントのコンポヌネントを介しお転送したす。


だった


 <span> ${require('!html-loader!image-webpack-loader?{}!./images/icon.svg')} </span> 

になりたした


 const imageIcon = require<string>("!html-loader!image-webpack-loader?{}!./images/icon.svg"); public imageIcon = imageIcon; <span [innerHTML]="imageIcon | vimBaseSafeHtml"> </span> 

たたはimg経由で䜿甚するため


だった


 <img ng-src="${require('./images/icon.svg')}" /> 

になりたした


 const imageIcon = require<string>("./images/icon.svg"); public imageIcon = imageIcon; <img [src]="imageIcon | vimBaseSafeUrl" /> 

動的なコンポヌネントずパタヌン


$コンパむルなしの生掻

文字列からの$compileがないので、 $compileはもうありたせん実際、小さなハックがありたすが、ここでは$compileなしで95のケヌスに察応する方法を瀺し$compile 。


動的に挿入されたコンポヌネントは、次のようにスロヌされたす。


 @Component({...}) class DynamicComponent {} @NgModule({ declarations: [ ... DynamicComponent, ], entryComponents: [ DynamicComponent, ], }) class SomeModule {} //  @Component({ ... template: ` <vim-base-dynamic-component [component]="dynamicComponent"></vim-base-dynamic-component> ` }) class SomeComponent { public dynamicComponent = DynamicComponent; } 

挿入されたコンポヌネントのクラスは、サヌビス、入力、たたはその他の方法でロヌルできたす。


vim-base-dynamic-componentは、入力/出力をサポヌトする他のコンポヌネントの動的挿入甚に既に䜜成されたvim-base-dynamic-componentです将来、必芁に応じお。


動的なtemplateUrlはありたせん

条件ごずに異なるテンプレヌトを出力する必芁があり、そのために動的なtemplateUrlを䜿甚した堎合、これを構造ディレクティブに眮き換えお、コンポヌネントを3぀に分割したす。 モバむル/非モバむルの出力を分割する䟋


リク゚スト/デヌタ凊理
モバむル向けのマッピング
デスクトップ甚ディスプレむ


最初のコンポヌネントには最小限のテンプレヌトがあり、デヌタの操䜜、ナヌザヌアクションなどの凊理に取り組んでいたすテンプレヌトは、簡朔さのため、コンポヌネントのコンポヌネントを個別のhtmlファむルずtemplateUrl代わりに ''に眮くのが理にかなっおいたす。 䟋


 @Component({ selector: "...", template: ` <some-component-mobile *vimBaseIfMobile="true" [data]="data" (changeSmth)="onChangeSmth($event)"> </some-component-mobile> <some-component-desktop *vimBaseIfMobile="false" [data]="data" (changeSmth)="onChangeSmth($event)"> </some-component-desktop> `, }) 

vimBaseIfMobileは、内郚条件ず枡されたパラメヌタヌに埓っお察応するコンポヌネントを衚瀺する構造ディレクティブこの堎合はngIf盎接の類䌌物です。


携垯電話ずデスクトップのコンポヌネントは、入力を介しおデヌタを受信し、出力を介しおいく぀かのむベントを送信し、必芁なものの出力のみを凊理したす。 すべおの耇雑なロゞック、凊理、デヌタの倉曎-それらを衚瀺するメむンコンポヌネント。 そのようなコンポヌネントdextop / mobileでは、 changeDetection: ChangeDetectionStrategy.OnPush安党に蚘述できたす。


Angular Servicesの䜿甚/ Angular Servicesのコンポヌネント/コンポヌネント


サヌビス/芁因/プロバむダヌ

app/entries/angularjs-services-upgrade.tsを開き、既存のコピヌず貌り付けの䟋に埓っおこのファむル内のすべお


 // EXAMPLE: copy-paste, fix naming/params, add to module providers at the bottom, use // ----- import LoaderService from "../service/loader"; // NOTE: this function MUST be provided and exported for AoT compilation export function loaderServiceFactory(i: any) { return i.get(LoaderService.ID); } const loaderServiceProvider = { provide: LoaderService, useFactory: loaderServiceFactory, deps: [ "$injector" ] }; // ----- @NgModule({ providers: [ loaderServiceProvider, ] }) export class AngularJSServicesUpgrade {} 

すなわち 既存のブロックをコピヌし、必芁なサヌビスをむンポヌトし、そのための定数/関数の名前を線集し、その䞭で䜿甚されるサヌビスずその名前を線集したすほずんどの堎合、 SmthService.ID代わりに、栌玍庫でサヌビスにアクセス SmthService.IDする名前を挿入する必芁がありたす、远加新しい定数smthServiceProviderをファむルの最埌にあるプロバむダヌのリストにsmthServiceProviderしたす。


このようなサヌビスは、ネむティブのAngularずしお䜿甚されたす。クラスごずにコンストラクタに単玔に泚入できたす。


成分

元のコンポヌネントを含むファむルに最初に次のスタブを配眮したす。これにより、コンポヌネントを角床環境にスロヌできたす。


 import {Directive, ElementRef, Injector, Input, Output, EventEmitter} from "@angular/core"; import {UpgradeComponent} from "@angular/upgrade/static"; @Directive({ /* tslint:disable:directive-selector */ selector: "vim-smth" }) /* tslint:disable:directive-class-suffix */ export class SmthComponent extends UpgradeComponent { @Input() smth: boolean; @Output() someAction: EventEmitter<string>; constructor(elementRef: ElementRef, injector: Injector) { super("vimSmth", elementRef, injector); } } @NgModule({ declarations: [ ... SmthComponent, ] }) export class SmthModule { 

この堎合、 Component代わりにDirectiveデコレヌタが䜿甚されるこずに泚意しおください。これは、Angularがこれを凊理する方法の機胜です。


すべおの入力/出力元のコンポヌネントからのバむンダヌを登録しdeclarations察応するモゞュヌルのdeclarationsコンポヌネントを登録するこずを忘れないでください。


将来、このコンポヌネントをアップグレヌドするず、そのようなスタブは角床の実際のコンポヌネントになりたす。


コンポヌネントたたは叀いコンポヌネントディレクティブがコントロヌラヌ/リンク関数に$attrsを泚入する堎合、そのようなコンポヌネントは栌玍庫から栌玍庫にキャストできず、栌玍庫のアップグレヌドされたコピヌの隣にアップグレヌドたたは配眮する必芁がありたす。


tslint゚ラヌを無効にするには、セレクタヌの名前ずディレクティブのデコレヌタヌに察するクラスの䞍䞀臎を誓わないこずが必芁です。 これらの行コメントは、コンポヌネントのアップグレヌド埌に削陀する必芁がありたす。


毎


毎
  • $q Promiseサヌビスを䜿甚するず、ネむティブPromise眮き換えられたす。 finallyはありたせんが、これはcore.js/es7.promise.finallyによっお修正され、珟圚は修正されおいたす。 たた、遅延はありたせん。ts-deferredが远加され、毎回自転車を曞かないようにしたす。
  • $timeoutず$interval代わりに、ネむティブwindow.setTimeoutずwindow.setInterval $interval䜿甚したす。
  • ng-show="visible"代わりに、属性ng-show="visible"バむンド[hidden]="!visible" ;
  • track by垞にメ゜ッドである必芁がありたすメ゜ッドのTrack埌眮を忘れないでください

 *ngFor="let item of items; trackBy: itemTrack" public itemTrack(_index: number, item: IItem): number { return item.id; } 

  • 99の堎合、 $digest 、 $apply 、 $evalAsyncなどは、眮換なしで切り取られたす。
  • サヌビスむンゞェクションの堎合、コンストラクタコンストラクconstructor(private someService: SomeService)に曞き蟌むだけで、角床自䜓がどこから取埗するかを理解したす。
  • ディレクティブ内で、それがハングする芁玠はconstructor(private element: ElementRef) AfterViewInitからアクセス可胜で、 AfterViewInitフックで初期化されたす ElementRefはDOMオブゞェクトそのものではなく、 this.element.nativeElementによっおアクセス可胜this.element.nativeElement 。
  • ng-include眮換なしでng-includeなく、コンポヌネントの動的䜜成を䜿甚したす。
  • angular.extend 、 angular.merge 、 angular.forEachなどが欠萜しおおり、ネむティブのjsずlodashを䜿甚しおいたす。
  • angular.elementずそのすべおのメ゜ッドが欠萜しおいたす。 @ViewChild/@ContentChildを䜿甚し、ネむティブjsを凊理したす。
  • OnPushしおコンポヌネントの怜出チェンゞャヌをプルする必芁がある堎合- private changeDetectorRef: ChangeDetectorRef挿入しprivate changeDetectorRef: ChangeDetectorRefおよびプルprivate changeDetectorRef: ChangeDetectorRef this.changeDetectorRef.markForCheck() ;
  • テンプレヌトから$ctrl.を芋぀けたした$ctrl. -名前によるsv-youおよびメ゜ッドぞの盎接アクセス。
  • ng-bind-html="smth" -> [innerHTML]="smth"
  • $sce import {DomSanitizer} from "@angular/platform-browser"; > import {DomSanitizer} from "@angular/platform-browser";
  • ng-pural > [ngPlural] https://angular.io/api/common/NgPlural
  • ngClassはそれができたせん

 [ngClass]="{ [ styles.active ]: visible, [ styles.smth ]: smth }" 

したがっお、配列に眮き換えたす


 [ngClass]="[ visible ? styles.active : '', smth ? styles.smth : '' ]" 

  • ui-routerサヌビスのクラスは@uirouter/coreからむンポヌトされ、叀い$プレフィックスなしで挿入されたす

 import {StateService, TransitionService} from "@uirouter/core"; constructor(stateService: StateService, transitionService: TransitionService) { 

  • コンポヌネントのデヌタ属性は、 attr.data-smth=""たたは[attr.data-smth]=""ずしお登録されたす。
  • コンポヌネント内のrequire /ディレクティブは、珟圚のコンポヌネントコンストラクタヌcontructor(private parentComponent: ParentComponent)のコンストラクタヌに盎接コンポヌネントクラスを挿入するこずで眮き換えられたす。 Angular自身は、これがコンポヌネントであるこずを確認し、それをフックしたす。 埮調敎のために、 @Self 芪間の怜玢、 @Self コンポヌネント䞊で盎接怜玢、 @Optional 存圚しない堎合ず存圚しない堎合があり、倉数は未定矩の@Optionalがありたす。 耇数の@Host() @Optional() parentComponent: ParentComponentスロヌできたす。 コンポヌネント/ディレクティブをコンポヌネント/ディレクティブに再利甚できたす。
  • 双方向バむンディングは、そのコンポヌネントでより明瀺的になり、同じ名前ず接尟蟞Change Outputを必芁ずしOutput 。

 export class SmthComponent { @Input() variable: string; @Output() variableChange = new EventEmitter<string>(); <vim-smth [(variable)]="localVar"></vim-smth> 

  • 角床成分の可胜な半透明の角床成分。 名前付きのtranslucをチェックする必芁がありたす動䜜するかどうかセレクタヌで行われる角床で

 <!-- angular --> <ng-content></ng-content> <!-- angularjs --> <vim-angular-component> transcluded data </vim-angular-component> 

次のパヌトでは、ハむブリッドモヌドでの䜜業の機胜 ず、Angularで慣れなければならない新しい芏則に぀いお説明したす 。



Source: https://habr.com/ru/post/J348356/


All Articles