Skip to content

Commit

Permalink
fix: snapshot global when loading plugins
Browse files Browse the repository at this point in the history
This allows us to load anything that modifies the `global` object and then restore it afterward. This is needed in particular for `@babel/polyfill` since it sets a global property to try to warn the user if it's being loaded more than once.
  • Loading branch information
eventualbuddha committed Jan 30, 2019
1 parent 528830a commit af933a2
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 9 deletions.
10 changes: 10 additions & 0 deletions packages/cli/src/ProcessSnapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ export default class ProcessSnapshot {
constructor(
private readonly requireImpl: typeof require = require,
private readonly processImpl: typeof process = process,
private readonly originalGlobal: typeof global = global,
private readonly log: typeof console.log = () => {}
) {
this.cacheEntries = this.snapshotRequireCache();
this.extensions = this.snapshotRequireExtensions();
this.processEvents = this.snapshotProcessEvents();
this.originalGlobal.global = Object.create(originalGlobal);
}

/**
Expand All @@ -46,6 +48,7 @@ export default class ProcessSnapshot {
this.restoreRequireCache();
this.restoreExtensions();
this.restoreProcessEvents();
this.restoreGlobal();
}

/**
Expand Down Expand Up @@ -172,6 +175,13 @@ export default class ProcessSnapshot {
}
}

/**
* Restores the state of the `global` object.
*/
private restoreGlobal(): void {
this.originalGlobal.global = this.originalGlobal;
}

/**
* Snapshots the current state of `require.cache`.
*/
Expand Down
83 changes: 74 additions & 9 deletions packages/cli/test/unit/ProcessSnapshotTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ProcessSnapshot from '../../src/ProcessSnapshot';
describe('ProcessSnapshot', function() {
let fakeRequire: typeof require;
let fakeProcess: typeof process;
let fakeGlobal: typeof global;
let messages: Array<string>;

function log(...args: Array<{}>): void {
Expand All @@ -21,12 +22,19 @@ describe('ProcessSnapshot', function() {
fakeProcess['_events'] = Object.create(fakeProcess['_events']);
fakeProcess.removeAllListeners();

fakeGlobal = Object.create(global);

messages = [];
});

it('removes added require entries from the cache', function() {
// Take a snapshot.
let snapshot = new ProcessSnapshot(fakeRequire, fakeProcess, log);
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

// Add a file to the cache.
let path = '/some/added/file';
Expand All @@ -47,7 +55,12 @@ describe('ProcessSnapshot', function() {
ok(path in fakeRequire.cache);

// Take a snapshot.
let snapshot = new ProcessSnapshot(fakeRequire, fakeProcess, log);
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

// Remove a file from the cache.
delete fakeRequire.cache[path];
Expand All @@ -70,7 +83,12 @@ describe('ProcessSnapshot', function() {
ok(path in fakeRequire.cache);

// Take a snapshot.
let snapshot = new ProcessSnapshot(fakeRequire, fakeProcess, log);
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

// Replace a file in the cache.
fakeRequire.cache[path] = new Module(path);
Expand All @@ -86,7 +104,12 @@ describe('ProcessSnapshot', function() {

it('removes added require extensions', function() {
// Take a snapshot.
let snapshot = new ProcessSnapshot(fakeRequire, fakeProcess, log);
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

// Add a require extension.
fakeRequire.extensions['.omg'] = () => {};
Expand All @@ -103,7 +126,12 @@ describe('ProcessSnapshot', function() {
fakeRequire.extensions['.omg'] = () => {};

// Take a snapshot.
let snapshot = new ProcessSnapshot(fakeRequire, fakeProcess, log);
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

// Remove the extension.
delete fakeRequire.extensions['.omg'];
Expand All @@ -121,7 +149,12 @@ describe('ProcessSnapshot', function() {
fakeRequire.extensions['.omg'] = originalLoader;

// Take a snapshot.
let snapshot = new ProcessSnapshot(fakeRequire, fakeProcess, log);
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

// Replace a require extension.
fakeRequire.extensions['.omg'] = () => {};
Expand All @@ -135,7 +168,12 @@ describe('ProcessSnapshot', function() {

it('removes added process event listeners', function() {
// Take a snapshot.
let snapshot = new ProcessSnapshot(fakeRequire, fakeProcess, log);
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

// Add an event listener.
let listener = (): void => {};
Expand All @@ -154,7 +192,12 @@ describe('ProcessSnapshot', function() {
fakeProcess.on('exit', listener);

// Take a snapshot.
let snapshot = new ProcessSnapshot(fakeRequire, fakeProcess, log);
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

// Remove the event listener.
fakeProcess.removeListener('exit', listener);
Expand All @@ -172,7 +215,12 @@ describe('ProcessSnapshot', function() {
fakeProcess.on('exit', existingListener);

// Take a snapshot.
let snapshot = new ProcessSnapshot(fakeRequire, fakeProcess, log);
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

// Add an event listener.
let listener = (): void => {};
Expand All @@ -184,4 +232,21 @@ describe('ProcessSnapshot', function() {
deepEqual(messages, [`removing added 'exit' event listener`]);
deepEqual(fakeProcess.listeners('exit'), [existingListener]);
});

it('restores `global`', function() {
// Take a snapshot.
let snapshot = new ProcessSnapshot(
fakeRequire,
fakeProcess,
fakeGlobal,
log
);

fakeGlobal.global['foo'] = 123;

// Restore the snapshot.
snapshot.restore();

strictEqual(fakeGlobal.global['foo'], undefined);
});
});

0 comments on commit af933a2

Please sign in to comment.