Created
November 18, 2020 05:57
-
-
Save steveblue/d003740efd08983f78d9d3e49e61072d to your computer and use it in GitHub Desktop.
Express middleware for server side rendering web components
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require('@skatejs/ssr/register'); | |
| const render = require('@skatejs/ssr'); | |
| const minify = require('html-minifier-terser').minify; | |
| const url = require('url'); | |
| const path = require('path'); | |
| const fs = require('fs'); | |
| // index.js is a bundle of the client-side app that includes a const routes, example below: | |
| // const routes = [ | |
| // { path: '/', component: HomeComponent, title: '', description: '' schema: JSON.stringify({}) }, | |
| // ]; | |
| const { routes } = require('./index.js'); | |
| const indexPath = path.join(process.cwd(), 'dist', 'client', 'index.html'); | |
| const dom = fs.readFileSync(indexPath).toString(); | |
| function generateIndex(template, route, dom){ | |
| let index = dom | |
| .replace(`<title></title>`, `<title>${route.title}</title>`) | |
| .replace(`<meta name="Description" content="">`, `<meta name="Description" content="${route.description}">`) | |
| .replace(`<div id="root"></div>`, `<div id="root">${template}</div>`) | |
| .replace(/__ssr\(\)/g, ''); | |
| if (route.schema) { | |
| index = index.replace(`<script type="application/ld+json"></script>`, `<script type="application/ld+json">${route.schema}</script>`); | |
| } else { | |
| index = index.replace(`<script type="application/ld+json"></script>`, ``); | |
| } | |
| index = minify(index, { | |
| minifyCSS: true, | |
| removeComments: true | |
| }); | |
| return index; | |
| } | |
| export default async(req, res, next) => { | |
| let component: any = class {}; | |
| const route = routes.find(rt => rt.path === url.parse(req.url).pathname); | |
| if (route == undefined) { | |
| res.redirect(301, '/404'); | |
| return; | |
| } else { | |
| component = route.component; | |
| } | |
| if (component) { | |
| const preRender = new component(); | |
| // if a component has the getModel method, it requires an async operation to render | |
| // ex: fetch some data for the component to render | |
| // you could swap this out with custom implementation | |
| if (preRender.getModel) { | |
| try { | |
| await preRender.getModel(); | |
| } catch(e) { | |
| next(e); | |
| } | |
| } | |
| const template = await render(preRender); | |
| res.send(generateIndex(template, route, dom)); | |
| } else { | |
| res.send(dom); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment