填寫這份《一分鐘調查》,幫我們(開發組)做得更好!去填寫Home

Ivy 相容性指南

Ivy compatibility guide

Angular 團隊一直在努力確保 Ivy 與之前的渲染引擎(“View Engine”)儘可能向後相容。但是,在極少數情況下,需要做一些小改動才能確保 Angular 的行為是可預測和一致的,以糾正 View Engine 實現中的問題。為了順利過渡,我們儘可能提供了自動遷移功能,以便 CLI 可以自動遷移你的應用和函式庫程式碼。也就是說,某些應用可能需要做一些手動更新。

The Angular team has worked hard to ensure Ivy is as backwards-compatible with the previous rendering engine ("View Engine") as possible. However, in rare cases, minor changes were necessary to ensure that the Angular's behavior was predictable and consistent, correcting issues in the View Engine implementation. In order to smooth the transition, we have provided automated migrations wherever possible so your application and library code is migrated automatically by the CLI. That said, some applications will likely need to apply some manual updates.

如何用 Ivy 除錯錯誤

How to debug errors with Ivy

如果發現了錯誤,請先在 tsconfig.json暫時關閉 Ivy ,然後重新啟動你的應用程式。

If you're seeing errors, first temporarily turn off Ivy in your tsconfig.json and re-start your app.

如果仍然有錯,說要這些錯誤不是 Ivy 特有的。在這種情況下,你可能需要查閱常規更新指南。如果你選擇了任何新的、更嚴格的型別檢查設定,則可能還需要檢視範本型別檢查指南

If you're still seeing the errors, they are not specific to Ivy. In this case, you may want to consult the general update guide. If you've opted into any of the new, stricter type-checking settings, you may also want to check out the template type-checking guide.

如果錯誤消失了,可以刪除對 tsconfig.base.json 的更改,切換回 Ivy,並檢視下面的預期更改列表。

If the errors are gone, switch back to Ivy by removing the changes to the tsconfig.json and review the list of expected changes below.

有效載荷大小除錯

Payload size debugging

如果你注意到應用的主服務套件的大小隨著 Ivy 的增加而增加了,你可能需要檢查如下內容:

If you notice that the size of your application's main bundle has increased with Ivy, you may want to check the following:

  1. 驗證你想要延遲載入的元件和 NgModules 是否只在惰性模組中才匯入過。你在惰性模組之外匯入的東西最終都會出現在主發佈套件中。原始問題請點選此處檢視詳情。

    Verify that the components and NgModules that you want to be lazy loaded are only imported in lazy modules. Anything that you import outside lazy modules can end up in the main bundle. See more details in the original issue here.

  2. 檢查匯入的函式庫是否已標記為無副作用。如果你的應用匯入過那些沒有副作用的共享函式庫,就把“sideEffects”:false 新增到他們的 package.json。如果這些函式庫被匯入過但沒有被直接參考,那麼這將確保這些函式庫被正確搖樹優化了。原始問題請點選此處檢視詳情。

    Check that imported libraries have been marked side-effect-free. If your app imports from shared libraries that are meant to be free from side effects, add "sideEffects": false to their package.json. This will ensure that the libraries will be properly tree-shaken if they are imported but not directly referenced. See more details in the original issue here.

  3. 未使用 Angular CLI 的專案會看到一個顯著的大小回歸,除非他們更新了最小化工具的設定,並把編譯時常量 ngDevModengI18nClosureModengJitMode 設為了 false (對於 Terser,請透過global_defs 配置選項把它們設為 false )。請注意,這些常量不能給第三方函式庫或應用程式碼使用,因為它們不是我們公共 API 的一部分,可能會在將來發生變化。

    Projects not using Angular CLI will see a significant size regression unless they update their minifier settings and set compile-time constants ngDevMode, ngI18nClosureMode and ngJitMode to false (for Terser, please set these to false via global_defs config option). Please note that these constants are not meant to be used by 3rd party library or application code as they are not part of our public API surface and might change in the future.

你可能會看到變化

Changes you may see

  • 預設情況下,@ContentChildren 查詢只搜尋 DOM 層次結構中的直接子節點(以前,只要它沒有匹配到另一個指令,它們就會搜尋 DOM 中的任何巢狀級別)。詳情參閱這裡

    By default, @ContentChildren queries will only search direct child nodes in the DOM hierarchy (previously, they would search any nesting level in the DOM as long as another directive wasn't matched above it). See further details.

  • 所有使用 Angular DI 的類別都必須有一個 Angular 裝飾器,比如 @Directive() 或者 @Injectable(以前,只有在 AOT 模式下或者帶有注入標誌時才能使用未修飾的類別)。詳情參閱這裡

    All classes that use Angular DI must have an Angular decorator like @Directive() or @Injectable (previously, undecorated classes were allowed in AOT mode only or if injection flags were used). See further details.

  • 指令的未繫結輸入(例如 <my-comp name=""> )現在是在建立檢視時設定的,位於執行變更檢測之前(以前所有輸入都是在變更檢測過程中設定的)。

    Unbound inputs for directives (e.g. name in <my-comp name="">) are now set upon creation of the view, before change detection runs (previously, all inputs were set during change detection).

  • 直接在範本的 HTML 中設定的靜態屬性會覆蓋指令或元件中設定的任何與之衝突的宿主屬性(以前,如果有衝突,指令/元件設定的靜態宿主屬性會覆蓋靜態的範本屬性)。

    Static attributes set directly in the HTML of a template will override any conflicting host attributes set by directives or components (previously, static host attributes set by directives / components would override static template attributes if conflicting).

不太常見的變化

Less common changes

  • @Component@Directive 裝飾器裡面的 host 這樣的屬性可以被繼承(之前,只有具有顯式欄位裝飾器的屬性,比如 @HostBinding 才會被繼承)。

    Properties like host inside @Component and @Directive decorators can be inherited (previously, only properties with explicit field decorators like @HostBinding would be inherited).

  • HammerJS 支援是可選的,如果需要則匯入 HammerModule (以前,它總是包含在生產套件中,而不管應用是否使用了 HammerJS)。

    HammerJS support is opt-in through importing the HammerModule (previously, it was always included in production bundles regardless of whether the app used HammerJS).

  • @ContentChild@ContentChildren 查詢將無法匹配指令自己的宿主節點(以前,這些查詢除了內容子節點外,還會匹配宿主節點)。

    @ContentChild and @ContentChildren queries will no longer be able to match their directive's own host node (previously, these queries would match the host node in addition to its content children).

  • 如果一個令牌是使用 @Host@Self 標誌注入的,則不會在模組注入器中搜索該令牌(以前,有這些標誌的令牌仍會在模組級別進行搜尋)。

    If a token is injected with the @Host or @Self flag, the module injector is not searched for that token (previously, tokens marked with these flags would still search at the module level).

  • 當在範本繫結中訪問同名的多個本地參考時,匹配上的總是第一個參考(以前匹配的是最後一個參考)。

    When accessing multiple local refs with the same name in template bindings, the first is matched (previously, the last instance was matched).

  • 從本模組匯出的其它模組中使用的指令(但這些模組自己沒有主動匯出過)會被公開匯出(之前,編譯器會自動編寫一個私有的、使用別名的匯出,以便利用其中的全域性知識解析下游模組)。

    Directives that are used in an exported module (but not exported themselves) are exported publicly (previously, the compiler would automatically write a private, aliased export that it could use its global knowledge to resolve downstream).

  • 裝飾器元資料中的外部函式或外部常量不能再用靜態解析的(之前,你可以從其它編譯單元(比如函式庫)中匯入一個常量或函式,並在你的 @NgModule 定義中使用該常量/函式)。

    Foreign functions or foreign constants in decorator metadata aren't statically resolvable (previously, you could import a constant or function from another compilation unit, like a library, and use that constant/function in your @NgModule definition).

  • 預設情況下,不再支援透過本地參考來訪問指令輸入的前向參考。詳情在此

    Forward references to directive inputs accessed through local refs are no longer supported by default. details

  • 如果同時存在一個未繫結的 class 屬性和一個 [class] 繫結,那麼未繫結的屬性中的類別也會被新增進去(以前,類別繫結會覆蓋未繫結屬性中的類別)。

    If there is both an unbound class attribute and a [class] binding, the classes in the unbound attribute will also be added (previously, the class binding would overwrite classes in the unbound attribute).

  • 現在賦值給一個僅用在範本中的變數會出錯,比如 ngFor="let item of items" 中的 item(以前,編譯器會忽略這些賦值)。

    It is now an error to assign values to template-only variables like item in ngFor="let item of items" (previously, the compiler would ignore these assignments).

  • 不能再在指令實例上使用 Mock 方式來覆蓋生命週期鉤子(而應該修改指令型別本身的生命週期鉤子)。

    It's no longer possible to overwrite lifecycle hooks with mocks on directive instances for testing (instead, modify the lifecycle hook on the directive type itself).

  • 特殊注入令牌(比如 TemplateRefViewContainerRef )每次都會返回一個新的實例(之前,如果它們在同一個節點上被請求過,就會共享這些特殊令牌的同一個實例)。這主要會影響到那些比較這些物件標識的測試。

    Special injection tokens (such as TemplateRef or ViewContainerRef) return a new instance whenever they are requested (previously, instances of special tokens were shared if requested on the same node). This primarily affects tests that do identity comparison of these objects.

  • ICU 解析是在執行時發生的,因此在 ICU 案例中只允許使用文字、HTML 標籤和文字繫結(以前,ICU 中也允許使用指令)。

    ICU parsing happens at runtime, so only text, HTML tags and text bindings are allowed inside ICU cases (previously, directives were also permitted inside ICUs).

  • 把文字繫結新增到源範本中不存在的 i18n 會丟擲一個執行時錯誤(以前,允許在翻譯中包含額外繫結)。

    Adding text bindings into i18n translations that are not present in the source template itself will throw a runtime error (previously, including extra bindings in translations was permitted).

  • i18n 翻譯中的額外 HTML 標籤(源範本中不存在的)將渲染為純文字(以前,這些標籤會渲染為 HTML 格式)。

    Extra HTML tags in i18n translations that are not present in the source template itself will be rendered as plain text (previously, these tags would render as HTML).

  • 格式為 {provide: X} 且不帶 useValueuseFactoryuseExistinguseClass 屬性的服務提供者將被視為 {provide: X, useClass: X} (以前被視為 {provide: X, useValue: undefined} )。

    Providers formatted as {provide: X} without a useValue, useFactory, useExisting, or useClass property are treated like {provide: X, useClass: X} (previously, it defaulted to {provide: X, useValue: undefined}).

  • DebugElement.attributes 為那些已新增過的屬性返回 undefined,並導致它們被移除(以前,表示新增後再刪除的屬性的值為 null )。

    DebugElement.attributes returns undefined for attributes that were added and then subsequently removed (previously, attributes added and later removed would have a value of null).

  • DebugElement.classes 為那些已新增過再刪除的類別返回 undefined (以前,表示新增後再刪除的類別的值為 false )。

    DebugElement.classes returns undefined for classes that were added and then subsequently removed (previously, classes added and later removed would have a value of false).

  • 如果在 <select> 中選擇原生的 <option> 元素,而這個 <option> 元素是透過 *ngFor 建立的,就使用 <option>[selected] 屬性,而不是繫結到 <select> 元素上的 [value] 屬性(以前,你可以繫結到任何一個。)詳情在此

    If selecting the native <option> element in a <select> where the <option>s are created via *ngFor, use the [selected] property of an <option> instead of binding to the [value] property of the <select> element (previously, you could bind to either.) details

  • 嵌入式檢視(比如 *ngFor 建立的嵌入式檢視)現在會插入到錨點註釋節點(例如 <!--ng-for-of--> )的前面,而不是像之前一樣插入到後面。在大多數情況下,這對渲染的 DOM 沒有任何影響。在某些情況下(比如動畫會延遲刪除嵌入式檢視),任何新的嵌入式檢視都會插入在這個被刪除的嵌入式檢視後面。這種差異只會在動畫處於活動狀態時存在,並可能會改變動畫的視覺外觀。動畫完成後,渲染出的 DOM 與使用 View Engine 渲染的 DOM 完全相同。

    Embedded views (such as ones created by *ngFor) are now inserted in front of anchor DOM comment node (e.g. <!--ng-for-of-->) rather than behind it as was the case previously. In most cases this does not have any impact on rendered DOM. In some cases (such as animations delaying the removal of an embedded view) any new embedded views will be inserted after the embedded view being animated away. This difference only last while the animation is active, and might alter the visual appearance of the animation. Once the animation is finished the resulting rendered DOM is identical to that rendered with View Engine.