ember-fastboot-server
Advanced tools
Comparing version 0.5.4 to 0.6.0
@@ -58,2 +58,8 @@ var fs = require('fs'); | ||
EmberApp.prototype.destroy = function() { | ||
if (this._app) { | ||
this._app.destroy(); | ||
} | ||
}; | ||
EmberApp.prototype.buildApp = function() { | ||
@@ -60,0 +66,0 @@ return this._app.boot().then(function(app) { |
@@ -1,2 +0,2 @@ | ||
var cookie = require('cookie'); | ||
var FastBootRequest = require('./fastboot-request'); | ||
@@ -9,53 +9,6 @@ /* | ||
function FastBootInfo(request, response, hostWhitelist) { | ||
this.request = request; | ||
this.response = response; | ||
this.cookies = this.extractCookies(request); | ||
this.headers = request.headers; | ||
this.hostWhitelist = hostWhitelist; | ||
this.request = new FastBootRequest(request, hostWhitelist); | ||
} | ||
FastBootInfo.prototype.extractCookies = function(request) { | ||
// If cookie-parser middleware has already parsed the cookies, | ||
// just use that. | ||
if (request.cookies) { | ||
return request.cookies; | ||
} | ||
// Otherwise, try to parse the cookies ourselves, if they exist. | ||
var cookies = request.get('cookie'); | ||
if (cookies) { | ||
return cookie.parse(cookies); | ||
} | ||
// Return an empty object instead of undefined if no cookies are present. | ||
return {}; | ||
}; | ||
FastBootInfo.prototype.host = function() { | ||
if (!this.hostWhitelist) { | ||
throw new Error('You must provide a hostWhitelist to retrieve the host'); | ||
} | ||
var host = this.request.headers.host; | ||
var matchFound = this.hostWhitelist.reduce(function(previous, currentEntry) { | ||
if (currentEntry[0] === '/' && | ||
currentEntry.slice(-1) === '/') { | ||
// RegExp as string | ||
var regexp = new RegExp(currentEntry.slice(1, -1)); | ||
return previous || regexp.test(host); | ||
} else { | ||
return previous || currentEntry === host; | ||
} | ||
}, false); | ||
if (!matchFound) { | ||
throw new Error('The host header did not match a hostWhitelist entry'); | ||
} | ||
return this.request.protocol + '://' + host; | ||
}; | ||
/* | ||
@@ -62,0 +15,0 @@ * Registers this FastBootInfo instance in the registry of an Ember |
@@ -60,3 +60,4 @@ var chalk = require('chalk'); | ||
} | ||
return wrappedConsole; | ||
}; | ||
@@ -63,0 +64,0 @@ Sandbox.isLegacyVM = isLegacyVM; |
@@ -8,2 +8,4 @@ var chalk = require('chalk'); | ||
detectDeprecatedNode(); | ||
function FastBootServer(options) { | ||
@@ -13,3 +15,17 @@ options = options || {}; | ||
var distPath = options.distPath; | ||
var ui = options.ui; | ||
this.buildEmberApp(distPath, ui); | ||
} | ||
// Stubs out the `ui` object for printing to the terminal used | ||
// by Ember CLI addons. | ||
var defaultUI = { | ||
writeLine: function() { | ||
console.log.apply(console, arguments); | ||
} | ||
}; | ||
FastBootServer.prototype.buildEmberApp = function(distPath, ui) { | ||
if (!distPath) { | ||
@@ -27,10 +43,13 @@ throw new Error('You must instantiate FastBootServer with a distPath ' + | ||
// Stubs out the `ui` object for printing to the terminal used | ||
// by Ember CLI addons. | ||
var defaultUI = { | ||
writeLine: function() { | ||
console.log.apply(console, arguments); | ||
} | ||
}; | ||
if (!ui) { | ||
ui = this.ui || defaultUI; | ||
} | ||
this.distPath = distPath; | ||
this.ui = ui; | ||
if (this.app) { | ||
this.app.destroy(); | ||
} | ||
this.app = new EmberApp({ | ||
@@ -45,6 +64,4 @@ distPath: path.resolve(distPath), | ||
this.html = fs.readFileSync(config.htmlFile, 'utf8'); | ||
}; | ||
this.ui = options.ui || defaultUI; | ||
} | ||
FastBootServer.prototype.log = function(statusCode, message, startTime) { | ||
@@ -93,8 +110,8 @@ var color = statusCode === 200 ? 'green' : 'red'; | ||
debug("app boot failed"); | ||
self.ui.writeLine(chalk.red("Error loading the application.")); | ||
self.ui.writeLine(error); | ||
this.ui.writeLine(chalk.red("Error loading the application.")); | ||
this.ui.writeLine(error); | ||
}; | ||
FastBootServer.prototype.middleware = function() { | ||
return function(req, res, next) { | ||
return function(req, res) { | ||
var path = req.url; | ||
@@ -125,2 +142,12 @@ debug("middleware request; path=%s", path); | ||
FastBootServer.prototype.reload = function(options) { | ||
var distPath = this.distPath; | ||
if (options && options.distPath) { | ||
distPath = options.distPath; | ||
} | ||
this.buildEmberApp(distPath); | ||
}; | ||
function readPackageJSON(distPath) { | ||
@@ -155,2 +182,13 @@ var pkgPath = path.join(distPath, 'package.json'); | ||
function detectDeprecatedNode() { | ||
var version = process.version.match(/^v(\d+)\.(\d+)/); | ||
var major = parseInt(version[1]); | ||
var minor = parseInt(version[2]); | ||
if (major === 0 && minor <= 10) { | ||
console.log("Support for Node.js 0.10 has been deprecated and will be removed before the 1.0 release. Please upgrade to Node.js 0.12 or later."); | ||
} | ||
} | ||
module.exports = FastBootServer; |
{ | ||
"name": "ember-fastboot-server", | ||
"version": "0.5.4", | ||
"version": "0.6.0", | ||
"description": "Production server for running Ember applications using FastBoot", | ||
@@ -43,5 +43,7 @@ "main": "./lib/server", | ||
"chai-as-promised": "^5.2.0", | ||
"fs-promise": "^0.5.0", | ||
"mocha": "^2.4.5", | ||
"request-promise": "^2.0.1" | ||
"request-promise": "^2.0.1", | ||
"temp": "^0.8.3" | ||
} | ||
} |
@@ -10,15 +10,45 @@ # Ember FastBoot Server | ||
For more information about FastBoot, see | ||
[ember-cli-fastboot][ember-cli-fastboot], the Ember CLI addon that's a | ||
[www.ember-fastboot.com][ember-fastboot], the Ember CLI addon that's a | ||
prerequisite for developing FastBoot apps. | ||
[ember-cli-fastboot]: https://github.com/tildeio/ember-cli-fastboot | ||
[ember-fastboot]: https://www.ember-fastboot.com | ||
The FastBoot server requires Node 0.12 or later. | ||
## Usage | ||
The FastBoot server supports two modes of usage: | ||
1. Running as a binary from the command line. | ||
2. Running programmatically as an Express middleware. | ||
In both cases, you will first need to build your Ember application, | ||
which packages it up for using in both the browser and in Node.js. | ||
### Build Your App | ||
To get your Ember.js application ready to both run in your user's | ||
browsers and run inside the FastBoot environment, run the Ember CLI | ||
build command: | ||
```sh | ||
$ ember build --environment production | ||
``` | ||
(You will need to have already set up the Ember CLI FastBoot addon. For | ||
more information, see the [FastBoot quickstart][quickstart].) | ||
[quickstart]: https://www.ember-fastboot.com/quickstart | ||
Once this is done, you will have a `dist` directory that contains the | ||
multi-environment build of your app. Upload this file to your FastBoot | ||
server. | ||
### Command Line | ||
You can run the FastBoot server from the command line: | ||
You can start a simple HTTP server that responds to incoming requests by | ||
rendering your Ember.js application using the `ember-fastboot` command: | ||
``` | ||
$ ember-fastboot path/to/fastboot-dist --port 80 | ||
$ ember-fastboot path/to/dist --port 80 | ||
``` | ||
@@ -34,3 +64,3 @@ | ||
var server = new FastBootServer({ | ||
distPath: 'path/to/fastboot-dist' | ||
distPath: 'path/to/dist' | ||
}); | ||
@@ -37,0 +67,0 @@ |
@@ -8,2 +8,4 @@ var expect = require('chai').expect; | ||
var Server = require('./helpers/cli-server'); | ||
var temp = require('temp').track(); | ||
var fsp = require('fs-promise'); | ||
var fixturePath = require('./helpers/fixture-path'); | ||
@@ -72,2 +74,57 @@ | ||
}); | ||
it("allows console.log from within the app", function() { | ||
this.timeout(3000); | ||
var server = new Server('app-with-console-log'); | ||
server.start(); | ||
return new RSVP.Promise(function(resolve, reject) { | ||
server.stdout.on('data', function(data) { | ||
if (data.toString().indexOf('The files are *in* the computer?')) { | ||
resolve(); | ||
} | ||
}); | ||
}).finally(function() { | ||
server.stop(); | ||
}); | ||
}); | ||
it("reloads on SIGUSR1", function() { | ||
this.timeout(7000); | ||
var tmpPath = temp.path({ suffix: '-fastboot-server-test' }); | ||
var server = new Server({ path: tmpPath }); | ||
after(function() { | ||
server.stop(); | ||
}); | ||
return expect(fsp.copy(fixturePath('basic-app'), tmpPath)).to.be.fulfilled | ||
.then(function() { | ||
return server.start(); | ||
}) | ||
.then(function() { | ||
return request('http://localhost:3000'); | ||
}) | ||
.then(function(html) { | ||
expect(html).to.match(/<h2 id="title">Welcome to Ember<\/h2>/); | ||
}) | ||
.then(function() { | ||
return fsp.remove(tmpPath); | ||
}) | ||
.then(function() { | ||
return fsp.copy(fixturePath('hot-swap-app'), tmpPath); | ||
}) | ||
.then(function() { | ||
return server.reload(); | ||
}) | ||
.then(function() { | ||
return request('http://localhost:3000'); | ||
}) | ||
.then(function(html) { | ||
expect(html).to.match(/<h2 id="title">Goodbye from Ember<\/h2>/); | ||
}); | ||
}); | ||
}); |
@@ -6,3 +6,3 @@ var expect = require('chai').expect; | ||
describe("FastBootInfo", function() { | ||
it("throws an exception if no hostWhitelist is provided", function() { | ||
it("has a FastBootRequest", function() { | ||
var response = {}; | ||
@@ -18,69 +18,7 @@ var request = { | ||
}; | ||
var fastBootInfo = new FastBootInfo(request, response); | ||
var fastbootInfo = new FastBootInfo(request, response); | ||
var fn = function() { | ||
fastBootInfo.host(); | ||
}; | ||
expect(fn).to.throw(/You must provide a hostWhitelist to retrieve the host/); | ||
expect(fastbootInfo.request.protocol).to.equal("http"); | ||
}); | ||
it("throws an exception if the host header does not match an entry in the hostWhitelist", function() { | ||
var response = {}; | ||
var request = { | ||
cookie: "", | ||
protocol: "http", | ||
headers: { | ||
host: "evil.com" | ||
}, | ||
get: function() { | ||
return this.cookie; | ||
} | ||
}; | ||
var hostWhitelist = ["example.com", "localhost:4200"] | ||
var fastBootInfo = new FastBootInfo(request, response, hostWhitelist); | ||
var fn = function() { | ||
fastBootInfo.host(); | ||
}; | ||
expect(fn).to.throw(/The host header did not match a hostWhitelist entry/); | ||
}); | ||
it("returns the host with protocol if it is in the hostWhitelist", function() { | ||
var response = {}; | ||
var request = { | ||
cookie: "", | ||
protocol: "http", | ||
headers: { | ||
host: "localhost:4200" | ||
}, | ||
get: function() { | ||
return this.cookie; | ||
} | ||
}; | ||
var hostWhitelist = ["example.com", "localhost:4200"] | ||
var fastBootInfo = new FastBootInfo(request, response, hostWhitelist); | ||
var host = fastBootInfo.host(); | ||
expect(host).to.equal("http://localhost:4200"); | ||
}); | ||
it("returns the host with protocol matches a regex in the hostWhitelist", function() { | ||
var response = {}; | ||
var request = { | ||
cookie: "", | ||
protocol: "http", | ||
headers: { | ||
host: "localhost:4200" | ||
}, | ||
get: function() { | ||
return this.cookie; | ||
} | ||
}; | ||
var hostWhitelist = ["example.com", "/localhost:\\d+/"] | ||
var fastBootInfo = new FastBootInfo(request, response, hostWhitelist); | ||
var host = fastBootInfo.host(); | ||
expect(host).to.equal("http://localhost:4200"); | ||
}); | ||
}); | ||
@@ -1,4 +0,6 @@ | ||
var expect = require('chai').expect; | ||
var path = require('path'); | ||
var expect = require('chai').expect; | ||
var path = require('path'); | ||
var request = require('request-promise'); | ||
var FastBootServer = require('../lib/server.js'); | ||
var TestHTTPServer = require('./helpers/test-http-server'); | ||
@@ -35,2 +37,49 @@ describe("FastBootServer", function() { | ||
}); | ||
it("can reload the distPath", function() { | ||
var distPath = fixture('basic-app'); | ||
var server = new TestHTTPServer({ | ||
distPath: distPath | ||
}); | ||
var promise = server.start() | ||
.then(requestFirstApp) | ||
.then(hotReloadApp) | ||
.then(requestSecondApp) | ||
.finally(cleanup); | ||
var url; | ||
return promise; | ||
function requestFirstApp(info) { | ||
url = 'http://[' + info.host + ']:' + info.port + '/'; | ||
return request(url) | ||
.then(function(html) { | ||
expect(html).to.match(/Welcome to Ember/); | ||
}); | ||
} | ||
function hotReloadApp() { | ||
return server.withFastBootServer(function(fbs) { | ||
return fbs.reload({ | ||
distPath: fixture('hot-swap-app') | ||
}); | ||
}); | ||
} | ||
function requestSecondApp(info) { | ||
return request(url) | ||
.then(function(html) { | ||
expect(html).to.match(/Goodbye from Ember/); | ||
}); | ||
} | ||
// Always clean up the server | ||
function cleanup() { | ||
server.stop(); | ||
} | ||
}); | ||
}); | ||
@@ -37,0 +86,0 @@ |
@@ -8,5 +8,9 @@ var RSVP = require('rsvp'); | ||
function Server(fixture, options) { | ||
if (typeof fixture === 'object') { | ||
options = fixture; | ||
} | ||
options = options || {}; | ||
this.path = fixturePath(fixture); | ||
this.path = options.path || fixturePath(fixture); | ||
this.args = [this.path]; | ||
@@ -22,2 +26,5 @@ | ||
this.stdout = server.stdout; | ||
this.stdin = server.stdin; | ||
return new RSVP.Promise(function(resolve, reject) { | ||
@@ -52,2 +59,16 @@ | ||
Server.prototype.reload = function(si) { | ||
var server = this.server; | ||
return new RSVP.Promise(function(resolve, reject) { | ||
server.stdout.on('data', function(data) { | ||
if (data.toString().match('Reloading Ember app')) { | ||
resolve(); | ||
} | ||
}); | ||
server.kill('SIGUSR1'); | ||
}); | ||
}; | ||
module.exports = Server; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
17895859
47
213640
77
6
6