refactor(upgrade): ignore cross relative import for package (#51500)

The upgrade package duplicaes some of code due to relative
imports between entry-points. This caused bundlers to
inline shared functions twice in both FESM outputs.

This is an acceptable limitation and we are not changing this
because the primary entry-point is not synced into G3. It's non-trivial
to remove these cross relative imports right now because the primary
entry-point is not even built in G3 so instead we just ignore the
relative imports using a re-export file.

Note: To simplify this change, we continue using namespace exports
as exporting individual named exports for all these possible usages
is rather cumbersome and also we had existing namespace imports for
e.g. `angular1.ts`. The code of upgrade is rarely edited these days

PR Close #51500
This commit is contained in:
Paul Gschwendtner
2023-08-25 12:20:33 +00:00
committed by Jessica Janiuk
parent 86c5e34601
commit 65b6fdb9cd
9 changed files with 107 additions and 83 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ ng_module(
deps = [
"//packages/core",
"//packages/platform-browser",
"//packages/upgrade/src/common",
"//packages/upgrade",
],
)
+24
View File
@@ -0,0 +1,24 @@
/**
* @license
* Copyright Google LLC 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
*/
/**
* Note: We intentionally use cross entry-point relative paths here. This
* is because the primary entry-point is deprecated and we also don't have
* it available in G3.
*/
// @ng_package: ignore-cross-repo-import
import * as ɵangular1 from '../src/common/src/angular1';
// @ng_package: ignore-cross-repo-import
import * as ɵconstants from '../src/common/src/constants';
// @ng_package: ignore-cross-repo-import
import * as ɵupgradeHelper from '../src/common/src/upgrade_helper';
// @ng_package: ignore-cross-repo-import
import * as ɵutil from '../src/common/src/util';
export {ɵangular1, ɵconstants, ɵupgradeHelper, ɵutil};
+1
View File
@@ -13,6 +13,7 @@ export {VERSION} from '../src/common/src/version';
export {downgradeModule} from './src/downgrade_module';
export {UpgradeComponent} from './src/upgrade_component';
export {UpgradeModule} from './src/upgrade_module';
export * from './common';
// This file only re-exports items to appear in the public api. Keep it that way.
+20 -20
View File
@@ -9,9 +9,7 @@
import {Injector, NgModuleFactory, NgModuleRef, PlatformRef, StaticProvider, Type} from '@angular/core';
import {platformBrowser} from '@angular/platform-browser';
import {IInjectorService, IProvideService, module_ as angularModule} from '../../src/common/src/angular1';
import {$INJECTOR, $PROVIDE, DOWNGRADED_MODULE_COUNT_KEY, INJECTOR_KEY, LAZY_MODULE_REF, UPGRADE_APP_TYPE_KEY, UPGRADE_MODULE_NAME} from '../../src/common/src/constants';
import {destroyApp, getDowngradedModuleCount, isFunction, isNgModuleType, LazyModuleRef, UpgradeAppType} from '../../src/common/src/util';
import {ɵangular1, ɵconstants, ɵutil} from '../common';
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
import {NgAdapterInjector} from './util';
@@ -366,16 +364,16 @@ export function downgradeModule<T>(moduleOrBootstrapFn: NgModuleFactory<T>): str
*/
export function downgradeModule<T>(moduleOrBootstrapFn: Type<T>|NgModuleFactory<T>|(
(extraProviders: StaticProvider[]) => Promise<NgModuleRef<T>>)): string {
const lazyModuleName = `${UPGRADE_MODULE_NAME}.lazy${++moduleUid}`;
const lazyModuleRefKey = `${LAZY_MODULE_REF}${lazyModuleName}`;
const lazyInjectorKey = `${INJECTOR_KEY}${lazyModuleName}`;
const lazyModuleName = `${ɵconstants.UPGRADE_MODULE_NAME}.lazy${++moduleUid}`;
const lazyModuleRefKey = `${ɵconstants.LAZY_MODULE_REF}${lazyModuleName}`;
const lazyInjectorKey = `${ɵconstants.INJECTOR_KEY}${lazyModuleName}`;
let bootstrapFn: (extraProviders: StaticProvider[]) => Promise<NgModuleRef<T>>;
if (isNgModuleType(moduleOrBootstrapFn)) {
if (ɵutil.isNgModuleType(moduleOrBootstrapFn)) {
// NgModule class
bootstrapFn = (extraProviders: StaticProvider[]) =>
platformBrowser(extraProviders).bootstrapModule(moduleOrBootstrapFn);
} else if (!isFunction(moduleOrBootstrapFn)) {
} else if (!ɵutil.isFunction(moduleOrBootstrapFn)) {
// NgModule factory
bootstrapFn = (extraProviders: StaticProvider[]) =>
platformBrowser(extraProviders).bootstrapModuleFactory(moduleOrBootstrapFn);
@@ -387,9 +385,9 @@ export function downgradeModule<T>(moduleOrBootstrapFn: Type<T>|NgModuleFactory<
let injector: Injector;
// Create an ng1 module to bootstrap.
angularModule(lazyModuleName, [])
.constant(UPGRADE_APP_TYPE_KEY, UpgradeAppType.Lite)
.factory(INJECTOR_KEY, [lazyInjectorKey, identity])
ɵangular1.module_(lazyModuleName, [])
.constant(ɵconstants.UPGRADE_APP_TYPE_KEY, ɵutil.UpgradeAppType.Lite)
.factory(ɵconstants.INJECTOR_KEY, [lazyInjectorKey, identity])
.factory(
lazyInjectorKey,
() => {
@@ -400,24 +398,24 @@ export function downgradeModule<T>(moduleOrBootstrapFn: Type<T>|NgModuleFactory<
}
return injector;
})
.factory(LAZY_MODULE_REF, [lazyModuleRefKey, identity])
.factory(ɵconstants.LAZY_MODULE_REF, [lazyModuleRefKey, identity])
.factory(
lazyModuleRefKey,
[
$INJECTOR,
($injector: IInjectorService) => {
ɵconstants.$INJECTOR,
($injector: ɵangular1.IInjectorService) => {
setTempInjectorRef($injector);
const result: LazyModuleRef = {
const result: ɵutil.LazyModuleRef = {
promise: bootstrapFn(angular1Providers).then(ref => {
injector = result.injector = new NgAdapterInjector(ref.injector);
injector.get($INJECTOR);
injector.get(ɵconstants.$INJECTOR);
// Destroy the AngularJS app once the Angular `PlatformRef` is destroyed.
// This does not happen in a typical SPA scenario, but it might be useful for
// other use-cases where disposing of an Angular/AngularJS app is necessary
// (such as Hot Module Replacement (HMR)).
// See https://github.com/angular/angular/issues/39935.
injector.get(PlatformRef).onDestroy(() => destroyApp($injector));
injector.get(PlatformRef).onDestroy(() => ɵutil.destroyApp($injector));
return injector;
})
@@ -426,9 +424,11 @@ export function downgradeModule<T>(moduleOrBootstrapFn: Type<T>|NgModuleFactory<
}
])
.config([
$INJECTOR, $PROVIDE,
($injector: IInjectorService, $provide: IProvideService) => {
$provide.constant(DOWNGRADED_MODULE_COUNT_KEY, getDowngradedModuleCount($injector) + 1);
ɵconstants.$INJECTOR, ɵconstants.$PROVIDE,
($injector: ɵangular1.IInjectorService, $provide: ɵangular1.IProvideService) => {
$provide.constant(
ɵconstants.DOWNGRADED_MODULE_COUNT_KEY,
ɵutil.getDowngradedModuleCount($injector) + 1);
}
]);
@@ -8,10 +8,7 @@
import {Directive, DoCheck, ElementRef, EventEmitter, Injector, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core';
import {IAttributes, IAugmentedJQuery, IDirective, IInjectorService, ILinkFn, IScope, ITranscludeFunction} from '../../src/common/src/angular1';
import {$SCOPE} from '../../src/common/src/constants';
import {IBindingDestination, IControllerInstance, UpgradeHelper} from '../../src/common/src/upgrade_helper';
import {isFunction} from '../../src/common/src/util';
import {ɵangular1, ɵconstants, ɵupgradeHelper, ɵutil} from '../common';
const NOT_SUPPORTED: any = 'NOT_SUPPORTED';
const INITIAL_VALUE = {
@@ -69,16 +66,16 @@ class Bindings {
*/
@Directive()
export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
private helper: UpgradeHelper;
private helper: ɵupgradeHelper.UpgradeHelper;
private $element: IAugmentedJQuery;
private $componentScope: IScope;
private $element: ɵangular1.IAugmentedJQuery;
private $componentScope: ɵangular1.IScope;
private directive: IDirective;
private directive: ɵangular1.IDirective;
private bindings: Bindings;
private controllerInstance?: IControllerInstance;
private bindingDestination?: IBindingDestination;
private controllerInstance?: ɵupgradeHelper.IControllerInstance;
private bindingDestination?: ɵupgradeHelper.IBindingDestination;
// We will be instantiating the controller in the `ngOnInit` hook, when the
// first `ngOnChanges` will have been already triggered. We store the
@@ -99,7 +96,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
* injection into the base class constructor.
*/
constructor(name: string, elementRef: ElementRef, injector: Injector) {
this.helper = new UpgradeHelper(injector, name, elementRef);
this.helper = new ɵupgradeHelper.UpgradeHelper(injector, name, elementRef);
this.$element = this.helper.$element;
@@ -108,7 +105,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
// We ask for the AngularJS scope from the Angular injector, since
// we will put the new component scope onto the new injector for each component
const $parentScope = injector.get($SCOPE);
const $parentScope = injector.get(ɵconstants.$SCOPE);
// QUESTION 1: Should we create an isolated scope if the scope is only true?
// QUESTION 2: Should we make the scope accessible through `$element.scope()/isolateScope()`?
this.$componentScope = $parentScope.$new(!!this.directive.scope);
@@ -119,7 +116,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
/** @nodoc */
ngOnInit() {
// Collect contents, insert and compile template
const attachChildNodes: ILinkFn|undefined = this.helper.prepareTransclusion();
const attachChildNodes: ɵangular1.ILinkFn|undefined = this.helper.prepareTransclusion();
const linkFn = this.helper.compileTemplate();
// Instantiate controller
@@ -128,7 +125,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
let controllerInstance = controllerType ?
this.helper.buildController(controllerType, this.$componentScope) :
undefined;
let bindingDestination: IBindingDestination;
let bindingDestination: ɵupgradeHelper.IBindingDestination;
if (!bindToController) {
bindingDestination = this.$componentScope;
@@ -154,12 +151,12 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
}
// Hook: $onInit
if (this.controllerInstance && isFunction(this.controllerInstance.$onInit)) {
if (this.controllerInstance && ɵutil.isFunction(this.controllerInstance.$onInit)) {
this.controllerInstance.$onInit();
}
// Hook: $doCheck
if (controllerInstance && isFunction(controllerInstance.$doCheck)) {
if (controllerInstance && ɵutil.isFunction(controllerInstance.$doCheck)) {
const callDoCheck = () => controllerInstance?.$doCheck?.();
this.unregisterDoCheckWatcher = this.$componentScope.$parent.$watch(callDoCheck);
@@ -170,8 +167,8 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
const link = this.directive.link;
const preLink = typeof link == 'object' && link.pre;
const postLink = typeof link == 'object' ? link.post : link;
const attrs: IAttributes = NOT_SUPPORTED;
const transcludeFn: ITranscludeFunction = NOT_SUPPORTED;
const attrs: ɵangular1.IAttributes = NOT_SUPPORTED;
const transcludeFn: ɵangular1.ITranscludeFunction = NOT_SUPPORTED;
if (preLink) {
preLink(this.$componentScope, this.$element, attrs, requiredControllers, transcludeFn);
}
@@ -183,7 +180,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
}
// Hook: $postLink
if (this.controllerInstance && isFunction(this.controllerInstance.$postLink)) {
if (this.controllerInstance && ɵutil.isFunction(this.controllerInstance.$postLink)) {
this.controllerInstance.$postLink();
}
}
@@ -219,13 +216,13 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
/** @nodoc */
ngOnDestroy() {
if (isFunction(this.unregisterDoCheckWatcher)) {
if (ɵutil.isFunction(this.unregisterDoCheckWatcher)) {
this.unregisterDoCheckWatcher();
}
this.helper.onDestroy(this.$componentScope, this.controllerInstance);
}
private initializeBindings(directive: IDirective, name: string) {
private initializeBindings(directive: ɵangular1.IDirective, name: string) {
const btcIsObject = typeof directive.bindToController === 'object';
if (btcIsObject && Object.keys(directive.scope!).length) {
throw new Error(
@@ -278,7 +275,7 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
});
}
private bindOutputs(bindingDestination: IBindingDestination) {
private bindOutputs(bindingDestination: ɵupgradeHelper.IBindingDestination) {
// Bind `&` bindings to the corresponding outputs
this.bindings.expressionBoundProperties.forEach(propName => {
const outputName = this.bindings.propertyToOutputMap[propName];
@@ -288,12 +285,13 @@ export class UpgradeComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
});
}
private forwardChanges(changes: SimpleChanges, bindingDestination: IBindingDestination) {
private forwardChanges(
changes: SimpleChanges, bindingDestination: ɵupgradeHelper.IBindingDestination) {
// Forward input changes to `bindingDestination`
Object.keys(changes).forEach(
propName => bindingDestination[propName] = changes[propName].currentValue);
if (isFunction(bindingDestination.$onChanges)) {
if (ɵutil.isFunction(bindingDestination.$onChanges)) {
bindingDestination.$onChanges(changes);
}
}
+29 -26
View File
@@ -8,9 +8,7 @@
import {Injector, NgModule, NgZone, PlatformRef, Testability} from '@angular/core';
import {bootstrap, element as angularElement, IInjectorService, IIntervalService, IProvideService, ITestabilityService, module_ as angularModule} from '../../src/common/src/angular1';
import {$$TESTABILITY, $DELEGATE, $INJECTOR, $INTERVAL, $PROVIDE, INJECTOR_KEY, LAZY_MODULE_REF, UPGRADE_APP_TYPE_KEY, UPGRADE_MODULE_NAME} from '../../src/common/src/constants';
import {controllerKey, destroyApp, LazyModuleRef, UpgradeAppType} from '../../src/common/src/util';
import {ɵangular1, ɵconstants, ɵutil} from '../common';
import {angular1Providers, setTempInjectorRef} from './angular1_providers';
import {NgAdapterInjector} from './util';
@@ -176,25 +174,27 @@ export class UpgradeModule {
bootstrap(
element: Element, modules: string[] = [], config?: any /*angular.IAngularBootstrapConfig*/):
any /*ReturnType<typeof angular.bootstrap>*/ {
const INIT_MODULE_NAME = UPGRADE_MODULE_NAME + '.init';
const INIT_MODULE_NAME = ɵconstants.UPGRADE_MODULE_NAME + '.init';
// Create an ng1 module to bootstrap
angularModule(INIT_MODULE_NAME, [])
ɵangular1
.module_(INIT_MODULE_NAME, [])
.constant(UPGRADE_APP_TYPE_KEY, UpgradeAppType.Static)
.constant(ɵconstants.UPGRADE_APP_TYPE_KEY, ɵutil.UpgradeAppType.Static)
.value(INJECTOR_KEY, this.injector)
.value(ɵconstants.INJECTOR_KEY, this.injector)
.factory(
LAZY_MODULE_REF, [INJECTOR_KEY, (injector: Injector) => ({injector} as LazyModuleRef)])
ɵconstants.LAZY_MODULE_REF,
[ɵconstants.INJECTOR_KEY, (injector: Injector) => ({injector} as ɵutil.LazyModuleRef)])
.config([
$PROVIDE, $INJECTOR,
($provide: IProvideService, $injector: IInjectorService) => {
if ($injector.has($$TESTABILITY)) {
$provide.decorator($$TESTABILITY, [
$DELEGATE,
(testabilityDelegate: ITestabilityService) => {
ɵconstants.$PROVIDE, ɵconstants.$INJECTOR,
($provide: ɵangular1.IProvideService, $injector: ɵangular1.IInjectorService) => {
if ($injector.has(ɵconstants.$$TESTABILITY)) {
$provide.decorator(ɵconstants.$$TESTABILITY, [
ɵconstants.$DELEGATE,
(testabilityDelegate: ɵangular1.ITestabilityService) => {
const originalWhenStable: Function = testabilityDelegate.whenStable;
const injector = this.injector;
// Cannot use arrow function below because we need the context
@@ -216,10 +216,10 @@ export class UpgradeModule {
]);
}
if ($injector.has($INTERVAL)) {
$provide.decorator($INTERVAL, [
$DELEGATE,
(intervalDelegate: IIntervalService) => {
if ($injector.has(ɵconstants.$INTERVAL)) {
$provide.decorator(ɵconstants.$INTERVAL, [
ɵconstants.$DELEGATE,
(intervalDelegate: ɵangular1.IIntervalService) => {
// Wrap the $interval service so that setInterval is called outside NgZone,
// but the callback is still invoked within it. This is so that $interval
// won't block stability, which preserves the behavior from AngularJS.
@@ -239,7 +239,7 @@ export class UpgradeModule {
});
};
(Object.keys(intervalDelegate) as (keyof IIntervalService)[])
(Object.keys(intervalDelegate) as (keyof ɵangular1.IIntervalService)[])
.forEach(prop => (wrappedInterval as any)[prop] = intervalDelegate[prop]);
// the `flush` method will be present when ngMocks is used
@@ -258,24 +258,25 @@ export class UpgradeModule {
])
.run([
$INJECTOR,
($injector: IInjectorService) => {
ɵconstants.$INJECTOR,
($injector: ɵangular1.IInjectorService) => {
this.$injector = $injector;
const $rootScope = $injector.get('$rootScope');
// Initialize the ng1 $injector provider
setTempInjectorRef($injector);
this.injector.get($INJECTOR);
this.injector.get(ɵconstants.$INJECTOR);
// Put the injector on the DOM, so that it can be "required"
angularElement(element).data!(controllerKey(INJECTOR_KEY), this.injector);
ɵangular1.element(element).data!
(ɵutil.controllerKey(ɵconstants.INJECTOR_KEY), this.injector);
// Destroy the AngularJS app once the Angular `PlatformRef` is destroyed.
// This does not happen in a typical SPA scenario, but it might be useful for
// other use-cases where disposing of an Angular/AngularJS app is necessary
// (such as Hot Module Replacement (HMR)).
// See https://github.com/angular/angular/issues/39935.
this.platformRef.onDestroy(() => destroyApp($injector));
this.platformRef.onDestroy(() => ɵutil.destroyApp($injector));
// Wire up the ng1 rootScope to run a digest cycle whenever the zone settles
// We need to do this in the next tick so that we don't prevent the bootup stabilizing
@@ -299,14 +300,16 @@ export class UpgradeModule {
}
]);
const upgradeModule = angularModule(UPGRADE_MODULE_NAME, [INIT_MODULE_NAME].concat(modules));
const upgradeModule =
ɵangular1.module_(ɵconstants.UPGRADE_MODULE_NAME, [INIT_MODULE_NAME].concat(modules));
// Make sure resumeBootstrap() only exists if the current bootstrap is deferred
const windowAngular = (window as any)['angular'];
windowAngular.resumeBootstrap = undefined;
// Bootstrap the AngularJS application inside our zone
const returnValue = this.ngZone.run(() => bootstrap(element, [upgradeModule.name], config));
const returnValue =
this.ngZone.run(() => ɵangular1.bootstrap(element, [upgradeModule.name], config));
// Patch resumeBootstrap() to run inside the ngZone
if (windowAngular.resumeBootstrap) {
+1 -1
View File
@@ -14,7 +14,7 @@ ng_module(
),
deps = [
"//packages/core/testing",
"//packages/upgrade/src/common",
"//packages/upgrade/static",
],
)
@@ -7,9 +7,8 @@
*/
import {Injector, NgModule, Type} from '@angular/core';
import {ɵangular1 as angular, ɵconstants} from '@angular/upgrade/static';
import * as angular from '../../../src/common/src/angular1';
import {$INJECTOR, INJECTOR_KEY, UPGRADE_APP_TYPE_KEY} from '../../../src/common/src/constants';
import {UpgradeAppType} from '../../../src/common/src/util';
let $injector: angular.IInjectorService|null = null;
@@ -19,7 +18,7 @@ export function $injectorFactory() {
return $injector;
}
@NgModule({providers: [{provide: $INJECTOR, useFactory: $injectorFactory}]})
@NgModule({providers: [{provide: ɵconstants.$INJECTOR, useFactory: $injectorFactory}]})
export class AngularTestingModule {
constructor(i: Injector) {
injector = i;
@@ -94,8 +93,8 @@ export class AngularTestingModule {
export function createAngularTestingModule(
angularJSModules: string[], strictDi?: boolean): Type<any> {
angular.module_('$$angularJSTestingModule', angularJSModules)
.constant(UPGRADE_APP_TYPE_KEY, UpgradeAppType.Static)
.factory(INJECTOR_KEY, () => injector);
.constant(ɵconstants.UPGRADE_APP_TYPE_KEY, UpgradeAppType.Static)
.factory(ɵconstants.INJECTOR_KEY, () => injector);
$injector = angular.injector(['ng', '$$angularJSTestingModule'], strictDi);
return AngularTestingModule;
}
@@ -8,9 +8,8 @@
import {Injector} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {ɵangular1 as ng, ɵconstants} from '@angular/upgrade/static';
import * as ng from '../../../src/common/src/angular1';
import {$INJECTOR, INJECTOR_KEY, UPGRADE_APP_TYPE_KEY} from '../../../src/common/src/constants';
import {UpgradeAppType} from '../../../src/common/src/util';
@@ -83,15 +82,15 @@ import {UpgradeAppType} from '../../../src/common/src/util';
*/
export function createAngularJSTestingModule(angularModules: any[]): string {
return ng.module_('$$angularJSTestingModule', [])
.constant(UPGRADE_APP_TYPE_KEY, UpgradeAppType.Static)
.constant(ɵconstants.UPGRADE_APP_TYPE_KEY, UpgradeAppType.Static)
.factory(
INJECTOR_KEY,
ɵconstants.INJECTOR_KEY,
[
$INJECTOR,
ɵconstants.$INJECTOR,
($injector: ng.IInjectorService) => {
TestBed.configureTestingModule({
imports: angularModules,
providers: [{provide: $INJECTOR, useValue: $injector}]
providers: [{provide: ɵconstants.$INJECTOR, useValue: $injector}]
});
return TestBed.inject(Injector);
}