Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: produce bundle indexes for @angular modules #14509

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions integration/hello_world__closure/bundle.sh
Expand Up @@ -35,6 +35,7 @@ CLOSURE_ARGS=(
node_modules/zone.js/dist/zone.js
$(find -L vendor/rxjs -name *.js)
node_modules/@angular/{core,common,compiler,platform-browser}/index.js
node_modules/@angular/{core,common}/public_api.js
$(find node_modules/@angular/{core,common,compiler,platform-browser}/src -name *.js)
"built/src/*.js"
"--entry_point=./built/src/main"
Expand Down
12 changes: 6 additions & 6 deletions modules/@angular/animation/index.ts
Expand Up @@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/

/**
* @module
* @description
* Entry point for all public APIs of the animation package.
*/
export * from './src/animation';
// This file is not used to build this module. It is only used during editing
// by the TypeScript language serivce and during build for verifcation. `ngc`
// replaces this file with production index.ts when it rewrites private symbol
// names.

export * from './public_api';
14 changes: 14 additions & 0 deletions modules/@angular/animation/public_api.ts
@@ -0,0 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

/**
* @module
* @description
* Entry point for all public APIs of the animation package.
*/
export * from './src/animation';
6 changes: 4 additions & 2 deletions modules/@angular/animation/tsconfig-build.json
Expand Up @@ -20,12 +20,14 @@
"types": []
},
"files": [
"index.ts",
"public_api.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts",
"../../system.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": true
"strictMetadataEmit": true,
"bundleIndex": "index",
"importAs": "@angular/animation"
}
}
12 changes: 5 additions & 7 deletions modules/@angular/common/index.ts
Expand Up @@ -6,11 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/

/**
* @module
* @description
* Entry point for all public APIs of the common package.
*/
export * from './src/common';
// This file is not used to build this module. It is only used during editing
// by the TypeScript language serivce and during build for verifcation. `ngc`
// replaces this file with production index.ts when it rewrites private symbol
// names.

// This file only reexports content of the `src` folder. Keep it that way.
export * from './public_api';
16 changes: 16 additions & 0 deletions modules/@angular/common/public_api.ts
@@ -0,0 +1,16 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

/**
* @module
* @description
* Entry point for all public APIs of the common package.
*/
export * from './src/common';

// This file only reexports content of the `src` folder. Keep it that way.
2 changes: 1 addition & 1 deletion modules/@angular/common/src/common.ts
Expand Up @@ -13,7 +13,7 @@
*/
export * from './location/index';
export {NgLocaleLocalization, NgLocalization} from './localization';
export {CommonModule} from './common_module';
export {CommonModule, DeprecatedCommonModule} from './common_module';
export {NgClass, NgFor, NgForOf, NgIf, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index';
export {AsyncPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCasePipe, CurrencyPipe, DecimalPipe, PercentPipe, SlicePipe, UpperCasePipe, TitleCasePipe} from './pipes/index';
export {VERSION} from './version';
4 changes: 3 additions & 1 deletion modules/@angular/common/src/common_module.ts
Expand Up @@ -32,7 +32,9 @@ export class CommonModule {

/**
* A module to contain deprecated directives.
*
* @deprecated
*/
@NgModule({declarations: [COMMON_DEPRECATED_DIRECTIVES], exports: [COMMON_DEPRECATED_DIRECTIVES]})
export class CommonDeprecatedModule {
export class DeprecatedCommonModule {
}
6 changes: 4 additions & 2 deletions modules/@angular/common/tsconfig-build.json
Expand Up @@ -20,11 +20,13 @@
"types": []
},
"files": [
"index.ts",
"public_api.ts",
"../../../node_modules/zone.js/dist/zone.js.d.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": true
"strictMetadataEmit": true,
"bundleIndex": "index",
"importAs": "@angular/common"
}
}
Expand Up @@ -31,8 +31,9 @@ function main() {

class AssertingHostContext extends NodeCompilerHostContext {
readFile(fileName: string): string {
if (/.*\/node_modules\/.*/.test(fileName) && !/.*ngsummary\.json$/.test(fileName)) {
// Only allow to read summaries from node_modules
if (/.*\/node_modules\/.*/.test(fileName) && !/.*ngsummary\.json$/.test(fileName) &&
!/package\.json$/.test(fileName)) {
// Only allow to read summaries and package.json files from node_modules
return null;
}
readFiles.push(path.relative(basePath, fileName));
Expand Down
2 changes: 1 addition & 1 deletion modules/@angular/compiler-cli/src/ngtools_impl.ts
Expand Up @@ -17,7 +17,7 @@ import {NgModule} from '@angular/core';

// We cannot depend directly to @angular/router.
type Route = any;
const ROUTER_MODULE_PATH = '@angular/router/src/router_config_loader';
const ROUTER_MODULE_PATH = '@angular/router';
const ROUTER_ROUTES_SYMBOL_NAME = 'ROUTES';


Expand Down
81 changes: 35 additions & 46 deletions modules/@angular/compiler/src/aot/static_reflector.ts
Expand Up @@ -14,15 +14,7 @@ import {syntaxError} from '../util';
import {StaticSymbol} from './static_symbol';
import {StaticSymbolResolver} from './static_symbol_resolver';

const ANGULAR_IMPORT_LOCATIONS = {
coreDecorators: '@angular/core/src/metadata',
diDecorators: '@angular/core/src/di/metadata',
diMetadata: '@angular/core/src/di/metadata',
diInjectionToken: '@angular/core/src/di/injection_token',
diOpaqueToken: '@angular/core/src/di/injection_token',
animationMetadata: '@angular/core/src/animation/metadata',
provider: '@angular/core/src/di/provider'
};
const ANGULAR_CORE = '@angular/core';

const HIDDEN_KEY = /^\$.*\$$/;

Expand Down Expand Up @@ -241,56 +233,53 @@ export class StaticReflector implements ReflectorReader {
}

private initializeConversionMap(): void {
const {coreDecorators, diDecorators, diMetadata, diInjectionToken,
diOpaqueToken, animationMetadata, provider} = ANGULAR_IMPORT_LOCATIONS;
this.injectionToken = this.findDeclaration(diInjectionToken, 'InjectionToken');
this.opaqueToken = this.findDeclaration(diInjectionToken, 'OpaqueToken');
this.injectionToken = this.findDeclaration(ANGULAR_CORE, 'InjectionToken');
this.opaqueToken = this.findDeclaration(ANGULAR_CORE, 'OpaqueToken');

this._registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Host'), Host);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), Host);
this._registerDecoratorOrConstructor(
this.findDeclaration(diDecorators, 'Injectable'), Injectable);
this._registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Self'), Self);
this._registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'SkipSelf'), SkipSelf);
this._registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Inject'), Inject);
this._registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Optional'), Optional);
this.findDeclaration(ANGULAR_CORE, 'Injectable'), Injectable);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), Self);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), SkipSelf);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Inject'), Inject);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), Optional);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'Attribute'), Attribute);
this.findDeclaration(ANGULAR_CORE, 'Attribute'), Attribute);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'ContentChild'), ContentChild);
this.findDeclaration(ANGULAR_CORE, 'ContentChild'), ContentChild);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'ContentChildren'), ContentChildren);
this.findDeclaration(ANGULAR_CORE, 'ContentChildren'), ContentChildren);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'ViewChild'), ViewChild);
this.findDeclaration(ANGULAR_CORE, 'ViewChild'), ViewChild);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'ViewChildren'), ViewChildren);
this._registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'Input'), Input);
this._registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'Output'), Output);
this._registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'Pipe'), Pipe);
this.findDeclaration(ANGULAR_CORE, 'ViewChildren'), ViewChildren);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Input'), Input);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Output'), Output);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Pipe'), Pipe);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'HostBinding'), HostBinding);
this.findDeclaration(ANGULAR_CORE, 'HostBinding'), HostBinding);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'HostListener'), HostListener);
this.findDeclaration(ANGULAR_CORE, 'HostListener'), HostListener);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'Directive'), Directive);
this.findDeclaration(ANGULAR_CORE, 'Directive'), Directive);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'Component'), Component);
this._registerDecoratorOrConstructor(
this.findDeclaration(coreDecorators, 'NgModule'), NgModule);
this.findDeclaration(ANGULAR_CORE, 'Component'), Component);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'NgModule'), NgModule);

// Note: Some metadata classes can be used directly with Provider.deps.
this._registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'Host'), Host);
this._registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'Self'), Self);
this._registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'SkipSelf'), SkipSelf);
this._registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'Optional'), Optional);

this._registerFunction(this.findDeclaration(animationMetadata, 'trigger'), trigger);
this._registerFunction(this.findDeclaration(animationMetadata, 'state'), state);
this._registerFunction(this.findDeclaration(animationMetadata, 'transition'), transition);
this._registerFunction(this.findDeclaration(animationMetadata, 'style'), style);
this._registerFunction(this.findDeclaration(animationMetadata, 'animate'), animate);
this._registerFunction(this.findDeclaration(animationMetadata, 'keyframes'), keyframes);
this._registerFunction(this.findDeclaration(animationMetadata, 'sequence'), sequence);
this._registerFunction(this.findDeclaration(animationMetadata, 'group'), group);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), Host);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), Self);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), SkipSelf);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), Optional);

this._registerFunction(this.findDeclaration(ANGULAR_CORE, 'trigger'), trigger);
this._registerFunction(this.findDeclaration(ANGULAR_CORE, 'state'), state);
this._registerFunction(this.findDeclaration(ANGULAR_CORE, 'transition'), transition);
this._registerFunction(this.findDeclaration(ANGULAR_CORE, 'style'), style);
this._registerFunction(this.findDeclaration(ANGULAR_CORE, 'animate'), animate);
this._registerFunction(this.findDeclaration(ANGULAR_CORE, 'keyframes'), keyframes);
this._registerFunction(this.findDeclaration(ANGULAR_CORE, 'sequence'), sequence);
this._registerFunction(this.findDeclaration(ANGULAR_CORE, 'group'), group);
}

/**
Expand Down
15 changes: 11 additions & 4 deletions modules/@angular/compiler/src/aot/static_symbol_resolver.ts
Expand Up @@ -202,9 +202,16 @@ export class StaticSymbolResolver {
new Set<string>(Object.keys(metadata['metadata']).map(unescapeIdentifier));
Object.keys(metadata['metadata']).forEach((metadataKey) => {
const symbolMeta = metadata['metadata'][metadataKey];
resolvedSymbols.push(this.createResolvedSymbol(
this.getStaticSymbol(filePath, unescapeIdentifier(metadataKey)), topLevelSymbolNames,
symbolMeta));
const name = unescapeIdentifier(metadataKey);
const canonicalSymbol = this.getStaticSymbol(filePath, name);
if (metadata['importAs']) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, as discussed offline. This is the module name the user declared in the tsconfig.json file that the compiler should generate for references to symbols in a bundle.

// Index bundle indexes should use the importAs module name instead of a reference
// to the .d.ts file directly.
const importSymbol = this.getStaticSymbol(metadata['importAs'], name);
this.recordImportAs(canonicalSymbol, importSymbol);
}
resolvedSymbols.push(
this.createResolvedSymbol(canonicalSymbol, topLevelSymbolNames, symbolMeta));
});
}

Expand Down Expand Up @@ -372,7 +379,7 @@ export class StaticSymbolResolver {
return this.host.moduleNameToFileName(module, containingFile);
} catch (e) {
console.error(`Could not resolve module '${module}' relative to file ${containingFile}`);
this.reportError(new e, null, containingFile);
this.reportError(e, null, containingFile);
}
}
}
Expand Down
62 changes: 56 additions & 6 deletions modules/@angular/compiler/test/aot/compiler_spec.ts
Expand Up @@ -9,15 +9,18 @@
import {AotCompiler, AotCompilerHost, createAotCompiler} from '@angular/compiler';
import {RenderComponentType} from '@angular/core';
import {async} from '@angular/core/testing';
import {MetadataBundler, MetadataCollector, ModuleMetadata, privateEntriesToIndex} from '@angular/tsc-wrapped';
import * as path from 'path';
import * as ts from 'typescript';

import {ReflectionCapabilities, reflector} from './private_import_core';
import {EmittingCompilerHost, MockAotCompilerHost, MockCompilerHost, MockData, settings} from './test_util';
import {EmittingCompilerHost, MockAotCompilerHost, MockCompilerHost, MockData, MockMetadataBundlerHost, settings} from './test_util';

const DTS = /\.d\.ts$/;

const minCoreIndex = `
export * from './src/application_module';
export * from './src/change_detection';
export * from './src/metadata';
export * from './src/di/metadata';
export * from './src/di/injector';
Expand All @@ -28,7 +31,7 @@ const minCoreIndex = `
export * from './src/codegen_private_exports';
`;

describe('compiler', () => {
describe('compiler (unbundled Angular)', () => {
let angularFiles: Map<string, string>;

beforeAll(() => {
Expand All @@ -55,17 +58,64 @@ describe('compiler', () => {
it('should compile',
async(() => compile(host, aotHost, expectNoDiagnostics).then(generatedFiles => {
expect(generatedFiles.find(f => /app\.component\.ngfactory\.ts/.test(f.genFileUrl)))
.not.toBeUndefined();
.toBeDefined();
expect(generatedFiles.find(f => /app\.module\.ngfactory\.ts/.test(f.genFileUrl)))
.not.toBeUndefined();
.toBeDefined();
})));

it('should compile using summaries',
async(() => summaryCompile(host, aotHost).then(generatedFiles => {
expect(generatedFiles.find(f => /app\.component\.ngfactory\.ts/.test(f.genFileUrl)))
.not.toBeUndefined();
.toBeDefined();
expect(generatedFiles.find(f => /app\.module\.ngfactory\.ts/.test(f.genFileUrl)))
.not.toBeUndefined();
.toBeDefined();
})));
});
});

describe('compiler (bundled Angular)', () => {
let angularFiles: Map<string, string>;

beforeAll(() => {
const emittingHost = new EmittingCompilerHost(['@angular/core/index'], {emitMetadata: false});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is /index right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This is unrelated to the changes we needed to make for tsickle


// Create the metadata bundled
const indexModule = emittingHost.effectiveName('@angular/core/index');
const bundler = new MetadataBundler(
indexModule, '@angular/core', new MockMetadataBundlerHost(emittingHost));
const bundle = bundler.getMetadataBundle();
const metadata = JSON.stringify(bundle.metadata, null, ' ');
const bundleIndexSource = privateEntriesToIndex('./index', bundle.privates);
emittingHost.override('@angular/core/bundle_index.ts', bundleIndexSource);
emittingHost.addWrittenFile(
'@angular/core/package.json', JSON.stringify({typings: 'bundle_index.d.ts'}));
emittingHost.addWrittenFile('@angular/core/bundle_index.metadata.json', metadata);

// Emit the sources
const bundleIndexName = emittingHost.effectiveName('@angular/core/bundle_index.ts');
const emittingProgram = ts.createProgram([bundleIndexName], settings, emittingHost);
emittingProgram.emit();
angularFiles = emittingHost.written;
});

describe('Quickstart', () => {
let host: MockCompilerHost;
let aotHost: MockAotCompilerHost;

beforeEach(() => {
host = new MockCompilerHost(QUICKSTART, FILES, angularFiles);
aotHost = new MockAotCompilerHost(host);
});

// Restore reflector since AoT compiler will update it with a new static reflector
afterEach(() => { reflector.updateCapabilities(new ReflectionCapabilities()); });

it('should compile',
async(() => compile(host, aotHost, expectNoDiagnostics).then(generatedFiles => {
expect(generatedFiles.find(f => /app\.component\.ngfactory\.ts/.test(f.genFileUrl)))
.toBeDefined();
expect(generatedFiles.find(f => /app\.module\.ngfactory\.ts/.test(f.genFileUrl)))
.toBeDefined();
})));
});
});
Expand Down