Skip to content

Commit

Permalink
fix(compiler-cli): use correct symbol name for default imported symbo…
Browse files Browse the repository at this point in the history
…ls in defer blocks (#54495)

This commit addresses a problem with PR #53695 that introduced support for default imports,
where the actual dynamic import used in the defer loading function continued to use the
symbol name, instead of `.default` for the dynamic import. This issue went unnoticed in the
testcase because a proper instance was being generated for the `ɵsetClassMetadataAsync` function,
but not the generated dependency loader function.

Fixes #54491

PR Close #54495
  • Loading branch information
JoostK authored and alxhub committed Feb 20, 2024
1 parent 5e80e6d commit 790f4f7
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1275,9 +1275,10 @@ export class ComponentDecoratorHandler implements
if (importDecl !== null && this.deferredSymbolTracker.canDefer(importDecl)) {
deferBlockDep.isDeferrable = true;
deferBlockDep.importPath = (importDecl.moduleSpecifier as ts.StringLiteral).text;
deferBlockDep.isDefaultImport = isDefaultImport(importDecl);
deferrableTypes.set(deferBlockDep.symbolName, {
importPath: deferBlockDep.importPath,
isDefaultImport: isDefaultImport(importDecl),
isDefaultImport: deferBlockDep.isDefaultImport,
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,85 @@ export declare class TestCmp {
static ɵcmp: i0.ɵɵComponentDeclaration<TestCmp, "test-cmp", never, {}, {}, never, never, true, never>;
}

/****************************************************************************************************
* PARTIAL FILE: defer_default_deps_ext.js
****************************************************************************************************/
import { Component } from '@angular/core';
import * as i0 from "@angular/core";
class CmpA {
}
CmpA.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: CmpA, deps: [], target: i0.ɵɵFactoryTarget.Component });
CmpA.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: CmpA, isStandalone: true, selector: "cmp-a", ngImport: i0, template: 'CmpA!', isInline: true });
export default CmpA;
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: CmpA, decorators: [{
type: Component,
args: [{ standalone: true, selector: 'cmp-a', template: 'CmpA!' }]
}] });

/****************************************************************************************************
* PARTIAL FILE: defer_default_deps_ext.d.ts
****************************************************************************************************/
import * as i0 from "@angular/core";
export default class CmpA {
static ɵfac: i0.ɵɵFactoryDeclaration<CmpA, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<CmpA, "cmp-a", never, {}, {}, never, never, true, never>;
}

/****************************************************************************************************
* PARTIAL FILE: defer_default_deps.js
****************************************************************************************************/
import { Component } from '@angular/core';
import CmpA from './defer_default_deps_ext';
import * as i0 from "@angular/core";
export class LocalDep {
}
LocalDep.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: LocalDep, deps: [], target: i0.ɵɵFactoryTarget.Component });
LocalDep.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: LocalDep, isStandalone: true, selector: "local-dep", ngImport: i0, template: 'Local dependency', isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: LocalDep, decorators: [{
type: Component,
args: [{
selector: 'local-dep',
standalone: true,
template: 'Local dependency',
}]
}] });
export class TestCmp {
}
TestCmp.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestCmp, deps: [], target: i0.ɵɵFactoryTarget.Component });
TestCmp.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "0.0.0-PLACEHOLDER", type: TestCmp, isStandalone: true, selector: "test-cmp", ngImport: i0, template: `
@defer {
<cmp-a />
<local-dep />
}
`, isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: TestCmp, decorators: [{
type: Component,
args: [{
selector: 'test-cmp',
standalone: true,
imports: [CmpA, LocalDep],
template: `
@defer {
<cmp-a />
<local-dep />
}
`,
}]
}] });

/****************************************************************************************************
* PARTIAL FILE: defer_default_deps.d.ts
****************************************************************************************************/
import * as i0 from "@angular/core";
export declare class LocalDep {
static ɵfac: i0.ɵɵFactoryDeclaration<LocalDep, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<LocalDep, "local-dep", never, {}, {}, never, never, true, never>;
}
export declare class TestCmp {
static ɵfac: i0.ɵɵFactoryDeclaration<TestCmp, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<TestCmp, "test-cmp", never, {}, {}, never, never, true, never>;
}

/****************************************************************************************************
* PARTIAL FILE: lazy_with_blocks.js
****************************************************************************************************/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,22 @@
}
]
},
{
"description": "should generate a deferred block with default imports",
"inputFiles": ["defer_default_deps.ts", "defer_default_deps_ext.ts"],
"compilationModeFilter": ["full compile"],
"expectations": [
{
"files": [
{
"expected": "defer_default_deps_template.js",
"generated": "defer_default_deps.js"
}
],
"failureMessage": "Incorrect template"
}
]
},
{
"description": "should generate a lazy deferred block with empty and placeholder",
"inputFiles": ["lazy_with_blocks.ts"],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {Component} from '@angular/core';

import CmpA from './defer_default_deps_ext';

@Component({
selector: 'local-dep',
standalone: true,
template: 'Local dependency',
})
export class LocalDep {
}

@Component({
selector: 'test-cmp',
standalone: true,
imports: [CmpA, LocalDep],
template: `
@defer {
<cmp-a />
<local-dep />
}
`,
})
export class TestCmp {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {Component} from '@angular/core';

@Component({standalone: true, selector: 'cmp-a', template: 'CmpA!'})
export default class CmpA {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const $TestCmp_Defer_1_DepsFn$ = () => [import("./defer_default_deps_ext").then(m => m.default), LocalDep];

function TestCmp_Defer_0_Template(rf, ctx) {
if (rf & 1) {
i0.ɵɵelement(0, "cmp-a")(1, "local-dep");
}
}

export class LocalDep {
}


function TestCmp_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵtemplate(0, TestCmp_Defer_0_Template, 2, 0);
i0.ɵɵdefer(1, 0, $TestCmp_Defer_1_DepsFn$);
i0.ɵɵdeferOnIdle();
} }
7 changes: 6 additions & 1 deletion packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9602,7 +9602,12 @@ function allTests(os: string) {
const jsContents = env.getContents('test.js');

expect(jsContents).toContain('ɵɵdefer(1, 0, TestCmp_Defer_1_DepsFn)');
expect(jsContents).toContain('() => [import("./cmp-a").then(m => m.default)]');
expect(jsContents)
.toContain(
'const TestCmp_Defer_1_DepsFn = () => [import("./cmp-a").then(m => m.default), LocalDep];');
expect(jsContents)
.toContain(
'i0.ɵsetClassMetadataAsync(TestCmp, () => [import("./cmp-a").then(m => m.default)]');

// The `CmpA` symbol wasn't referenced elsewhere, so it can be defer-loaded
// via dynamic imports and an original import can be removed.
Expand Down

0 comments on commit 790f4f7

Please sign in to comment.