Skip to content

Commit

Permalink
refactor(core): make the error messages tree shakable (#44219)
Browse files Browse the repository at this point in the history
Long error messages can be tree-shaken in the production build.
Doing this, we will keep the throw and remove the long error messages.

See: #44210 (review)

PR Close #44219
  • Loading branch information
ramthir authored and dylhunn committed Nov 30, 2021
1 parent 66b73d4 commit 277390e
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 30 deletions.
4 changes: 2 additions & 2 deletions goldens/size-tracking/aio-payloads.json
Expand Up @@ -15,12 +15,12 @@
"master": {
"uncompressed": {
"runtime": 4436,
"main": 459822,
"main": 459047,
"polyfills": 37271,
"styles": 70719,
"light-theme": 77717,
"dark-theme": 77897
}
}
}
}
}
14 changes: 7 additions & 7 deletions goldens/size-tracking/integration-payloads.json
Expand Up @@ -3,8 +3,8 @@
"master": {
"uncompressed": {
"runtime": 1083,
"main": 138745,
"polyfills": 37226
"main": 138491,
"polyfills": 36964
}
}
},
Expand All @@ -24,7 +24,7 @@
"master": {
"uncompressed": {
"runtime": 1105,
"main": 144744,
"main": 144185,
"polyfills": 36939
}
}
Expand All @@ -33,7 +33,7 @@
"master": {
"uncompressed": {
"runtime": 929,
"main": 137444,
"main": 136770,
"polyfills": 37933
}
}
Expand All @@ -42,7 +42,7 @@
"master": {
"uncompressed": {
"runtime": 2843,
"main": 231164,
"main": 230506,
"polyfills": 37064,
"src_app_lazy_lazy_module_ts": 795
}
Expand All @@ -52,7 +52,7 @@
"master": {
"uncompressed": {
"runtime": 1063,
"main": 164069,
"main": 163342,
"polyfills": 36975
}
}
Expand All @@ -68,4 +68,4 @@
}
}
}
}
}
51 changes: 35 additions & 16 deletions packages/core/src/application_ref.ts
Expand Up @@ -32,6 +32,7 @@ import {InternalViewRef, ViewRef} from './linker/view_ref';
import {isComponentResourceResolutionQueueEmpty, resolveComponentResources} from './metadata/resource_loading';
import {assertNgModuleType} from './render3/assert';
import {ComponentFactory as R3ComponentFactory} from './render3/component_ref';
import {RuntimeError, RuntimeErrorCode} from './render3/error_code';
import {setLocaleId} from './render3/i18n/i18n_locale_id';
import {setJitOptions} from './render3/jit/jit_options';
import {NgModuleFactory as R3NgModuleFactory} from './render3/ng_module_ref';
Expand Down Expand Up @@ -123,8 +124,10 @@ export class NgProbeToken {
export function createPlatform(injector: Injector): PlatformRef {
if (_platform && !_platform.destroyed &&
!_platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
throw new Error(
'There can be only one platform. Destroy the previous one to create a new one.');
const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
'There can be only one platform. Destroy the previous one to create a new one.' :
'';
throw new RuntimeError(RuntimeErrorCode.MULTIPLE_PLATFORMS, errorMessage);
}
publishDefaultGlobalUtils();
_platform = injector.get(PlatformRef);
Expand Down Expand Up @@ -177,11 +180,15 @@ export function assertPlatform(requiredToken: any): PlatformRef {
const platform = getPlatform();

if (!platform) {
throw new Error('No platform exists!');
const errorMessage =
(typeof ngDevMode === 'undefined' || ngDevMode) ? 'No platform exists!' : '';
throw new RuntimeError(RuntimeErrorCode.PLATFORM_NOT_FOUND, errorMessage);
}

if (!platform.injector.get(requiredToken, null)) {
throw new Error(
if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
!platform.injector.get(requiredToken, null)) {
throw new RuntimeError(
RuntimeErrorCode.MULTIPLE_PLATFORMS,
'A platform with a different configuration has been created. Please destroy it first.');
}

Expand Down Expand Up @@ -329,7 +336,10 @@ export class PlatformRef {
const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector);
const exceptionHandler: ErrorHandler|null = moduleRef.injector.get(ErrorHandler, null);
if (!exceptionHandler) {
throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
'No ErrorHandler. Is platform module (BrowserModule) included?' :
'';
throw new RuntimeError(RuntimeErrorCode.ERROR_HANDLER_NOT_FOUND, errorMessage);
}
ngZone!.runOutsideAngular(() => {
const subscription = ngZone!.onError.subscribe({
Expand Down Expand Up @@ -388,12 +398,12 @@ export class PlatformRef {
} else if (moduleRef.instance.ngDoBootstrap) {
moduleRef.instance.ngDoBootstrap(appRef);
} else {
throw new Error(
`The module ${
stringify(
moduleRef.instance
.constructor)} was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` +
`Please define one of these.`);
const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
`The module ${stringify(moduleRef.instance.constructor)} was bootstrapped, ` +
`but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` +
`Please define one of these.` :
'';
throw new RuntimeError(RuntimeErrorCode.BOOTSTRAP_COMPONENTS_NOT_FOUND, errorMessage);
}
this._modules.push(moduleRef);
}
Expand All @@ -419,7 +429,10 @@ export class PlatformRef {
*/
destroy() {
if (this._destroyed) {
throw new Error('The platform has already been destroyed!');
const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
'The platform has already been destroyed!' :
'';
throw new RuntimeError(RuntimeErrorCode.ALREADY_DESTROYED_PLATFORM, errorMessage);
}
this._modules.slice().forEach(module => module.destroy());
this._destroyListeners.forEach(listener => listener());
Expand Down Expand Up @@ -782,8 +795,11 @@ export class ApplicationRef {
bootstrap<C>(componentOrFactory: ComponentFactory<C>|Type<C>, rootSelectorOrNode?: string|any):
ComponentRef<C> {
if (!this._initStatus.done) {
throw new Error(
'Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.');
const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
'Cannot bootstrap as there are still asynchronous initializers running. ' +
'Bootstrap components in the `ngDoBootstrap` method of the root module.' :
'';
throw new RuntimeError(RuntimeErrorCode.ASYNC_INITIALIZERS_STILL_RUNNING, errorMessage);
}
let componentFactory: ComponentFactory<C>;
if (componentOrFactory instanceof ComponentFactory) {
Expand Down Expand Up @@ -835,7 +851,10 @@ export class ApplicationRef {
*/
tick(): void {
if (this._runningTick) {
throw new Error('ApplicationRef.tick is called recursively');
const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
'ApplicationRef.tick is called recursively' :
'';
throw new RuntimeError(RuntimeErrorCode.RECURSIVE_APPLICATION_REF_TICK, errorMessage);
}

try {
Expand Down
11 changes: 10 additions & 1 deletion packages/core/src/render3/error_code.ts
Expand Up @@ -13,6 +13,7 @@ export const enum RuntimeErrorCode {

// Change Detection Errors
EXPRESSION_CHANGED_AFTER_CHECKED = '100',
RECURSIVE_APPLICATION_REF_TICK = '101',

// Dependency Injection Errors
CYCLIC_DI_DEPENDENCY = '200',
Expand All @@ -24,7 +25,15 @@ export const enum RuntimeErrorCode {
PIPE_NOT_FOUND = '302',
UNKNOWN_BINDING = '303',
UNKNOWN_ELEMENT = '304',
TEMPLATE_STRUCTURE_ERROR = '305'
TEMPLATE_STRUCTURE_ERROR = '305',

// Bootstrap Errors
MULTIPLE_PLATFORMS = '400',
PLATFORM_NOT_FOUND = '401',
ERROR_HANDLER_NOT_FOUND = '402',
BOOTSTRAP_COMPONENTS_NOT_FOUND = '403',
ALREADY_DESTROYED_PLATFORM = '404',
ASYNC_INITIALIZERS_STILL_RUNNING = '405',

// Styling Errors

Expand Down
9 changes: 5 additions & 4 deletions packages/core/test/application_ref_spec.ts
Expand Up @@ -166,7 +166,7 @@ class SomeComponent {
appRef.attachView(fixture.componentRef.hostView);
appRef.tick();
expect(fixture.componentInstance.reenterErr.message)
.toBe('ApplicationRef.tick is called recursively');
.toBe('NG0101: ApplicationRef.tick is called recursively');
});

describe('APP_BOOTSTRAP_LISTENER', () => {
Expand Down Expand Up @@ -204,7 +204,7 @@ class SomeComponent {
createRootEl();
expect(() => ref.bootstrap(SomeComponent))
.toThrowError(
'Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.');
'NG0405: Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.');
})));
});
});
Expand Down Expand Up @@ -273,7 +273,8 @@ class SomeComponent {
return defaultPlatform.bootstrapModule(EmptyModule)
.then(() => fail('expecting error'), (error) => {
expect(error.message)
.toEqual('No ErrorHandler. Is platform module (BrowserModule) included?');
.toEqual(
'NG0402: No ErrorHandler. Is platform module (BrowserModule) included?');
});
}));

Expand All @@ -300,7 +301,7 @@ class SomeComponent {
defaultPlatform.bootstrapModule(createModule({ngDoBootstrap: false}))
.then(() => expect(false).toBe(true), (e) => {
const expectedErrMsg =
`The module MyModule was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. Please define one of these.`;
`NG0403: The module MyModule was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. Please define one of these.`;
expect(e.message).toEqual(expectedErrMsg);
expect(mockConsole.res[0].join('#')).toEqual('ERROR#Error: ' + expectedErrMsg);
});
Expand Down

0 comments on commit 277390e

Please sign in to comment.