From 5212b47bbf9f3da890176512296a49c1b98263c8 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 11 Aug 2023 08:52:39 +0200 Subject: [PATCH] refactor(compiler): introduce defer trigger instructions (#51315) Adds the logic for generating the instructions for the various deferred triggers. PR Close #51315 --- .../GOLDEN_PARTIAL.js | 98 +++++++++++++++++++ .../r3_view_compiler_deferred/TEST_CASES.json | 42 ++++++++ .../basic_deferred_template.js | 1 + .../deferred_secondary_blocks_template.js | 1 + .../deferred_with_external_deps_template.js | 1 + .../deferred_with_loading_params_template.js | 1 + .../deferred_with_local_deps_template.js | 1 + ...ferred_with_placeholder_params_template.js | 1 + .../deferred_with_prefetch_triggers.ts | 20 ++++ ...eferred_with_prefetch_triggers_template.js | 20 ++++ .../deferred_with_triggers.ts | 20 ++++ .../deferred_with_triggers_template.js | 19 ++++ .../compiler/src/render3/r3_identifiers.ts | 20 ++++ .../compiler/src/render3/view/template.ts | 73 ++++++++++++-- .../core/src/core_render3_private_export.ts | 14 +++ packages/core/src/render3/index.ts | 14 +++ .../core/src/render3/instructions/defer.ts | 91 +++++++++++++++++ packages/core/src/render3/jit/environment.ts | 14 +++ 18 files changed, 444 insertions(+), 7 deletions(-) create mode 100644 packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_prefetch_triggers.ts create mode 100644 packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_prefetch_triggers_template.js create mode 100644 packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_triggers.ts create mode 100644 packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_triggers_template.js diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/GOLDEN_PARTIAL.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/GOLDEN_PARTIAL.js index 3c0462f70ebf8..5b45f87ab4f68 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/GOLDEN_PARTIAL.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/GOLDEN_PARTIAL.js @@ -352,3 +352,101 @@ export declare class MyApp { static ɵcmp: i0.ɵɵComponentDeclaration; } +/**************************************************************************************************** + * PARTIAL FILE: deferred_with_triggers.js + ****************************************************************************************************/ +import { Component } from '@angular/core'; +import * as i0 from "@angular/core"; +export class MyApp { + constructor() { + this.message = 'hello'; + this.isReady = true; + } + isVisible() { + return false; + } +} +MyApp.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyApp, deps: [], target: i0.ɵɵFactoryTarget.Component }); +MyApp.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyApp, selector: "ng-component", ngImport: i0, template: ` + {{message}} + {#defer when isVisible() || isReady; on idle, timer(1337); on immediate, hover; + on interaction(button); on viewport(button)} + {{message}} + {:placeholder} + {/defer} + `, isInline: true }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyApp, decorators: [{ + type: Component, + args: [{ + template: ` + {{message}} + {#defer when isVisible() || isReady; on idle, timer(1337); on immediate, hover; + on interaction(button); on viewport(button)} + {{message}} + {:placeholder} + {/defer} + `, + }] + }] }); + +/**************************************************************************************************** + * PARTIAL FILE: deferred_with_triggers.d.ts + ****************************************************************************************************/ +import * as i0 from "@angular/core"; +export declare class MyApp { + message: string; + isReady: boolean; + isVisible(): boolean; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵcmp: i0.ɵɵComponentDeclaration; +} + +/**************************************************************************************************** + * PARTIAL FILE: deferred_with_prefetch_triggers.js + ****************************************************************************************************/ +import { Component } from '@angular/core'; +import * as i0 from "@angular/core"; +export class MyApp { + constructor() { + this.message = 'hello'; + this.isReady = true; + } + isVisible() { + return false; + } +} +MyApp.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyApp, deps: [], target: i0.ɵɵFactoryTarget.Component }); +MyApp.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyApp, selector: "ng-component", ngImport: i0, template: ` + {{message}} + {#defer prefetch when isVisible() || isReady; prefetch on idle, timer(1337); + prefetch on immediate, hover; prefetch on interaction(button); prefetch on viewport(button)} + {{message}} + {:placeholder} + {/defer} + `, isInline: true }); +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyApp, decorators: [{ + type: Component, + args: [{ + template: ` + {{message}} + {#defer prefetch when isVisible() || isReady; prefetch on idle, timer(1337); + prefetch on immediate, hover; prefetch on interaction(button); prefetch on viewport(button)} + {{message}} + {:placeholder} + {/defer} + `, + }] + }] }); + +/**************************************************************************************************** + * PARTIAL FILE: deferred_with_prefetch_triggers.d.ts + ****************************************************************************************************/ +import * as i0 from "@angular/core"; +export declare class MyApp { + message: string; + isReady: boolean; + isVisible(): boolean; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵcmp: i0.ɵɵComponentDeclaration; +} + diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/TEST_CASES.json b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/TEST_CASES.json index 6c52794150f95..a1ef47aa22fca 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/TEST_CASES.json +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/TEST_CASES.json @@ -129,6 +129,48 @@ } ], "skipForTemplatePipeline": true + }, + { + "description": "should generate a deferred block with triggers", + "angularCompilerOptions": { + "_enabledBlockTypes": ["defer"] + }, + "inputFiles": [ + "deferred_with_triggers.ts" + ], + "expectations": [ + { + "files": [ + { + "expected": "deferred_with_triggers_template.js", + "generated": "deferred_with_triggers.js" + } + ], + "failureMessage": "Incorrect template" + } + ], + "skipForTemplatePipeline": true + }, + { + "description": "should generate a deferred block with prefetch triggers", + "angularCompilerOptions": { + "_enabledBlockTypes": ["defer"] + }, + "inputFiles": [ + "deferred_with_prefetch_triggers.ts" + ], + "expectations": [ + { + "files": [ + { + "expected": "deferred_with_prefetch_triggers_template.js", + "generated": "deferred_with_prefetch_triggers.js" + } + ], + "failureMessage": "Incorrect template" + } + ], + "skipForTemplatePipeline": true } ] } diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/basic_deferred_template.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/basic_deferred_template.js index ee2daf442d3b7..d28a3a68387d3 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/basic_deferred_template.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/basic_deferred_template.js @@ -12,6 +12,7 @@ MyApp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({ $r3$.ɵɵtext(1); $r3$.ɵɵtemplate(2, MyApp_Defer_2_Template, 1, 0); $r3$.ɵɵdefer(3, 2); + $r3$.ɵɵdeferOnIdle(); $r3$.ɵɵelementEnd(); } if (rf & 2) { diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_secondary_blocks_template.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_secondary_blocks_template.js index f3a3b67b750dd..71fbdd4ef10a9 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_secondary_blocks_template.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_secondary_blocks_template.js @@ -43,6 +43,7 @@ MyApp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({ $r3$.ɵɵtemplate(4, MyApp_DeferPlaceholder_4_Template, 1, 0); $r3$.ɵɵtemplate(5, MyApp_DeferError_5_Template, 3, 0); $r3$.ɵɵdefer(6, 2, null, 3, 4, 5); + $r3$.ɵɵdeferOnIdle(); $r3$.ɵɵelementEnd(); } if (rf & 2) { diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_external_deps_template.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_external_deps_template.js index 5bff4a9330a60..65df1231109cf 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_external_deps_template.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_external_deps_template.js @@ -29,6 +29,7 @@ MyApp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({ $r3$.ɵɵtemplate(2, MyApp_Defer_2_Template, 1, 0); $r3$.ɵɵtemplate(3, MyApp_DeferLoading_3_Template, 1, 0); $r3$.ɵɵdefer(4, 2, MyApp_Defer_4_DepsFn, 3); + $r3$.ɵɵdeferOnIdle(); $r3$.ɵɵelementEnd(); } }, diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_loading_params_template.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_loading_params_template.js index c09fa69fc65cf..7f63cd93194b9 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_loading_params_template.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_loading_params_template.js @@ -18,6 +18,7 @@ MyApp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({ $r3$.ɵɵtemplate(0, MyApp_Defer_0_Template, 1, 0); $r3$.ɵɵtemplate(1, MyApp_DeferLoading_1_Template, 1, 0); $r3$.ɵɵdefer(2, 0, null, 1, null, null, 0); + $r3$.ɵɵdeferOnIdle(); } }, … diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_local_deps_template.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_local_deps_template.js index e370a32f677bc..f6947bbe407ec 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_local_deps_template.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_local_deps_template.js @@ -11,6 +11,7 @@ MyApp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({ $r3$.ɵɵtemplate(2, MyApp_Defer_2_Template, 1, 0); $r3$.ɵɵtemplate(3, MyApp_DeferLoading_3_Template, 1, 0); $r3$.ɵɵdefer(4, 2, MyApp_Defer_4_DepsFn, 3); + $r3$.ɵɵdeferOnIdle(); $r3$.ɵɵelementEnd(); } }, diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_placeholder_params_template.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_placeholder_params_template.js index 81970c7944dbd..3c406e4a81a4a 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_placeholder_params_template.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_placeholder_params_template.js @@ -18,6 +18,7 @@ MyApp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({ $r3$.ɵɵtemplate(0, MyApp_Defer_0_Template, 1, 0); $r3$.ɵɵtemplate(1, MyApp_DeferPlaceholder_1_Template, 1, 0); $r3$.ɵɵdefer(2, 0, null, null, 1, null, null, 0); + $r3$.ɵɵdeferOnIdle(); } }, … diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_prefetch_triggers.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_prefetch_triggers.ts new file mode 100644 index 0000000000000..ec3d15930f636 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_prefetch_triggers.ts @@ -0,0 +1,20 @@ +import {Component} from '@angular/core'; + +@Component({ + template: ` + {{message}} + {#defer prefetch when isVisible() || isReady; prefetch on idle, timer(1337); + prefetch on immediate, hover; prefetch on interaction(button); prefetch on viewport(button)} + {{message}} + {:placeholder} + {/defer} + `, +}) +export class MyApp { + message = 'hello'; + isReady = true; + + isVisible() { + return false; + } +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_prefetch_triggers_template.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_prefetch_triggers_template.js new file mode 100644 index 0000000000000..d621828afae8e --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_prefetch_triggers_template.js @@ -0,0 +1,20 @@ +function MyApp_Template(rf, ctx) { + if (rf & 1) { + $r3$.ɵɵtext(0); + $r3$.ɵɵtemplate(1, MyApp_Defer_1_Template, 1, 1); + $r3$.ɵɵtemplate(2, MyApp_DeferPlaceholder_2_Template, 3, 0); + $r3$.ɵɵdefer(3, 1, null, null, 2); + $r3$.ɵɵdeferOnIdle(); + $r3$.ɵɵdeferPrefetchOnIdle(); + $r3$.ɵɵdeferPrefetchOnImmediate(); + $r3$.ɵɵdeferPrefetchOnTimer(1337); + $r3$.ɵɵdeferPrefetchOnHover(); + $r3$.ɵɵdeferPrefetchOnInteraction("button"); + $r3$.ɵɵdeferPrefetchOnViewport("button"); + } + if (rf & 2) { + $r3$.ɵɵtextInterpolate1(" ", ctx.message, " "); + $r3$.ɵɵadvance(3); + $r3$.ɵɵdeferPrefetchWhen(ctx.isVisible() || ctx.isReady); + } +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_triggers.ts b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_triggers.ts new file mode 100644 index 0000000000000..9c29252d42889 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_triggers.ts @@ -0,0 +1,20 @@ +import {Component} from '@angular/core'; + +@Component({ + template: ` + {{message}} + {#defer when isVisible() || isReady; on idle, timer(1337); on immediate, hover; + on interaction(button); on viewport(button)} + {{message}} + {:placeholder} + {/defer} + `, +}) +export class MyApp { + message = 'hello'; + isReady = true; + + isVisible() { + return false; + } +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_triggers_template.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_triggers_template.js new file mode 100644 index 0000000000000..032c4a5072129 --- /dev/null +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/deferred_with_triggers_template.js @@ -0,0 +1,19 @@ +function MyApp_Template(rf, ctx) { + if (rf & 1) { + $r3$.ɵɵtext(0); + $r3$.ɵɵtemplate(1, MyApp_Defer_1_Template, 1, 1); + $r3$.ɵɵtemplate(2, MyApp_DeferPlaceholder_2_Template, 3, 0); + $r3$.ɵɵdefer(3, 1, null, null, 2); + $r3$.ɵɵdeferOnIdle(); + $r3$.ɵɵdeferOnImmediate(); + $r3$.ɵɵdeferOnTimer(1337); + $r3$.ɵɵdeferOnHover(); + $r3$.ɵɵdeferOnInteraction("button"); + $r3$.ɵɵdeferOnViewport("button"); + } + if (rf & 2) { + $r3$.ɵɵtextInterpolate1(" ", ctx.message, " "); + $r3$.ɵɵadvance(3); + $r3$.ɵɵdeferWhen(ctx.isVisible() || ctx.isReady); + } +} diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts index 1d8fb62f378cb..240889d9a2f5a 100644 --- a/packages/compiler/src/render3/r3_identifiers.ts +++ b/packages/compiler/src/render3/r3_identifiers.ts @@ -140,6 +140,26 @@ export class Identifiers { static templateCreate: o.ExternalReference = {name: 'ɵɵtemplate', moduleName: CORE}; static defer: o.ExternalReference = {name: 'ɵɵdefer', moduleName: CORE}; + static deferWhen: o.ExternalReference = {name: 'ɵɵdeferWhen', moduleName: CORE}; + static deferOnIdle: o.ExternalReference = {name: 'ɵɵdeferOnIdle', moduleName: CORE}; + static deferOnImmediate: o.ExternalReference = {name: 'ɵɵdeferOnImmediate', moduleName: CORE}; + static deferOnTimer: o.ExternalReference = {name: 'ɵɵdeferOnTimer', moduleName: CORE}; + static deferOnHover: o.ExternalReference = {name: 'ɵɵdeferOnHover', moduleName: CORE}; + static deferOnInteraction: o.ExternalReference = {name: 'ɵɵdeferOnInteraction', moduleName: CORE}; + static deferOnViewport: o.ExternalReference = {name: 'ɵɵdeferOnViewport', moduleName: CORE}; + static deferPrefetchWhen: o.ExternalReference = {name: 'ɵɵdeferPrefetchWhen', moduleName: CORE}; + static deferPrefetchOnIdle: + o.ExternalReference = {name: 'ɵɵdeferPrefetchOnIdle', moduleName: CORE}; + static deferPrefetchOnImmediate: + o.ExternalReference = {name: 'ɵɵdeferPrefetchOnImmediate', moduleName: CORE}; + static deferPrefetchOnTimer: + o.ExternalReference = {name: 'ɵɵdeferPrefetchOnTimer', moduleName: CORE}; + static deferPrefetchOnHover: + o.ExternalReference = {name: 'ɵɵdeferPrefetchOnHover', moduleName: CORE}; + static deferPrefetchOnInteraction: + o.ExternalReference = {name: 'ɵɵdeferPrefetchOnInteraction', moduleName: CORE}; + static deferPrefetchOnViewport: + o.ExternalReference = {name: 'ɵɵdeferPrefetchOnViewport', moduleName: CORE}; static text: o.ExternalReference = {name: 'ɵɵtext', moduleName: CORE}; diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index e21f57a8b1aff..b387fa0724f10 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -1089,7 +1089,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver } visitDeferredBlock(deferred: t.DeferredBlock): void { - const {loading, placeholder, error} = deferred; + const {loading, placeholder, error, triggers, prefetchTriggers} = deferred; const primaryTemplateIndex = this.createEmbeddedTemplateFn(null, deferred.children, '_Defer', deferred.sourceSpan); const loadingIndex = loading ? @@ -1117,7 +1117,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver const deferredIndex = this.allocateDataSlot(); const depsFnName = `${this.contextName}_Defer_${deferredIndex}_DepsFn`; - // e.g. `defer(1, MyComp_Defer_1_DepsFn, ...)` + // e.g. `defer(1, 0, MyComp_Defer_1_DepsFn, ...)` this.creationInstruction( deferred.sourceSpan, R3.defer, trimTrailingNulls([ o.literal(deferredIndex), @@ -1130,7 +1130,8 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver placeholderConsts ? this.addToConsts(placeholderConsts) : o.TYPED_NULL_EXPR, ])); - // TODO(crisbeto): generate trigger instructions + this.createDeferTriggerInstructions(deferredIndex, triggers, false); + this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, true); } private createDeferredDepsFunction(name: string, deferred: t.DeferredBlock) { @@ -1168,6 +1169,68 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver return o.variable(name); } + private createDeferTriggerInstructions( + deferredIndex: number, triggers: t.DeferredBlockTriggers, prefetch: boolean) { + const {when, idle, immediate, timer, hover, interaction, viewport} = triggers; + + // `deferWhen(ctx.someValue)` + if (when) { + this.allocateBindingSlots(null); + this.updateInstructionWithAdvance( + deferredIndex, when.sourceSpan, prefetch ? R3.deferPrefetchWhen : R3.deferWhen, + () => this.convertPropertyBinding(when.value)); + } + + // Note that we generate an implicit `on idle` if the `deferred` block has no triggers. + // TODO(crisbeto): decide if this should be baked into the `defer` instruction. + // `deferOnIdle()` + if (idle || (!prefetch && Object.keys(triggers).length === 0)) { + this.creationInstruction( + idle?.sourceSpan || null, prefetch ? R3.deferPrefetchOnIdle : R3.deferOnIdle); + } + + // `deferOnImmediate()` + if (immediate) { + this.creationInstruction( + immediate.sourceSpan, prefetch ? R3.deferPrefetchOnImmediate : R3.deferOnImmediate); + } + + // `deferOnTimer(1337)` + if (timer) { + this.creationInstruction( + timer.sourceSpan, prefetch ? R3.deferPrefetchOnTimer : R3.deferOnTimer, + [o.literal(timer.delay)]); + } + + // `deferOnHover()` + if (hover) { + this.creationInstruction( + hover.sourceSpan, prefetch ? R3.deferPrefetchOnHover : R3.deferOnHover); + } + + // TODO(crisbeto): currently the reference is passed as a string. + // Update this once we figure out how we should refer to the target. + // `deferOnInteraction(target)` + if (interaction) { + this.creationInstruction( + interaction.sourceSpan, prefetch ? R3.deferPrefetchOnInteraction : R3.deferOnInteraction, + [o.literal(interaction.reference)]); + } + + // TODO(crisbeto): currently the reference is passed as a string. + // Update this once we figure out how we should refer to the target. + // `deferOnViewport(target)` + if (viewport) { + this.creationInstruction( + viewport.sourceSpan, prefetch ? R3.deferPrefetchOnViewport : R3.deferOnViewport, + [o.literal(viewport.reference)]); + } + } + + private allocateDataSlot() { + return this._dataIndex++; + } + // TODO: implement control flow instructions visitSwitchBlock(block: t.SwitchBlock): void {} visitSwitchBlockCase(block: t.SwitchBlockCase): void {} @@ -1176,10 +1239,6 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver visitIfBlock(block: t.IfBlock): void {} visitIfBlockBranch(block: t.IfBlockBranch): void {} - private allocateDataSlot() { - return this._dataIndex++; - } - getConstCount() { return this._dataIndex; } diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 429c8153a784d..8a70800053560 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -199,6 +199,20 @@ export { ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵdefer, + ɵɵdeferWhen, + ɵɵdeferOnIdle, + ɵɵdeferOnImmediate, + ɵɵdeferOnTimer, + ɵɵdeferOnHover, + ɵɵdeferOnInteraction, + ɵɵdeferOnViewport, + ɵɵdeferPrefetchWhen, + ɵɵdeferPrefetchOnIdle, + ɵɵdeferPrefetchOnImmediate, + ɵɵdeferPrefetchOnTimer, + ɵɵdeferPrefetchOnHover, + ɵɵdeferPrefetchOnInteraction, + ɵɵdeferPrefetchOnViewport, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 4e623437bc3a5..2547079734abb 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -119,6 +119,20 @@ export { ɵɵtemplate, ɵɵdefer, + ɵɵdeferWhen, + ɵɵdeferOnIdle, + ɵɵdeferOnImmediate, + ɵɵdeferOnTimer, + ɵɵdeferOnHover, + ɵɵdeferOnInteraction, + ɵɵdeferOnViewport, + ɵɵdeferPrefetchWhen, + ɵɵdeferPrefetchOnIdle, + ɵɵdeferPrefetchOnImmediate, + ɵɵdeferPrefetchOnTimer, + ɵɵdeferPrefetchOnHover, + ɵɵdeferPrefetchOnInteraction, + ɵɵdeferPrefetchOnViewport, ɵɵtext, ɵɵtextInterpolate, diff --git a/packages/core/src/render3/instructions/defer.ts b/packages/core/src/render3/instructions/defer.ts index 6c6f5cc9763c4..3e9b3eebb23ae 100644 --- a/packages/core/src/render3/instructions/defer.ts +++ b/packages/core/src/render3/instructions/defer.ts @@ -42,3 +42,94 @@ export function ɵɵdefer( loadingConfigIndex?: number|null, placeholderConfigIndex?: number|null, ) {} // TODO: implement runtime logic. + +/** + * Loads the deferred content when a value becomes truthy. + * @codeGenApi + */ +export function ɵɵdeferWhen(value: unknown) {} // TODO: implement runtime logic. + +/** + * Prefetches the deferred content when a value becomes truthy. + * @codeGenApi + */ +export function ɵɵdeferPrefetchWhen(value: unknown) {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `on idle` deferred trigger. + * @codeGenApi + */ +export function ɵɵdeferOnIdle() {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `prefetech on idle` deferred trigger. + * @codeGenApi + */ +export function ɵɵdeferPrefetchOnIdle() {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `on immediate` deferred trigger. + * @codeGenApi + */ +export function ɵɵdeferOnImmediate() {} // TODO: implement runtime logic. + + +/** + * Creates runtime data structures for the `prefetech on immediate` deferred trigger. + * @codeGenApi + */ +export function ɵɵdeferPrefetchOnImmediate() {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `on timer` deferred trigger. + * @param delay Amount of time to wait before loading the content. + * @codeGenApi + */ +export function ɵɵdeferOnTimer(delay: number) {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `prefetch on timer` deferred trigger. + * @param delay Amount of time to wait before prefetching the content. + * @codeGenApi + */ +export function ɵɵdeferPrefetchOnTimer(delay: number) {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `on hover` deferred trigger. + * @codeGenApi + */ +export function ɵɵdeferOnHover() {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `prefetech on hover` deferred trigger. + * @codeGenApi + */ +export function ɵɵdeferPrefetchOnHover() {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `on interaction` deferred trigger. + * @param target Optional element on which to listen for hover events. + * @codeGenApi + */ +export function ɵɵdeferOnInteraction(target?: unknown) {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `prefetch on interaction` deferred trigger. + * @param target Optional element on which to listen for hover events. + * @codeGenApi + */ +export function ɵɵdeferPrefetchOnInteraction(target?: unknown) {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `on viewport` deferred trigger. + * @param target Optional element on which to listen for hover events. + * @codeGenApi + */ +export function ɵɵdeferOnViewport(target?: unknown) {} // TODO: implement runtime logic. + +/** + * Creates runtime data structures for the `prefetch on viewport` deferred trigger. + * @param target Optional element on which to listen for hover events. + * @codeGenApi + */ +export function ɵɵdeferPrefetchOnViewport(target?: unknown) {} // TODO: implement runtime logic. diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts index 47ae6f8680de5..5f5251f2618c6 100644 --- a/packages/core/src/render3/jit/environment.ts +++ b/packages/core/src/render3/jit/environment.ts @@ -139,6 +139,20 @@ export const angularCoreEnv: {[name: string]: Function} = 'ɵɵadvance': r3.ɵɵadvance, 'ɵɵtemplate': r3.ɵɵtemplate, 'ɵɵdefer': r3.ɵɵdefer, + 'ɵɵdeferWhen': r3.ɵɵdeferWhen, + 'ɵɵdeferOnIdle': r3.ɵɵdeferOnIdle, + 'ɵɵdeferOnImmediate': r3.ɵɵdeferOnImmediate, + 'ɵɵdeferOnTimer': r3.ɵɵdeferOnTimer, + 'ɵɵdeferOnHover': r3.ɵɵdeferOnHover, + 'ɵɵdeferOnInteraction': r3.ɵɵdeferOnInteraction, + 'ɵɵdeferOnViewport': r3.ɵɵdeferOnViewport, + 'ɵɵdeferPrefetchWhen': r3.ɵɵdeferPrefetchWhen, + 'ɵɵdeferPrefetchOnIdle': r3.ɵɵdeferPrefetchOnIdle, + 'ɵɵdeferPrefetchOnImmediate': r3.ɵɵdeferPrefetchOnImmediate, + 'ɵɵdeferPrefetchOnTimer': r3.ɵɵdeferPrefetchOnTimer, + 'ɵɵdeferPrefetchOnHover': r3.ɵɵdeferPrefetchOnHover, + 'ɵɵdeferPrefetchOnInteraction': r3.ɵɵdeferPrefetchOnInteraction, + 'ɵɵdeferPrefetchOnViewport': r3.ɵɵdeferPrefetchOnViewport, 'ɵɵtext': r3.ɵɵtext, 'ɵɵtextInterpolate': r3.ɵɵtextInterpolate, 'ɵɵtextInterpolate1': r3.ɵɵtextInterpolate1,