diff --git a/README.md b/README.md index 5990aa403..4a6549cd7 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,40 @@ visit your app at `http://localhost:4200/?fastboot=false`. If you want to turn o You can even disable serving fastboot with `ember serve` using an environment flag: `FASTBOOT_DISABLED=true ember serve`. If you have disabled building fastboot assets using the same flag as described [here](https://github.com/ember-fastboot/ember-cli-fastboot#double-build-times-and-no-incremental-builds), remember to also disable serving fastboot assets when using `ember serve`. +### FastBoot Configuration + +When running locally using `ember serve` you can pass options into FastBoot instance via `config/fastboot.js` file. The configuration file is applicable only for applications, addons are not supported. + +```js +module.exports = function(environment) { + let myGlobal = environment === 'production' ? process.env.MY_GLOBAL : 'testing'; + + return { + sandboxGlobals: { + myGlobal; + } + }; +} +``` + +There are several options available, see FastBoot's [README](https://github.com/ember-fastboot/fastboot/tree/v2.0.3#usage) for more information, but be aware that `distPath` is provided internally by `ember-cli-fastboot`, hence it can not be modified by this file. + +### FastBoot App Server Configuration + +When using FastBoot App Server for production environment you have to manually pass options from `config/fastboot.js` file. + +```js +const FastBootAppServer = require('fastboot-app-server'); +const config = require('./config/fastboot')(process.env.NODE_ENV); + +let server = new FastBootAppServer({ + distPath: 'dist', + ...config, +}); + +server.start(); +``` + ## Using Node/npm Dependencies ### Whitelisting Packages diff --git a/index.js b/index.js index 97a06ad13..433f58069 100644 --- a/index.js +++ b/index.js @@ -79,6 +79,8 @@ module.exports = { this._appRegistry = app.registry; this._name = app.name; + this.fastbootOptions = this._fastbootOptionsFor(app.env, app.project); + migrateInitializers(this.project); }, @@ -323,13 +325,14 @@ module.exports = { if (!this.fastboot) { const broccoliHeader = req.headers['x-broccoli']; const outputPath = broccoliHeader['outputPath']; + const fastbootOptions = Object.assign( + {}, + this.fastbootOptions, + { distPath: outputPath } + ); - // TODO(future): make this configurable for allowing apps to pass sandboxGlobals - // and custom sandbox class this.ui.writeLine(chalk.green('App is being served by FastBoot')); - this.fastboot = new FastBoot({ - distPath: outputPath - }); + this.fastboot = new FastBoot(fastbootOptions); } let fastbootMiddleware = FastBootExpressMiddleware({ @@ -373,8 +376,26 @@ module.exports = { return checker.for('ember', 'bower'); }, - + _isModuleUnification() { return (typeof this.project.isModuleUnification === 'function') && this.project.isModuleUnification(); + }, + + /** + * Reads FastBoot configuration from application's `config/fastboot.js` file if present, + * otherwise returns empty object. + * + * The configuration file is expected to export a function with `environment` as an argument, + * which is same as a how `config/environment.js` works. + * + * TODO Allow add-ons to provide own options and merge them with the application's options. + */ + _fastbootOptionsFor(environment, project) { + const configPath = path.join(path.dirname(project.configPath()), 'fastboot.js'); + + if (fs.existsSync(configPath)) { + return require(configPath)(environment); + } + return {}; } }; diff --git a/test/fastboot-config-test.js b/test/fastboot-config-test.js new file mode 100644 index 000000000..43f1e8e85 --- /dev/null +++ b/test/fastboot-config-test.js @@ -0,0 +1,42 @@ +'use strict'; + +const expect = require('chai').use(require('chai-string')).expect; +const RSVP = require('rsvp'); +const request = RSVP.denodeify(require('request')); + +const AddonTestApp = require('ember-cli-addon-tests').AddonTestApp; + +describe('FastBoot config', function() { + this.timeout(400000); + + let app; + + before(function() { + app = new AddonTestApp(); + + return app.create('fastboot-config') + .then(function() { + return app.startServer({ + command: 'serve' + }); + }); + }); + + after(function() { + return app.stopServer(); + }); + + it('provides sandbox globals', function() { + return request({ + url: 'http://localhost:49741/', + headers: { + 'Accept': 'text/html' + } + }) + .then(function(response) { + expect(response.statusCode).to.equal(200); + expect(response.headers['content-type']).to.equalIgnoreCase('text/html; charset=utf-8'); + expect(response.body).to.contain('

My Global

'); + }); + }); +}); diff --git a/test/fixtures/fastboot-config/app/router.js b/test/fixtures/fastboot-config/app/router.js new file mode 100644 index 000000000..cdc257875 --- /dev/null +++ b/test/fixtures/fastboot-config/app/router.js @@ -0,0 +1,12 @@ +import Ember from 'ember'; +import config from './config/environment'; + +const Router = Ember.Router.extend({ + location: config.locationType, + rootURL: config.rootURL +}); + +Router.map(function() { +}); + +export default Router; diff --git a/test/fixtures/fastboot-config/app/routes/application.js b/test/fixtures/fastboot-config/app/routes/application.js new file mode 100644 index 000000000..9f8225d41 --- /dev/null +++ b/test/fixtures/fastboot-config/app/routes/application.js @@ -0,0 +1,9 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ + model() { + if (typeof FastBoot !== 'undefined') { + return window.myGlobal; + } + } +}); diff --git a/test/fixtures/fastboot-config/app/templates/application.hbs b/test/fixtures/fastboot-config/app/templates/application.hbs new file mode 100644 index 000000000..17f5e29c5 --- /dev/null +++ b/test/fixtures/fastboot-config/app/templates/application.hbs @@ -0,0 +1 @@ +

{{this.model}}

\ No newline at end of file diff --git a/test/fixtures/fastboot-config/config/fastboot.js b/test/fixtures/fastboot-config/config/fastboot.js new file mode 100644 index 000000000..f6a69ddf8 --- /dev/null +++ b/test/fixtures/fastboot-config/config/fastboot.js @@ -0,0 +1,7 @@ +module.exports = function(environment) { + return { + sandboxGlobals: { + myGlobal: 'My Global' + } + }; +}