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

fix(ivy): adhere to bootstrap options for JIT compiled components #35534

Closed
wants to merge 4 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
28 changes: 27 additions & 1 deletion packages/core/src/application_ref.ts
Expand Up @@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/

import './util/ng_jit_mode';

import {Observable, Observer, Subscription, merge} from 'rxjs';
import {share} from 'rxjs/operators';

Expand All @@ -29,6 +31,7 @@ import {isComponentResourceResolutionQueueEmpty, resolveComponentResources} from
import {assertNgModuleType} from './render3/assert';
import {ComponentFactory as R3ComponentFactory} from './render3/component_ref';
import {setLocaleId} from './render3/i18n';
import {setJitOptions} from './render3/jit/jit_options';
import {NgModuleFactory as R3NgModuleFactory} from './render3/ng_module_ref';
import {publishDefaultGlobalUtils as _publishDefaultGlobalUtils} from './render3/util/global_utils';
import {Testability, TestabilityRegistry} from './testability/testability';
Expand Down Expand Up @@ -56,13 +59,27 @@ export function compileNgModuleFactory__POST_R3__<M>(
injector: Injector, options: CompilerOptions,
moduleType: Type<M>): Promise<NgModuleFactory<M>> {
ngDevMode && assertNgModuleType(moduleType);

const compilerOptions = injector.get(COMPILER_OPTIONS, []).concat(options);

if (typeof ngJitMode === 'undefined' || ngJitMode) {
Copy link
Member

Choose a reason for hiding this comment

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

You're correct in your assumption - ng_jit_mode.ts needs to be side-effectfully imported into this file.

// Configure the compiler to use the provided options. This call may fail when multiple modules
// are bootstrapped with incompatible options, as a component can only be compiled according to
// a single set of options.
setJitOptions({
defaultEncapsulation:
_lastDefined(compilerOptions.map(options => options.defaultEncapsulation)),
preserveWhitespaces:
_lastDefined(compilerOptions.map(options => options.preserveWhitespaces)),
});
}

const moduleFactory = new R3NgModuleFactory(moduleType);

if (isComponentResourceResolutionQueueEmpty()) {
return Promise.resolve(moduleFactory);
}

const compilerOptions = injector.get(COMPILER_OPTIONS, []).concat(options);
const compilerProviders = _mergeArrays(compilerOptions.map(o => o.providers !));

// In case there are no compiler providers, we just return the module factory as
Expand Down Expand Up @@ -748,6 +765,15 @@ function remove<T>(list: T[], el: T): void {
}
}

function _lastDefined<T>(args: T[]): T|undefined {
for (let i = args.length - 1; i >= 0; i--) {
if (args[i] !== undefined) {
return args[i];
}
}
return undefined;
}

function _mergeArrays(parts: any[][]): any[] {
const result: any[] = [];
parts.forEach((part) => part && result.push(...part));
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/core_render3_private_export.ts
Expand Up @@ -197,6 +197,9 @@ export {
export {
compilePipe as ɵcompilePipe,
} from './render3/jit/pipe';
export {
resetJitOptions as ɵresetJitOptions,
} from './render3/jit/jit_options';

export {
NgModuleDef as ɵNgModuleDef,
Expand Down
25 changes: 21 additions & 4 deletions packages/core/src/render3/jit/directive.ts
Expand Up @@ -23,6 +23,7 @@ import {ComponentType} from '../interfaces/definition';
import {stringifyForError} from '../util/misc_utils';

import {angularCoreEnv} from './environment';
import {getJitOptions} from './jit_options';
import {flushModuleScopingQueueAsMuchAsPossible, patchComponentDefWithScope, transitiveScopesFor} from './module';


Expand Down Expand Up @@ -68,18 +69,34 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
throw new Error(error.join('\n'));
}

const jitOptions = getJitOptions();
let preserveWhitespaces = metadata.preserveWhitespaces;
if (preserveWhitespaces === undefined) {
if (jitOptions !== null && jitOptions.preserveWhitespaces !== undefined) {
preserveWhitespaces = jitOptions.preserveWhitespaces;
} else {
preserveWhitespaces = false;
}
}
let encapsulation = metadata.encapsulation;
if (encapsulation === undefined) {
if (jitOptions !== null && jitOptions.defaultEncapsulation !== undefined) {
encapsulation = jitOptions.defaultEncapsulation;
} else {
encapsulation = ViewEncapsulation.Emulated;
}
}

const templateUrl = metadata.templateUrl || `ng:///${type.name}/template.html`;
const meta: R3ComponentMetadataFacade = {
...directiveMetadata(type, metadata),
typeSourceSpan: compiler.createParseSourceSpan('Component', type.name, templateUrl),
template: metadata.template || '',
preserveWhitespaces: metadata.preserveWhitespaces || false,
template: metadata.template || '', preserveWhitespaces,
styles: metadata.styles || EMPTY_ARRAY,
animations: metadata.animations,
directives: [],
changeDetection: metadata.changeDetection,
pipes: new Map(),
encapsulation: metadata.encapsulation || ViewEncapsulation.Emulated,
pipes: new Map(), encapsulation,
interpolation: metadata.interpolation,
viewProviders: metadata.viewProviders || null,
};
Expand Down
41 changes: 41 additions & 0 deletions packages/core/src/render3/jit/jit_options.ts
@@ -0,0 +1,41 @@
/**
* @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
*/
import {ViewEncapsulation} from '../../metadata/view';

export interface JitCompilerOptions {
defaultEncapsulation?: ViewEncapsulation;
preserveWhitespaces?: boolean;
}

let jitOptions: JitCompilerOptions|null = null;

export function setJitOptions(options: JitCompilerOptions): void {
if (jitOptions !== null) {
if (options.defaultEncapsulation !== jitOptions.defaultEncapsulation) {
ngDevMode &&
console.error(
'Provided value for `defaultEncapsulation` can not be changed once it has been set.');
return;
}
if (options.preserveWhitespaces !== jitOptions.preserveWhitespaces) {
ngDevMode &&
console.error(
'Provided value for `preserveWhitespaces` can not be changed once it has been set.');
return;
}
}
jitOptions = options;
}

export function getJitOptions(): JitCompilerOptions|null {
return jitOptions;
}

export function resetJitOptions(): void {
jitOptions = null;
}
14 changes: 14 additions & 0 deletions packages/core/src/util/ng_jit_mode.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
*/

declare global {
const ngJitMode: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

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

hmm.. we are starting to have too many places where the global is augmented. Could we consolidated this in a follow up PR?

Many but possibly not all (e.g. spec?) of these files should be consolidated so that the global namespace type or value mangling happens from one place and is tracked by the ts-api-guardian:

git grep -E "declare (var )?global" "packages/**/*.ts" 
packages/compiler/src/util.ts:declare var global: any;
packages/core/src/util/global.ts:declare var global: any /** TODO #9100 */;
packages/core/src/util/global.ts:declare var globalThis: any /** TODO #9100 */;
packages/core/src/util/ng_dev_mode.ts:declare global {
packages/core/src/util/ng_i18n_closure_mode.ts:declare global {
packages/core/test/util/global_spec.ts:declare var globalThis: any /** TODO #9100 */;
packages/core/testing/src/async_fallback.ts:declare var global: any;
packages/core/testing/src/before_each.ts:declare var global: any;
packages/examples/upgrade/static/ts/lite/e2e_test/e2e_util.ts:declare global {
packages/localize/init/index.ts:// `declare global` allows us to escape the current module and place types on the global namespace
packages/localize/init/index.ts:declare global {
packages/localize/src/localize/src/global.ts:declare global {
packages/upgrade/src/dynamic/test/upgrade_spec.ts:declare global {
packages/zone.js/lib/zone.ts:declare var global: NodeJS.Global;

}

// Make this an ES module to be able to augment the global scope
export {};