ff-stream-web

git clone git://archive.git.mtrnord.blog/MTRNord/ff-stream-web.git
Log | Files | Refs | README | LICENSE

server.js (5262B)


      1 /**
      2  * React Starter Kit (https://www.reactstarterkit.com/)
      3  *
      4  * Copyright © 2014-present Kriasoft, LLC. All rights reserved.
      5  *
      6  * This source code is licensed under the MIT license found in the
      7  * LICENSE.txt file in the root directory of this source tree.
      8  */
      9 
     10 import path from 'path';
     11 import express from 'express';
     12 import cookieParser from 'cookie-parser';
     13 import bodyParser from 'body-parser';
     14 import expressJwt from 'express-jwt';
     15 import expressGraphQL from 'express-graphql';
     16 import jwt from 'jsonwebtoken';
     17 import React from 'react';
     18 import ReactDOM from 'react-dom/server';
     19 import UniversalRouter from 'universal-router';
     20 import PrettyError from 'pretty-error';
     21 import App from './components/App';
     22 import Html from './components/Html';
     23 import { ErrorPageWithoutStyle } from './routes/error/ErrorPage';
     24 import errorPageStyle from './routes/error/ErrorPage.css';
     25 import passport from './core/passport';
     26 import models from './data/models';
     27 import schema from './data/schema';
     28 import routes from './routes';
     29 import assets from './assets.json'; // eslint-disable-line import/no-unresolved
     30 import { port, auth } from './config';
     31 
     32 const app = express();
     33 
     34 //
     35 // Tell any CSS tooling (such as Material UI) to use all vendor prefixes if the
     36 // user agent is not known.
     37 // -----------------------------------------------------------------------------
     38 global.navigator = global.navigator || {};
     39 global.navigator.userAgent = global.navigator.userAgent || 'all';
     40 
     41 //
     42 // Register Node.js middleware
     43 // -----------------------------------------------------------------------------
     44 app.use(express.static(path.join(__dirname, 'public')));
     45 app.use(cookieParser());
     46 app.use(bodyParser.urlencoded({ extended: true }));
     47 app.use(bodyParser.json());
     48 
     49 //
     50 // Authentication
     51 // -----------------------------------------------------------------------------
     52 app.use(expressJwt({
     53   secret: auth.jwt.secret,
     54   credentialsRequired: false,
     55   getToken: req => req.cookies.id_token,
     56 }));
     57 app.use(passport.initialize());
     58 
     59 if (__DEV__) {
     60   app.enable('trust proxy');
     61 }
     62 app.get('/login/facebook',
     63   passport.authenticate('facebook', { scope: ['email', 'user_location'], session: false }),
     64 );
     65 app.get('/login/facebook/return',
     66   passport.authenticate('facebook', { failureRedirect: '/login', session: false }),
     67   (req, res) => {
     68     const expiresIn = 60 * 60 * 24 * 180; // 180 days
     69     const token = jwt.sign(req.user, auth.jwt.secret, { expiresIn });
     70     res.cookie('id_token', token, { maxAge: 1000 * expiresIn, httpOnly: true });
     71     res.redirect('/');
     72   },
     73 );
     74 
     75 //
     76 // Register API middleware
     77 // -----------------------------------------------------------------------------
     78 app.use('/graphql', expressGraphQL(req => ({
     79   schema,
     80   graphiql: __DEV__,
     81   rootValue: { request: req },
     82   pretty: __DEV__,
     83 })));
     84 
     85 //
     86 // Register server-side rendering middleware
     87 // -----------------------------------------------------------------------------
     88 app.get('*', async (req, res, next) => {
     89   try {
     90     const css = new Set();
     91 
     92     // Global (context) variables that can be easily accessed from any React component
     93     // https://facebook.github.io/react/docs/context.html
     94     const context = {
     95       // Enables critical path CSS rendering
     96       // https://github.com/kriasoft/isomorphic-style-loader
     97       insertCss: (...styles) => {
     98         // eslint-disable-next-line no-underscore-dangle
     99         styles.forEach(style => css.add(style._getCss()));
    100       },
    101     };
    102 
    103     const route = await UniversalRouter.resolve(routes, {
    104       path: req.path,
    105       query: req.query,
    106     });
    107 
    108     if (route.redirect) {
    109       res.redirect(route.status || 302, route.redirect);
    110       return;
    111     }
    112 
    113     const data = { ...route };
    114     data.children = ReactDOM.renderToString(<App context={context}>{route.component}</App>);
    115     data.styles = [
    116       { id: 'css', cssText: [...css].join('') },
    117     ];
    118     data.scripts = [
    119       assets.vendor.js,
    120       assets.client.js,
    121     ];
    122     if (assets[route.chunk]) {
    123       data.scripts.push(assets[route.chunk].js);
    124     }
    125 
    126     const html = ReactDOM.renderToStaticMarkup(<Html {...data} />);
    127     res.status(route.status || 200);
    128     res.send(`<!doctype html>${html}`);
    129   } catch (err) {
    130     next(err);
    131   }
    132 });
    133 
    134 //
    135 // Error handling
    136 // -----------------------------------------------------------------------------
    137 const pe = new PrettyError();
    138 pe.skipNodeFiles();
    139 pe.skipPackage('express');
    140 
    141 app.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
    142   console.log(pe.render(err)); // eslint-disable-line no-console
    143   const html = ReactDOM.renderToStaticMarkup(
    144     <Html
    145       title="Internal Server Error"
    146       description={err.message}
    147       styles={[{ id: 'css', cssText: errorPageStyle._getCss() }]} // eslint-disable-line no-underscore-dangle
    148     >
    149       {ReactDOM.renderToString(<ErrorPageWithoutStyle error={err} />)}
    150     </Html>,
    151   );
    152   res.status(err.status || 500);
    153   res.send(`<!doctype html>${html}`);
    154 });
    155 
    156 //
    157 // Launch the server
    158 // -----------------------------------------------------------------------------
    159 /* eslint-disable no-console */
    160 models.sync().catch(err => console.error(err.stack)).then(() => {
    161   app.listen(port, () => {
    162     console.log(`The server is running at http://localhost:${port}/`);
    163   });
    164 });
    165 /* eslint-enable no-console */