Skip to content

Commit 503905c

Browse files
mheveryjasonaden
authored andcommitted
feat(ivy): add ngcc ivy switch (angular#25238)
Provides a runtime and compile time switch for ivy including `ApplicationRef.bootstrapModule`. This is done by naming the symbols such that `ngcc` (angular Compatibility compiler) can rename symbols in such a way that running `ngcc` command will switch the `@angular/core` module from `legacy` to `ivy` mode. This is done as follows: ``` const someToken__PRE_NGCC__ = ‘legacy mode’; const someToken__POST_NGCC__ = ‘ivy mode’; export someSymbol = someToken__PRE_NGCC__; ``` The `ngcc` will search for any token which ends with `__PRE_NGCC__` and replace it with `__POST_NGCC__`. This allows the `@angular/core` package to be rewritten to ivy mode post `ngcc` execution. PR Close angular#25238
1 parent cc55d60 commit 503905c

23 files changed

Lines changed: 297 additions & 200 deletions

packages/compiler/test/schema/schema_extractor.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ const MISSING_FROM_CHROME: {[el: string]: string[]} = {
3838
':svg:cursor^:svg:': [],
3939
};
4040

41-
const _G: any = global;
41+
const _G: any = typeof window != 'undefined' && window || typeof global != 'undefined' && global ||
42+
typeof self != 'undefined' && self;
43+
4244
const document: any = typeof _G['document'] == 'object' ? _G['document'] : null;
4345

4446
export function extractSchema(): Map<string, string[]>|null {

packages/core/src/application_ref.ts

Lines changed: 26 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,60 +9,51 @@
99
import {Observable, Observer, Subscription, merge} from 'rxjs';
1010
import {share} from 'rxjs/operators';
1111

12-
import {ErrorHandler} from '../src/error_handler';
13-
import {scheduleMicroTask, stringify} from '../src/util';
14-
import {isPromise} from '../src/util/lang';
15-
1612
import {ApplicationInitStatus} from './application_init';
1713
import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens';
1814
import {Console} from './console';
1915
import {Injectable, InjectionToken, Injector, StaticProvider} from './di';
16+
import {ErrorHandler} from './error_handler';
17+
import {isDevMode} from './is_dev_mode';
2018
import {CompilerFactory, CompilerOptions} from './linker/compiler';
2119
import {ComponentFactory, ComponentRef} from './linker/component_factory';
2220
import {ComponentFactoryBoundToModule, ComponentFactoryResolver} from './linker/component_factory_resolver';
2321
import {InternalNgModuleRef, NgModuleFactory, NgModuleRef} from './linker/ng_module_factory';
2422
import {InternalViewRef, ViewRef} from './linker/view_ref';
2523
import {WtfScopeFn, wtfCreateScope, wtfLeave} from './profile/profile';
24+
import {assertNgModuleType} from './render3/assert';
25+
import {NgModuleFactory as R3NgModuleFactory} from './render3/ng_module_ref';
2626
import {Testability, TestabilityRegistry} from './testability/testability';
2727
import {Type} from './type';
28+
import {scheduleMicroTask, stringify} from './util';
29+
import {isPromise} from './util/lang';
2830
import {NgZone, NoopNgZone} from './zone/ng_zone';
2931

30-
let _devMode: boolean = true;
31-
let _runModeLocked: boolean = false;
3232
let _platform: PlatformRef;
3333

34-
export const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken<boolean>('AllowMultipleToken');
34+
let compileNgModuleFactory:
35+
<M>(injector: Injector, options: CompilerOptions, moduleType: Type<M>) =>
36+
Promise<NgModuleFactory<M>> = compileNgModuleFactory__PRE_NGCC__;
3537

36-
/**
37-
* Disable Angular's development mode, which turns off assertions and other
38-
* checks within the framework.
39-
*
40-
* One important assertion this disables verifies that a change detection pass
41-
* does not result in additional changes to any bindings (also known as
42-
* unidirectional data flow).
43-
*
44-
*
45-
*/
46-
export function enableProdMode(): void {
47-
if (_runModeLocked) {
48-
throw new Error('Cannot enable prod mode after platform setup.');
49-
}
50-
_devMode = false;
38+
function compileNgModuleFactory__PRE_NGCC__<M>(
39+
injector: Injector, options: CompilerOptions,
40+
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
41+
const compilerFactory: CompilerFactory = injector.get(CompilerFactory);
42+
const compiler = compilerFactory.createCompiler([options]);
43+
return compiler.compileModuleAsync(moduleType);
5144
}
5245

53-
/**
54-
* Returns whether Angular is in development mode. After called once,
55-
* the value is locked and won't change any more.
56-
*
57-
* By default, this is true, unless a user calls `enableProdMode` before calling this.
58-
*
59-
* @experimental APIs related to application bootstrap are currently under review.
60-
*/
61-
export function isDevMode(): boolean {
62-
_runModeLocked = true;
63-
return _devMode;
46+
function compileNgModuleFactory__POST_NGCC__<M>(
47+
injector: Injector, options: CompilerOptions,
48+
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
49+
ngDevMode && assertNgModuleType(moduleType);
50+
return Promise.resolve(new R3NgModuleFactory(moduleType));
6451
}
6552

53+
export const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken<boolean>('AllowMultipleToken');
54+
55+
56+
6657
/**
6758
* A token for third-party components that can register themselves with NgProbe.
6859
*
@@ -267,12 +258,9 @@ export class PlatformRef {
267258
bootstrapModule<M>(
268259
moduleType: Type<M>, compilerOptions: (CompilerOptions&BootstrapOptions)|
269260
Array<CompilerOptions&BootstrapOptions> = []): Promise<NgModuleRef<M>> {
270-
const compilerFactory: CompilerFactory = this.injector.get(CompilerFactory);
271261
const options = optionsReducer({}, compilerOptions);
272-
const compiler = compilerFactory.createCompiler([options]);
273-
274-
return compiler.compileModuleAsync(moduleType)
275-
.then((moduleFactory) => this.bootstrapModuleFactory(moduleFactory, options));
262+
return compileNgModuleFactory(this.injector, options, moduleType)
263+
.then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options));
276264
}
277265

278266
private _moduleDoBootstrap(moduleRef: InternalNgModuleRef<any>): void {

packages/core/src/core.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ export * from './metadata';
1515
export * from './version';
1616
export {TypeDecorator} from './util/decorators';
1717
export * from './di';
18-
export {createPlatform, assertPlatform, destroyPlatform, getPlatform, PlatformRef, ApplicationRef, enableProdMode, isDevMode, createPlatformFactory, NgProbeToken} from './application_ref';
18+
export {createPlatform, assertPlatform, destroyPlatform, getPlatform, PlatformRef, ApplicationRef, createPlatformFactory, NgProbeToken} from './application_ref';
19+
export {enableProdMode, isDevMode} from './is_dev_mode';
1920
export {APP_ID, PACKAGE_ROOT_URL, PLATFORM_INITIALIZER, PLATFORM_ID, APP_BOOTSTRAP_LISTENER} from './application_tokens';
2021
export {APP_INITIALIZER, ApplicationInitStatus} from './application_init';
2122
export * from './zone';

packages/core/src/core_render3_private_export.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,10 @@ export {
120120
I18nInstruction as ɵI18nInstruction,
121121
I18nExpInstruction as ɵI18nExpInstruction,
122122
WRAP_RENDERER_FACTORY2 as ɵWRAP_RENDERER_FACTORY2,
123-
Render3DebugRendererFactory2 as ɵRender3DebugRendererFactory2,
124123
} from './render3/index';
125124

125+
export { Render3DebugRendererFactory2 as ɵRender3DebugRendererFactory2 } from './render3/debug';
126+
126127

127128
export {
128129
compileNgModuleDefs as ɵcompileNgModuleDefs,

packages/core/src/di/injectable.ts

Lines changed: 7 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,11 @@
77
*/
88

99
import {R3_COMPILE_INJECTABLE} from '../ivy_switch';
10-
import {ReflectionCapabilities} from '../reflection/reflection_capabilities';
1110
import {Type} from '../type';
12-
import {makeDecorator, makeParamDecorator} from '../util/decorators';
13-
import {getClosureSafeProperty} from '../util/property';
11+
import {makeDecorator} from '../util/decorators';
1412

15-
import {InjectableDef, InjectableType, defineInjectable} from './defs';
16-
import {inject, injectArgs} from './injector';
17-
import {ClassSansProvider, ConstructorProvider, ConstructorSansProvider, ExistingProvider, ExistingSansProvider, FactoryProvider, FactorySansProvider, StaticClassProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider';
18-
19-
const GET_PROPERTY_NAME = {} as any;
20-
const USE_VALUE = getClosureSafeProperty<ValueProvider>(
21-
{provide: String, useValue: GET_PROPERTY_NAME}, GET_PROPERTY_NAME);
13+
import {InjectableDef, InjectableType} from './defs';
14+
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider';
2215

2316
/**
2417
* Injectable providers used in `@Injectable` decorator.
@@ -61,67 +54,16 @@ export interface InjectableDecorator {
6154
*/
6255
export interface Injectable { providedIn?: Type<any>|'root'|null; }
6356

64-
const EMPTY_ARRAY: any[] = [];
65-
66-
export function convertInjectableProviderToFactory(
67-
type: Type<any>, provider?: InjectableProvider): () => any {
68-
if (!provider) {
69-
const reflectionCapabilities = new ReflectionCapabilities();
70-
const deps = reflectionCapabilities.parameters(type);
71-
// TODO - convert to flags.
72-
return () => new type(...injectArgs(deps as any[]));
73-
}
74-
75-
if (USE_VALUE in provider) {
76-
const valueProvider = (provider as ValueSansProvider);
77-
return () => valueProvider.useValue;
78-
} else if ((provider as ExistingSansProvider).useExisting) {
79-
const existingProvider = (provider as ExistingSansProvider);
80-
return () => inject(existingProvider.useExisting);
81-
} else if ((provider as FactorySansProvider).useFactory) {
82-
const factoryProvider = (provider as FactorySansProvider);
83-
return () => factoryProvider.useFactory(...injectArgs(factoryProvider.deps || EMPTY_ARRAY));
84-
} else if ((provider as StaticClassSansProvider | ClassSansProvider).useClass) {
85-
const classProvider = (provider as StaticClassSansProvider | ClassSansProvider);
86-
let deps = (provider as StaticClassSansProvider).deps;
87-
if (!deps) {
88-
const reflectionCapabilities = new ReflectionCapabilities();
89-
deps = reflectionCapabilities.parameters(type);
90-
}
91-
return () => new classProvider.useClass(...injectArgs(deps));
92-
} else {
93-
let deps = (provider as ConstructorSansProvider).deps;
94-
if (!deps) {
95-
const reflectionCapabilities = new ReflectionCapabilities();
96-
deps = reflectionCapabilities.parameters(type);
97-
}
98-
return () => new type(...injectArgs(deps !));
99-
}
100-
}
101-
102-
/**
103-
* Supports @Injectable() in JIT mode for Render2.
104-
*/
105-
function preR3InjectableCompile(
106-
injectableType: InjectableType<any>,
107-
options: {providedIn?: Type<any>| 'root' | null} & InjectableProvider): void {
108-
if (options && options.providedIn !== undefined && injectableType.ngInjectableDef === undefined) {
109-
injectableType.ngInjectableDef = defineInjectable({
110-
providedIn: options.providedIn,
111-
factory: convertInjectableProviderToFactory(injectableType, options),
112-
});
113-
}
114-
}
115-
11657
/**
11758
* Injectable decorator and metadata.
11859
*
11960
* @Annotation
12061
*/
12162
export const Injectable: InjectableDecorator = makeDecorator(
122-
'Injectable', undefined, undefined, undefined,
123-
(type: Type<any>, meta: Injectable) =>
124-
(R3_COMPILE_INJECTABLE || preR3InjectableCompile)(type, meta));
63+
'Injectable', undefined, undefined, undefined, (type: Type<any>, meta: Injectable) => {
64+
debugger;
65+
return R3_COMPILE_INJECTABLE(type, meta);
66+
});
12567

12668
/**
12769
* Type representing injectable service.

packages/core/src/is_dev_mode.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. 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 file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
11+
*
12+
* For more information on how to run and debug tests with either Ivy or View Engine (legacy),
13+
* please see [BAZEL.md](./docs/BAZEL.md).
14+
*/
15+
16+
let _devMode: boolean = true;
17+
let _runModeLocked: boolean = false;
18+
19+
20+
/**
21+
* Returns whether Angular is in development mode. After called once,
22+
* the value is locked and won't change any more.
23+
*
24+
* By default, this is true, unless a user calls `enableProdMode` before calling this.
25+
*
26+
* @experimental APIs related to application bootstrap are currently under review.
27+
*/
28+
export function isDevMode(): boolean {
29+
_runModeLocked = true;
30+
return _devMode;
31+
}
32+
33+
/**
34+
* Disable Angular's development mode, which turns off assertions and other
35+
* checks within the framework.
36+
*
37+
* One important assertion this disables verifies that a change detection pass
38+
* does not result in additional changes to any bindings (also known as
39+
* unidirectional data flow).
40+
*/
41+
export function enableProdMode(): void {
42+
if (_runModeLocked) {
43+
throw new Error('Cannot enable prod mode after platform setup.');
44+
}
45+
_devMode = false;
46+
}

packages/core/src/ivy_switch_legacy.ts

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

9-
export const ivyEnabled = false;
10-
export const R3_COMPILE_COMPONENT: ((type: any, meta: any) => void)|null = null;
11-
export const R3_COMPILE_DIRECTIVE: ((type: any, meta: any) => void)|null = null;
12-
export const R3_COMPILE_INJECTABLE: ((type: any, meta: any) => void)|null = null;
13-
export const R3_COMPILE_NGMODULE: ((type: any, meta: any) => void)|null = null;
14-
export const R3_COMPILE_PIPE: ((type: any, meta: any) => void)|null = null;
9+
import {InjectableType, InjectorType, defineInjectable, defineInjector} from './di/defs';
10+
import {InjectableProvider} from './di/injectable';
11+
import {inject, injectArgs} from './di/injector';
12+
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './di/provider';
13+
import * as ivyOn from './ivy_switch_on';
14+
import {NgModule} from './metadata';
15+
import {ReflectionCapabilities} from './reflection/reflection_capabilities';
16+
import {Type} from './type';
17+
import {getClosureSafeProperty} from './util/property';
18+
19+
function noop() {}
20+
21+
export interface DirectiveCompiler { (type: any, meta: any): void; }
22+
23+
const R3_COMPILE_COMPONENT__POST_NGCC__ = ivyOn.R3_COMPILE_COMPONENT;
24+
const R3_COMPILE_DIRECTIVE__POST_NGCC__ = ivyOn.R3_COMPILE_DIRECTIVE;
25+
const R3_COMPILE_INJECTABLE__POST_NGCC__ = ivyOn.R3_COMPILE_INJECTABLE;
26+
const R3_COMPILE_NGMODULE__POST_NGCC__ = ivyOn.R3_COMPILE_NGMODULE;
27+
const R3_COMPILE_PIPE__POST_NGCC__ = ivyOn.R3_COMPILE_PIPE;
28+
const ivyEnable__POST_NGCC__ = ivyOn.ivyEnabled;
29+
30+
const compileComponentQueue: any[] = [];
31+
const compileDirectiveQueue: any[] = [];
32+
const compileInjectableQueue: any[] = [];
33+
const compileNgModuleQueue: any[] = [];
34+
const compilePipeQueue: any[] = [];
35+
36+
const R3_COMPILE_COMPONENT__PRE_NGCC__: DirectiveCompiler = noop;
37+
const R3_COMPILE_DIRECTIVE__PRE_NGCC__: DirectiveCompiler = noop;
38+
const R3_COMPILE_INJECTABLE__PRE_NGCC__: DirectiveCompiler = preR3InjectableCompile;
39+
const R3_COMPILE_NGMODULE__PRE_NGCC__: DirectiveCompiler = preR3NgModuleCompile;
40+
const R3_COMPILE_PIPE__PRE_NGCC__: DirectiveCompiler = noop;
41+
const ivyEnable__PRE_NGCC__ = false;
42+
43+
export const ivyEnabled = ivyEnable__PRE_NGCC__;
44+
export let R3_COMPILE_COMPONENT: DirectiveCompiler = R3_COMPILE_COMPONENT__PRE_NGCC__;
45+
export let R3_COMPILE_DIRECTIVE: DirectiveCompiler = R3_COMPILE_DIRECTIVE__PRE_NGCC__;
46+
export let R3_COMPILE_INJECTABLE: DirectiveCompiler = R3_COMPILE_INJECTABLE__PRE_NGCC__;
47+
export let R3_COMPILE_NGMODULE: DirectiveCompiler = R3_COMPILE_NGMODULE__PRE_NGCC__;
48+
export let R3_COMPILE_PIPE: DirectiveCompiler = R3_COMPILE_PIPE__PRE_NGCC__;
49+
50+
51+
////////////////////////////////////////////////////////////
52+
// Glue code which should be removed after Ivy is default //
53+
////////////////////////////////////////////////////////////
54+
55+
function preR3NgModuleCompile(moduleType: InjectorType<any>, metadata: NgModule): void {
56+
let imports = (metadata && metadata.imports) || [];
57+
if (metadata && metadata.exports) {
58+
imports = [...imports, metadata.exports];
59+
}
60+
61+
moduleType.ngInjectorDef = defineInjector({
62+
factory: convertInjectableProviderToFactory(moduleType, {useClass: moduleType}),
63+
providers: metadata && metadata.providers,
64+
imports: imports,
65+
});
66+
}
67+
68+
const GET_PROPERTY_NAME = {} as any;
69+
const USE_VALUE = getClosureSafeProperty<ValueProvider>(
70+
{provide: String, useValue: GET_PROPERTY_NAME}, GET_PROPERTY_NAME);
71+
const EMPTY_ARRAY: any[] = [];
72+
73+
function convertInjectableProviderToFactory(type: Type<any>, provider?: InjectableProvider): () =>
74+
any {
75+
if (!provider) {
76+
const reflectionCapabilities = new ReflectionCapabilities();
77+
const deps = reflectionCapabilities.parameters(type);
78+
// TODO - convert to flags.
79+
return () => new type(...injectArgs(deps as any[]));
80+
}
81+
82+
if (USE_VALUE in provider) {
83+
const valueProvider = (provider as ValueSansProvider);
84+
return () => valueProvider.useValue;
85+
} else if ((provider as ExistingSansProvider).useExisting) {
86+
const existingProvider = (provider as ExistingSansProvider);
87+
return () => inject(existingProvider.useExisting);
88+
} else if ((provider as FactorySansProvider).useFactory) {
89+
const factoryProvider = (provider as FactorySansProvider);
90+
return () => factoryProvider.useFactory(...injectArgs(factoryProvider.deps || EMPTY_ARRAY));
91+
} else if ((provider as StaticClassSansProvider | ClassSansProvider).useClass) {
92+
const classProvider = (provider as StaticClassSansProvider | ClassSansProvider);
93+
let deps = (provider as StaticClassSansProvider).deps;
94+
if (!deps) {
95+
const reflectionCapabilities = new ReflectionCapabilities();
96+
deps = reflectionCapabilities.parameters(type);
97+
}
98+
return () => new classProvider.useClass(...injectArgs(deps));
99+
} else {
100+
let deps = (provider as ConstructorSansProvider).deps;
101+
if (!deps) {
102+
const reflectionCapabilities = new ReflectionCapabilities();
103+
deps = reflectionCapabilities.parameters(type);
104+
}
105+
return () => new type(...injectArgs(deps !));
106+
}
107+
}
108+
109+
/**
110+
* Supports @Injectable() in JIT mode for Render2.
111+
*/
112+
function preR3InjectableCompile(
113+
injectableType: InjectableType<any>,
114+
options: {providedIn?: Type<any>| 'root' | null} & InjectableProvider): void {
115+
if (options && options.providedIn !== undefined && injectableType.ngInjectableDef === undefined) {
116+
injectableType.ngInjectableDef = defineInjectable({
117+
providedIn: options.providedIn,
118+
factory: convertInjectableProviderToFactory(injectableType, options),
119+
});
120+
}
121+
}

0 commit comments

Comments
 (0)