UNPKG

@harmonyjs/controller-spa

Version:

Single Page Application controller for Harmony

131 lines (110 loc) 3.61 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var httpProxy = _interopDefault(require('http-proxy')); var FastifyStatic = _interopDefault(require('fastify-static')); var FastifyHttpProxy = _interopDefault(require('fastify-http-proxy')); let sockjsProxied = false; async function serveStaticFiles({ server, path, dir, webpack, logger }) { // In development, we can use options.hmr.active = false to run in production-like mode const production = process.env.NODE_ENV === 'production' || !webpack || !webpack.active; logger.info(`Initializing SPA Controller on path ${path} (Environment: ${process.env.NODE_ENV || 'development'}, Mode: ${production ? 'static' : 'webpack'})`); let staticPath = path; if (!staticPath.endsWith('/')) { staticPath += '/'; } // Route for serving static files await server.register(FastifyStatic, { root: dir, prefix: staticPath, serve: production }); if (production) { logger.info(`Serving static files from ${dir} on path ${staticPath}`); } else if (webpack) { const upstream = [webpack.endpoint, webpack.port].filter(s => s).join(':'); // Webpack Proxy server.register(FastifyHttpProxy, { prefix: staticPath, rewritePrefix: staticPath, upstream, http2: false }); // We also need to proxy sockjs-node, since Webpack development uses the standard sockjs path // This means that any other sockjs used for Harmony need to be on a different path if (!sockjsProxied) { sockjsProxied = true; server.register(FastifyHttpProxy, { prefix: '/sockjs-node', upstream, http2: false }); // Finally, we proxy the upgrade request if they start by /socket.io const wsProxy = httpProxy.createProxyServer({ target: upstream }); wsProxy.on('error', error => logger.error(error)); server.server.on('upgrade', (req, socket, head) => { if (req.url.startsWith('/sockjs-node')) wsProxy.ws(req, socket, head); }); } logger.info(`Webpack proxy established to address ${upstream}`); } logger.info(`SPA site served on ${path}`); } async function serveViewsCatchAll({ server, logger, views }) { if (views) { views.forEach(view => { const basePath = view.path.endsWith('/') ? view.path : `${view.path}/`; const mainPath = basePath.length > 1 ? basePath.slice(0, -1) : basePath; const path = basePath.endsWith('*') ? basePath : `${basePath}*`; server.get(mainPath, (request, reply) => { reply.sendFile(view.file, view.dir); }); server.get(path, (request, reply) => { reply.sendFile(view.file, view.dir); }); logger.info(`Serving ${`${view.dir}/${view.file}`} for route ${path}`); }); } } /* * The SPA Controller exposes a single-page app on a given path, * statically built using Webpack, or served by Webpack-Dev-Server in development */ const ControllerSPA = function ControllerSPA(config) { return { name: 'ControllerSPA', async initialize({ logger, server }) { const { path, dir, webpack, views } = config; await serveStaticFiles({ server, logger, path, dir, webpack }); await serveViewsCatchAll({ server, logger, views }); } }; }; exports.default = ControllerSPA; //# sourceMappingURL=index.js.map