Skip to content

Commit

Permalink
fix(core): fix angular#405, refine the error message when zone.js alr…
Browse files Browse the repository at this point in the history
…eady loaded.
  • Loading branch information
JiaLiPassion committed Apr 7, 2017
1 parent 0d0ee53 commit 5d0bb09
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
38 changes: 35 additions & 3 deletions lib/zone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,21 @@ type AmbientZoneDelegate = ZoneDelegate;

const Zone: ZoneType = (function(global: any) {
if (global['Zone']) {
throw new Error('Zone already loaded.');
let zoneAlreadyLoadedMessage: string = 'Zone already loaded.';
// try to findout the already loaded zone.js script file
// require the loaded zone.js version to be newer than 0.8.6
try {
const LoadedZone: any = global['Zone'];
if (LoadedZone['assertZonePatched']) {
const scriptFileName: string = LoadedZone['__zone_symbol__scriptFileName'];
if (scriptFileName) {
zoneAlreadyLoadedMessage =
'Zone already loaded. The loaded Zone.js script file seems to be ' + scriptFileName;
}
}
} catch (error) {
}
throw new Error(zoneAlreadyLoadedMessage);
}

const NO_ZONE = {name: 'NO ZONE'};
Expand All @@ -623,12 +637,17 @@ const Zone: ZoneType = (function(global: any) {

static assertZonePatched() {
if (global.Promise !== ZoneAwarePromise) {
// try to findout the already loaded zone.js script file
// require the loaded zone.js version to be newer than 0.8.6
const scriptFileName: string = (Zone as any)[__symbol__('scriptFileName')];
const scriptFileErrorMessage: string =
scriptFileName ? 'the loaded Zone.js script file seems to be ' + scriptFileName : '';
throw new Error(
'Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' +
'has been overwritten.\n' +
'Most likely cause is that a Promise polyfill has been loaded ' +
'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' +
'If you must load one, do so before loading zone.js.)');
'If you must load one, do so before loading zone.js.)' + scriptFileErrorMessage);
}
}

Expand Down Expand Up @@ -1803,11 +1822,24 @@ const Zone: ZoneType = (function(global: any) {
// Chrome: at Zone.run (http://localhost:9876/base/build/lib/zone.js:100:24)
// FireFox: Zone.prototype.run@http://localhost:9876/base/build/lib/zone.js:101:24
// Safari: run@http://localhost:9876/base/build/lib/zone.js:101:24
let fnName: string = frame.split('(')[0].split('@')[0];
let frameParts: string[] = frame.split('(');
let fnNamePart: string = frameParts[0];

let fnName: string = fnNamePart.split('@')[0];
let frameType = FrameType.transition;
if (fnName.indexOf('ZoneAwareError') !== -1) {
zoneAwareFrame1 = frame;
zoneAwareFrame2 = frame.replace('Error.', '');

// try to find the filename where zone.js live with
let fileNamePart1: string = frameParts.length > 1 ? frameParts[1] : fnNamePart;
let fileNameParts: string[] = fileNamePart1.split('@');
let fileNamePart2: string =
fileNameParts.length > 1 ? fileNameParts[1] : fileNameParts[0];
// Keep a script file name in Zone, so when zone.js report 'already loaded'
// error, it can report which file include the loaded zone.js
(Zone as any)[__symbol__('scriptFileName')] = fileNamePart2;

blackListedStackFrames[zoneAwareFrame2] = FrameType.blackList;
}
if (fnName.indexOf('runGuarded') !== -1) {
Expand Down
14 changes: 13 additions & 1 deletion test/common/zone.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,12 +328,24 @@ describe('Zone', function() {

it('should throw when Promise has been patched', () => {
class WrongPromise {}
const errorMessage =
'Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' +
'has been overwritten.';
const errorScriptMessage = 'the loaded Zone.js script file seems to be';

const ZoneAwarePromise = global.Promise;
global.Promise = WrongPromise;
try {
expect(ZoneAwarePromise).toBeTruthy();
expect(() => Zone.assertZonePatched()).toThrow();
try {
Zone.assertZonePatched();
} catch (error) {
expect(error.message).toContain(errorMessage);
expect(error.message).toContain(errorScriptMessage);
const idx = error.message.lastIndexOf(errorScriptMessage);
const fileName: string = error.message.slice(idx + errorScriptMessage.length);
expect(fileName).toContain('zone.js');
}
} finally {
// restore it.
global.Promise = ZoneAwarePromise;
Expand Down

0 comments on commit 5d0bb09

Please sign in to comment.