mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
fix(compiler-cli): insert constant statements after the first group of imports (#56431)
The linker inserts the constant statements that are needed to support compiled templates after the import statements of an ESM file, but it failed to account for import statements that are not at the top of the file. This is typically seen in FESM files where multiple individual ESMs have been concatenated into a single ESM file, with imports in various places. The linker would then find the very last import statement to insert the constant statements after, but this may result in TDZ errors for component templates that have been emitted earlier in the file. This commit updates the Babel linker plugin to insert constant statements after the last import of the first import group, therefore avoiding the TDZ error. Fixes #56403 PR Close #56431
This commit is contained in:
parent
571d06b6c3
commit
ec0d1bf6f3
2 changed files with 29 additions and 11 deletions
|
|
@ -134,11 +134,12 @@ function insertIntoFunction(
|
|||
*/
|
||||
function insertIntoProgram(program: NodePath<t.Program>, statements: t.Statement[]): void {
|
||||
const body = program.get('body');
|
||||
const importStatements = body.filter((statement) => statement.isImportDeclaration());
|
||||
if (importStatements.length === 0) {
|
||||
const insertBeforeIndex = body.findIndex((statement) => !statement.isImportDeclaration());
|
||||
|
||||
if (insertBeforeIndex === -1) {
|
||||
program.unshiftContainer('body', statements);
|
||||
} else {
|
||||
importStatements[importStatements.length - 1].insertAfter(statements);
|
||||
body[insertBeforeIndex].insertBefore(statements);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ describe('createEs2015LinkerPlugin()', () => {
|
|||
);
|
||||
const fileSystem = new MockFileSystemNative();
|
||||
const logger = new MockLogger();
|
||||
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
|
||||
|
||||
babel.transformSync(
|
||||
[
|
||||
|
|
@ -115,7 +114,6 @@ describe('createEs2015LinkerPlugin()', () => {
|
|||
);
|
||||
const fileSystem = new MockFileSystemNative();
|
||||
const logger = new MockLogger();
|
||||
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
|
||||
const result = babel.transformSync(
|
||||
[
|
||||
'var core;',
|
||||
|
|
@ -138,7 +136,6 @@ describe('createEs2015LinkerPlugin()', () => {
|
|||
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
|
||||
const fileSystem = new MockFileSystemNative();
|
||||
const logger = new MockLogger();
|
||||
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
|
||||
const result = babel.transformSync(
|
||||
[
|
||||
"import * as core from 'some-module';",
|
||||
|
|
@ -159,11 +156,35 @@ describe('createEs2015LinkerPlugin()', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should return a Babel plugin that adds shared statements after the first group of imports', () => {
|
||||
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
|
||||
const fileSystem = new MockFileSystemNative();
|
||||
const logger = new MockLogger();
|
||||
const result = babel.transformSync(
|
||||
[
|
||||
"import * as core from 'some-module';",
|
||||
"import {id} from 'other-module';",
|
||||
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
|
||||
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
|
||||
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core})`,
|
||||
"import {second} from 'second-module';",
|
||||
].join('\n'),
|
||||
{
|
||||
plugins: [createEs2015LinkerPlugin({fileSystem, logger})],
|
||||
filename: '/test.js',
|
||||
parserOpts: {sourceType: 'unambiguous'},
|
||||
generatorOpts: {compact: true},
|
||||
},
|
||||
);
|
||||
expect(result!.code).toEqual(
|
||||
'import*as core from\'some-module\';import{id}from\'other-module\';const _c0=[1];const _c1=[2];const _c2=[3];"REPLACEMENT";"REPLACEMENT";"REPLACEMENT";import{second}from\'second-module\';',
|
||||
);
|
||||
});
|
||||
|
||||
it('should return a Babel plugin that adds shared statements at the start of the program if it is an ECMAScript Module and there are no imports', () => {
|
||||
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
|
||||
const fileSystem = new MockFileSystemNative();
|
||||
const logger = new MockLogger();
|
||||
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
|
||||
const result = babel.transformSync(
|
||||
[
|
||||
'var core;',
|
||||
|
|
@ -188,7 +209,6 @@ describe('createEs2015LinkerPlugin()', () => {
|
|||
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
|
||||
const fileSystem = new MockFileSystemNative();
|
||||
const logger = new MockLogger();
|
||||
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
|
||||
const result = babel.transformSync(
|
||||
[
|
||||
'function run(core) {',
|
||||
|
|
@ -213,7 +233,6 @@ describe('createEs2015LinkerPlugin()', () => {
|
|||
spyOnLinkPartialDeclarationWithConstants(o.literal('REPLACEMENT'));
|
||||
const fileSystem = new MockFileSystemNative();
|
||||
const logger = new MockLogger();
|
||||
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
|
||||
const result = babel.transformSync(
|
||||
[
|
||||
'function run() {',
|
||||
|
|
@ -244,7 +263,6 @@ describe('createEs2015LinkerPlugin()', () => {
|
|||
spyOnLinkPartialDeclarationWithConstants(o.fn([], [], null, null, 'FOO'));
|
||||
const fileSystem = new MockFileSystemNative();
|
||||
const logger = new MockLogger();
|
||||
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
|
||||
const result = babel.transformSync(
|
||||
[
|
||||
`ɵɵngDeclareDirective({minVersion: '0.0.0-PLACEHOLDER', version: '0.0.0-PLACEHOLDER', ngImport: core}); FOO;`,
|
||||
|
|
@ -298,7 +316,6 @@ describe('createEs2015LinkerPlugin()', () => {
|
|||
|
||||
const fileSystem = new MockFileSystemNative();
|
||||
const logger = new MockLogger();
|
||||
const plugin = createEs2015LinkerPlugin({fileSystem, logger});
|
||||
const result = babel.transformSync(
|
||||
[
|
||||
"import * as core from 'some-module';",
|
||||
|
|
|
|||
Loading…
Reference in a new issue