justinhelmer
1/25/2018 - 5:50 AM

scaffold.js

/**
 * Common node web server interface used for development and production.
 * This server is only used for development purposes, since this feature is consumed by a page.
 *
 * @see https://code.devops.fds.com/polaris/core/server/blob/master/README.md
 */
const _ = require('lodash');
const Server = require('@core/server');

const server = new Server({
  mock: true, // enable mocks in dev mode (@see server/mocks.js)
  sharedStore: true, // enable shared client/server state (@see @core/lib/store)
});

const { app } = server;

// attach custom express middleware - http://expressjs.com/en/guide/using-middleware.html
app.get('/', (req, res) => {
  res.redirect('/introduction');
});

/**
 * An example of using server.proxy to make a request to an external API (i.e. xAPI), and store the results for SSR.
 *
 * If mock is enabled at the time the server is newed (e.g. if server.mock = true or the environment variable MOCK_ENABLED = 'yes'),
 * then server/mock.js will be used to resolve mock data for calls made via server.proxy.
 *
 * If universal JS is enabled at the time the server is newed (e.g. if server.universalJS = true or the environment variable MOCK_ENABLED = 'yes'),
 * then the proxy will cache the results to be used by the client-side store. @see @core/lib/store.
 *
 * Results are stored in req.locals.context.benefits. @see @core/server/lib/proxy.js
 */
app.get('/benefits', server.proxy({ store: 'benefits', host: process.env.XAPI_HOST, url: '/xapi/benefits' }));

/**
 * An example of using server.proxy to make a request to an external API (i.e. xAPI), then respond with the JSON result.
 *
 * If mock is enabled at the time the server is newed (e.g. if server.mock = true or the environment variable MOCK_ENABLED = 'yes'),
 * then server/mock.js will be used to resolve mock data for calls made via server.proxy.
 *
 * Results are stored in req.locals.context.benefits. @see @core/server/lib/proxy.js
 */
app.get('/xapi/benefits', [
  server.proxy({ store: 'benefits', host: process.env.XAPI_HOST }), // not setting url wil proxy to req.url (/xapi/benefits)
  (req, res) => {
    res.json(req.locals.context.benefits);
  }
]);

/**
 * An example of using server-side rendering for all routes.
 *
 * A single template is always rendered: src/templates/main.hbs. That template can do a "lookup" to determine which
 * partial to render, based on the route. For example, assume main.hbs has the following template HTML:
 *
 *     <div id="{{id}}">
 *         {{> (lookup . 'id') (lookup . id)}}
 *     </div>
 *
 * On the server side, req.locals.context defines the context that handlebars will use to compile the template.
 * Assuming the following context:
 *
 *     req.locals.context = { id: 'foo', partial: 'foo', foo: { someKey: 'some value' } };
 *
 * ... the lookup helper will resolve the template HTML to:
 *
 *     <div id="{{id}}">
 *         {{> foo foo}}
 *     </div>
 *
 * More on Handlebars built-in lookup helper is here: http://handlebarsjs.com/builtin_helpers.html
 *
 * When this template HTML is compiled, {{id}} will be replaced by req.locals.context.id, which is "foo".
 * Also {{> foo foo}} will look for a file named "foo.hbs" inside the src/templates/partials directory, and
 * render it with req.locals.context.foo
 *
 * Assuming src/templates/partials/foo.hbs has:
 *
 *     <p>This is {{someKey}}</p>
 *
 * ... the final output will become:
 *
 *     <div id="foo">
 *         <p>This is some value</p>
 *     </div>
 */
app.get('/:page', [
  (req, res, next) => {
    // DO NOT override anything in req.locals.context. Use _.defaults instead.
    _.defaults(req.locals.context, {
      id: req.params.page, // introduction, benefits, etc.
    });

    next();
  },

  (req, res, next) => {
    req.locals.context.navigation = [ // @see src/templates/main.hbs
      { page: 'introduction', label: 'Introduction' },
      { page: 'benefits', label: 'Benefits' },
    ];

    const active = _.find(req.locals.context.navigation, { page: req.params.page });
    if (active) {
      active.selected = true;
    }

    next();
  }
]);

server.start();