Skip to content

Commit 97aad84

Browse files
Robert Jacksonkrisselden
andcommitted
Make a vm context per visit.
Co-authored-by: Kris Selden <[email protected]>
1 parent 5ad17de commit 97aad84

5 files changed

Lines changed: 70 additions & 105 deletions

File tree

src/ember-app.js

Lines changed: 46 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ class EmberApp {
3131
* @param {Object} [options.sandboxGlobals] - sandbox variables that can be added or used for overrides in the sandbox.
3232
*/
3333
constructor(options) {
34-
let distPath = path.resolve(options.distPath);
34+
// TODO: make these two into builder functions
35+
this.SandboxClass = options.sandbox;
36+
this.sandboxGlobals = options.sandboxGlobals;
37+
38+
let distPath = (this.distPath = path.resolve(options.distPath));
3539
let config = this.readPackageJSON(distPath);
3640

3741
this.appFilePaths = config.appFiles;
@@ -57,23 +61,16 @@ class EmberApp {
5761

5862
this.html = fs.readFileSync(config.htmlFile, 'utf8');
5963

60-
this.sandbox = this.buildSandbox(distPath, options.sandbox, options.sandboxGlobals);
61-
this.app = this.retrieveSandboxedApp();
64+
this.sandboxRequire = this.buildWhitelistedRequire(this.moduleWhitelist, distPath);
6265
}
6366

6467
/**
6568
* @private
6669
*
6770
* Builds and initializes a new sandbox to run the Ember application in.
68-
*
69-
* @param {string} distPath path to the built Ember app to load
70-
* @param {Sandbox} [sandboxClass=VMSandbox] sandbox class to use
71-
* @param {Object} [sandboxGlobals={}] any additional variables to expose in the sandbox or override existing in the sandbox
7271
*/
73-
buildSandbox(distPath, sandboxClass, sandboxGlobals) {
74-
const { config, appName } = this;
75-
76-
let sandboxRequire = this.buildWhitelistedRequire(this.moduleWhitelist, distPath);
72+
buildSandbox() {
73+
const { distPath, SandboxClass, sandboxGlobals, config, appName, sandboxRequire } = this;
7774

7875
function fastbootConfig(key) {
7976
if (!key) {
@@ -89,21 +86,22 @@ class EmberApp {
8986
}
9087

9188
// add any additional user provided variables or override the default globals in the sandbox
92-
let globals = {
93-
najax,
94-
FastBoot: {
95-
require: sandboxRequire,
96-
config: fastbootConfig,
97-
98-
get distPath() {
99-
return distPath;
89+
let globals = Object.assign(
90+
{
91+
najax,
92+
FastBoot: {
93+
require: sandboxRequire,
94+
config: fastbootConfig,
95+
96+
get distPath() {
97+
return distPath;
98+
},
10099
},
101100
},
102-
};
103-
104-
globals = Object.assign(globals, sandboxGlobals);
101+
sandboxGlobals
102+
);
105103

106-
return new sandboxClass({ globals });
104+
return new SandboxClass(globals);
107105
}
108106

109107
/**
@@ -185,8 +183,7 @@ class EmberApp {
185183
* Loads the app and vendor files in the sandbox (Node vm).
186184
*
187185
*/
188-
loadAppFiles() {
189-
let sandbox = this.sandbox;
186+
loadAppFiles(sandbox) {
190187
let appFilePaths = this.appFilePaths;
191188
let vendorFilePaths = this.vendorFilePaths;
192189

@@ -215,9 +212,7 @@ class EmberApp {
215212
* Create the ember application in the sandbox.
216213
*
217214
*/
218-
createEmberApp() {
219-
let sandbox = this.sandbox;
220-
215+
createEmberApp(sandbox) {
221216
// Retrieve the application factory from within the sandbox
222217
let AppFactory = sandbox.run(function(ctx) {
223218
return ctx.require('~fastboot/app-factory');
@@ -234,30 +229,13 @@ class EmberApp {
234229
return AppFactory['default']();
235230
}
236231

237-
/**
238-
* @private
239-
*
240-
* Initializes the sandbox by evaluating the Ember app's JavaScript
241-
* code, then retrieves the application factory from the sandbox and creates a new
242-
* `Ember.Application`.
243-
*
244-
* @returns {Ember.Application} the Ember application from the sandbox
245-
*/
246-
retrieveSandboxedApp() {
247-
this.loadAppFiles();
248-
249-
return this.createEmberApp();
250-
}
251-
252232
/**
253233
* Destroys the app and its sandbox.
254234
*/
255235
destroy() {
256236
if (this.app) {
257237
this.app.destroy();
258238
}
259-
260-
this.sandbox = null;
261239
}
262240

263241
/**
@@ -267,11 +245,15 @@ class EmberApp {
267245
*
268246
* @returns {Promise<Ember.ApplicationInstance>} instance
269247
*/
270-
buildAppInstance() {
271-
return this.app.boot().then(function(app) {
272-
debug('building instance');
273-
return app.buildInstance();
274-
});
248+
async buildAppInstance() {
249+
let sandbox = this.buildSandbox();
250+
251+
this.loadAppFiles(sandbox);
252+
253+
let app = await this.createEmberApp(sandbox).boot();
254+
255+
debug('building instance');
256+
return app.buildInstance();
275257
}
276258

277259
/**
@@ -292,20 +274,15 @@ class EmberApp {
292274
* @param {Object} result
293275
* @return {Promise<instance>} instance
294276
*/
295-
visitRoute(path, fastbootInfo, bootOptions, result) {
296-
let instance;
277+
async visitRoute(path, fastbootInfo, bootOptions, result) {
278+
let instance = await this.buildAppInstance();
297279

298-
return this.buildAppInstance()
299-
.then(appInstance => {
300-
instance = appInstance;
301-
result.instance = instance;
302-
registerFastBootInfo(fastbootInfo, instance);
280+
result.instance = instance;
281+
registerFastBootInfo(fastbootInfo, instance);
303282

304-
return instance.boot(bootOptions);
305-
})
306-
.then(() => instance.visit(path, bootOptions))
307-
.then(() => fastbootInfo.deferredPromise)
308-
.then(() => instance);
283+
await instance.boot(bootOptions);
284+
await instance.visit(path, bootOptions);
285+
await fastbootInfo.deferredPromise;
309286
}
310287

311288
/**
@@ -345,13 +322,9 @@ class EmberApp {
345322
});
346323

347324
let doc = bootOptions.document;
325+
let result = new Result(doc, html, fastbootInfo);
348326

349-
let result = new Result({
350-
doc: doc,
351-
html: html,
352-
fastbootInfo: fastbootInfo,
353-
});
354-
327+
// TODO: Use Promise.race here
355328
let destroyAppInstanceTimer;
356329
if (destroyAppInstanceInMs > 0) {
357330
// start a timer to destroy the appInstance forcefully in the given ms.
@@ -455,14 +428,14 @@ class EmberApp {
455428
});
456429

457430
return {
458-
appFiles: appFiles,
459-
vendorFiles: vendorFiles,
431+
appFiles,
432+
vendorFiles,
460433
htmlFile: path.join(distPath, manifest.htmlFile),
461434
moduleWhitelist: pkg.fastboot.moduleWhitelist,
462435
hostWhitelist: pkg.fastboot.hostWhitelist,
463-
config: config,
464-
appName: appName,
465-
schemaVersion: schemaVersion,
436+
config,
437+
appName,
438+
schemaVersion,
466439
};
467440
}
468441

src/result.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@ const HTML_HEAD_REGEX = /^([\s\S]*<\/head>)([\s\S]*)/;
1212
* method.
1313
*/
1414
class Result {
15-
constructor(options = {}) {
16-
let { doc, html, fastbootInfo } = options;
17-
15+
constructor(doc, html, fastbootInfo) {
1816
this._instanceDestroyed = false;
1917

2018
this._doc = doc;
2119
this._html = html;
2220
this._fastbootInfo = fastbootInfo;
21+
this.instance = undefined;
2322
}
2423

2524
/**

src/sandbox.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ const chalk = require('chalk');
44
const vm = require('vm');
55

66
module.exports = class Sandbox {
7-
constructor(options = {}) {
8-
this.globals = options.globals;
9-
this.sandbox = this.buildSandbox();
10-
vm.createContext(this.sandbox);
7+
constructor(globals) {
8+
this.globals = globals;
9+
10+
let sandbox = this.buildSandbox();
11+
this.context = vm.createContext(sandbox);
1112
}
1213

1314
buildSandbox() {
@@ -16,18 +17,19 @@ module.exports = class Sandbox {
1617
let URL = require('url');
1718
let globals = this.globals;
1819

19-
let sandbox = {
20-
sourceMapSupport,
21-
console,
22-
setTimeout,
23-
clearTimeout,
24-
URL,
25-
26-
// Convince jQuery not to assume it's in a browser
27-
module: { exports: {} },
28-
};
20+
let sandbox = Object.assign(
21+
{
22+
sourceMapSupport,
23+
console,
24+
setTimeout,
25+
clearTimeout,
26+
URL,
2927

30-
Object.assign(sandbox, globals);
28+
// Convince jQuery not to assume it's in a browser
29+
module: { exports: {} },
30+
},
31+
globals
32+
);
3133

3234
// Set the global as `window`.
3335
sandbox.window = sandbox;
@@ -53,10 +55,10 @@ module.exports = class Sandbox {
5355

5456
eval(source, filePath) {
5557
var fileScript = new vm.Script(source, { filename: filePath });
56-
fileScript.runInContext(this.sandbox);
58+
fileScript.runInContext(this.context);
5759
}
5860

5961
run(cb) {
60-
return cb.call(this.sandbox, this.sandbox);
62+
return cb.call(this.context, this.context);
6163
}
6264
};

test/fixtures/custom-sandbox/custom-sandbox.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,13 @@ const Sandbox = require('./../../../src/sandbox');
1111
*
1212
*/
1313
class CustomSandbox extends Sandbox {
14-
constructor(options) {
15-
super(options);
16-
vm.createContext(this.sandbox);
17-
}
18-
1914
/**
2015
* Evals the file in the sandbox.
2116
*
2217
*/
2318
eval(source, filePath) {
2419
var fileScript = new vm.Script(source, { filename: filePath });
25-
fileScript.runInContext(this.sandbox);
20+
fileScript.runInContext(this.context);
2621
}
2722

2823
/**
@@ -32,7 +27,7 @@ class CustomSandbox extends Sandbox {
3227
* @todo: use this when we create app factory from addon
3328
*/
3429
run(cb) {
35-
return cb.call(this.sandbox, this.sandbox);
30+
return cb.call(this.context, this.context);
3631
}
3732

3833
/**

test/result-test.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,7 @@ describe('Result', function() {
1313
html = `<!-- EMBER_CLI_FASTBOOT_HEAD -->
1414
<!-- EMBER_CLI_FASTBOOT_BODY -->`;
1515

16-
result = new Result({
17-
doc: doc,
18-
html: html,
19-
fastbootInfo: new FastBootInfo(req, {}, ['example.com']),
20-
});
16+
result = new Result(doc, html, new FastBootInfo(req, {}, ['example.com']));
2117
});
2218

2319
it('constructor', function() {

0 commit comments

Comments
 (0)