Ember.js server side rendering

To allow search engines crawl your Ember.js website contents , you need to render the web page in the server side and serve HTML content  the first time you load the application, then allow the JavaScript to take over once it has finished loading, to do that we will use Fastboot add-on.

install it in the Ember application

ember install ember-cli-fastboot

you need to configure a host white list domains that will serve the app

//config/environment.js file
module.exports = function (environment) {
  let ENV = {
    ...
    ,fastboot: {
      hostWhitelist: ['yourdomain.ext', /^localhost:\d+$/]
    }
  };

We can use Fastboot service to check if it is a Fastboot environment or not, this is useful to disable the use of browser specific operations like localStorage, for example if you use window.localStorage to save your authentication Token , with fastboot it will not be accessible, so you have to check if you are in Fastboot environment and use cookies instead, let see an example of isLoggedin function

import Service from '@ember/service';
import { inject as service } from '@ember/service';

export default class Auth extends service {
  @service fastboot;

  get isLoggedin() {
    let isFastBoot = this.fastboot.isFastBoot;
    if (isFastBoot) {
      let token = this.fastboot.request.cookies.token;

      if (token != null) {
        return true;
      } else {
        //this.expireCookie('token');
        return false;
      }
    } else {
      let loggedin =
        window.localStorage.getItem('loggedin') == 'true' ? true : false;
      return loggedin;
    }
  }
};

Following is a simple Node.js server using Fastboot to render the app and serve it

//index
const express = require('express');
const FastBootAppServer = require('fastboot-app-server');
const ExpressHTTPServer = require('fastboot-app-server/src/express-http-server');
const compression = require('compression');

const httpServer = new ExpressHTTPServer({
  port: 8087
});
const app = httpServer.app;

app.disable('x-powered-by');
app.use(compression());

app.use('/assets', express.static('./public/assets'));
app.use('/api', express.static('./public/api'));
app.use('/images', express.static('./public/images'));


let server = new FastBootAppServer({
  httpServer: httpServer,
  distPath: 'public',
  resilient:true,
  gzip: true, // Optional - Enables gzip compression.
  host: '0.0.0.0', // Optional - Sets the host the server listens on.
  port: 8080, // Optional -(defaults to the PORT env var or 3000).
  buildSandboxGlobals(defaultGlobals) { // Optional - Make values available to the Ember app running in the FastBoot server, e.g. "MY_GLOBAL" will be available as "GLOBAL_VALUE"
    return Object.assign({}, defaultGlobals, { });
  },
  log: true, // Optional - Specifies whether the server should use its default request logging. Useful for turning off default logging when providing custom logging middlewares
  chunkedResponse: false,
});

server.start();

You need to install  ember-fetch  to be used to fetch data used by the app, package.json will look like this.

{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ember-fetch": "^8.1.1",
    "express": "^4.17.1",
    "fastboot-app-server": "^3.3.0"
  }
}