Skip to content

Commit 8d7f109

Browse files
devversiondylhunn
authored andcommitted
refactor: make all imports compatible with ESM/CJS output. (angular#43431)
As outlined in the previous commit which enabled the `esModuleInterop` TypeScript compiler option, we need to update all namespace imports for `typescript` to default imports. This is needed to allow for TypeScript to be imported at runtime from an ES module. Similar changes are needed for modules like `semver` where the types incorrectly suggest named exports that will not exist at runtime when imported from ESM. This commit refactors all imports to match with the lint rule we have configured in the previous commit. See the previous commit for more details on why certain imports have been changed. A special case are the imports to `@babel/core` and `@babel/types`. For these a special interop is needed as both default imports, or named imports break the other module format. e.g default imports would work well for ESM, but it breaks for CJS. For CJS, the named imports would only work, but in ESM, only the default export exist. We work around this for now until the devmode is using ESM as well (which would be consistent with prodmode and gives us more valuable test results). More details on the interop can be found in the `babel_core.ts` files (two interops are needed for both localize/or the compiler-cli). PR Close angular#43431
1 parent d15a692 commit 8d7f109

File tree

471 files changed

+691
-583
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

471 files changed

+691
-583
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
"@babel/preset-env": "7.10.2",
6262
"@babel/template": "7.8.6",
6363
"@babel/traverse": "7.8.6",
64-
"@babel/types": "7.8.6",
6564
"@bazel/concatjs": "4.3.0",
6665
"@bazel/esbuild": "4.3.0",
6766
"@bazel/jasmine": "4.3.0",

packages/bazel/src/ngc-wrapped/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {BazelOptions, CachedFileLoader, CompilerHost, constructManifest, debug,
1212
import * as fs from 'fs';
1313
import * as path from 'path';
1414
import * as tsickle from 'tsickle';
15-
import * as ts from 'typescript';
15+
import ts from 'typescript';
1616

1717
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
1818
const NGC_GEN_FILES = /^(.*?)\.(ngfactory|ngsummary|ngstyle|shim\.ngstyle)(.*)$/;

packages/bazel/test/ngc-wrapped/test_support.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import {runOneBuild} from '@angular/bazel';
1010
import * as fs from 'fs';
1111
import * as path from 'path';
12-
import * as ts from 'typescript';
12+
import ts from 'typescript';
1313

1414
import {createTsConfig} from './tsconfig_template';
1515

packages/common/locales/generate-locales-tool/cldr-data.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import {runfiles} from '@bazel/runfiles';
1010
import {CldrStatic} from 'cldrjs';
11-
import {sync as globSync} from 'glob';
11+
import glob from 'glob';
1212

1313
// TypeScript doesn't allow us to import the default export without the `esModuleInterop`. We use
1414
// the NodeJS require function instead as specifying a custom tsconfig complicates the setup
@@ -141,7 +141,7 @@ export class CldrData {
141141
*/
142142
private _readCldrDataFromRepository(): object[] {
143143
const jsonFiles =
144-
CLDR_DATA_GLOBS.map(pattern => globSync(pattern, {cwd: this.cldrDataDir, absolute: true}))
144+
CLDR_DATA_GLOBS.map(pattern => glob.sync(pattern, {cwd: this.cldrDataDir, absolute: true}))
145145
.reduce((acc, dataFiles) => [...acc, ...dataFiles], []);
146146

147147
// Read the JSON for all determined CLDR json files.

packages/compiler-cli/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ esbuild(
4242
"@angular/compiler",
4343
"typescript",
4444
"@babel/core",
45-
"@babel/types",
4645
"reflect-metadata",
4746
"minimist",
4847
"canonical-path",

packages/compiler-cli/linker/babel/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ ts_library(
1414
"//packages/compiler-cli/src/ngtsc/logging",
1515
"//packages/compiler-cli/src/ngtsc/translator",
1616
"@npm//@babel/core",
17-
"@npm//@babel/types",
1817
"@npm//@types/babel__core",
1918
"@npm//@types/babel__traverse",
2019
],

packages/compiler-cli/linker/babel/src/ast/babel_ast_factory.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import * as t from '@babel/types';
9-
108
import {assert} from '../../../../linker';
119
import {AstFactory, BinaryOperator, LeadingComment, ObjectLiteralProperty, SourceMapRange, TemplateLiteral, VariableDeclarationType} from '../../../../src/ngtsc/translator';
10+
import {types as t} from '../babel_core';
1211

1312
/**
1413
* A Babel flavored implementation of the AstFactory.

packages/compiler-cli/linker/babel/src/ast/babel_ast_host.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import * as t from '@babel/types';
10-
119
import {assert, AstHost, FatalLinkerError, Range} from '../../../../linker';
10+
import {types as t} from '../babel_core';
1211

1312
/**
1413
* This implementation of `AstHost` is able to get information from Babel AST nodes.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/**
10+
* This is an interop file allowing for `@babel/core` to be imported in both CommonJS or
11+
* ES module files. The `@babel/core` package needs some special treatment because:
12+
*
13+
* Using a default import does not with CommonJS because the `@babel/core` package does not
14+
* expose a `default` export at runtime (because it sets the `_esModule` property that causes
15+
* TS to not create the necessary interop `default` export). On the other side, when loaded
16+
* as part of an ESM, NodeJS will make all of the exports available as default export.
17+
*
18+
* Using named import bindings (i.e. namespace import or actual named bindings) is not
19+
* working well for ESM because as said before, NodeJS will make all of the exports available
20+
* as the `default` export. Hence ESM that imports CJS, always should use the default import.
21+
*
22+
* There is no solution that would work for both CJS and ESM, so we need to use a custom interop
23+
* that switches between the named exports or the default exports depending on what is available.
24+
* This allows the code to run in both ESM (for production) and CJS (for development).
25+
*
26+
* TODO(devversion): remove this once devmode uses ESM as well.
27+
*/
28+
29+
// tslint:disable-next-line
30+
import * as _babelNamespace from '@babel/core';
31+
// tslint:disable-next-line
32+
import _babelDefault from '@babel/core';
33+
34+
const babel: typeof _babelNamespace = _babelDefault ?? _babelNamespace;
35+
36+
// We create an alias of the `types` namespace so that we can re-export the
37+
// types namespace. Preserving the namespace is important so that types
38+
// can still be referenced using a qualified name.
39+
import _typesNamespace = _babelNamespace.types;
40+
41+
// If the default export is available, we use its `types` runtime value
42+
// for the type namespace we re-export. This is a trick we use to preserve
43+
// the namespace types, while changing the runtime value of the namespace.
44+
// TS complains about us assigning to a namespace but this is legal at runtime.
45+
if (_babelDefault !== undefined) {
46+
// @ts-ignore
47+
_typesNamespace = _babelDefault.types;
48+
}
49+
50+
export import types = _typesNamespace;
51+
export type PluginObj = _babelNamespace.PluginObj;
52+
export type ConfigAPI = _babelNamespace.ConfigAPI;
53+
export type NodePath<T = _babelNamespace.Node> = _babelNamespace.NodePath<T>;
54+
55+
export const NodePath: typeof _babelNamespace.NodePath = babel.NodePath;
56+
export const transformSync: typeof _babelNamespace.transformSync = babel.transformSync;
57+
export const parse: typeof _babelNamespace.parse = babel.parse;

packages/compiler-cli/linker/babel/src/babel_declaration_scope.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import {NodePath, Scope} from '@babel/traverse';
9-
import * as t from '@babel/types';
109

1110
import {DeclarationScope} from '../../../linker';
1211

12+
import {types as t} from './babel_core';
13+
1314
export type ConstantScopePath = NodePath<t.Function|t.Program>;
1415

1516
/**

0 commit comments

Comments
 (0)