Skip to content

Instantly share code, notes, and snippets.

@steveblue
Created November 18, 2020 05:57
Show Gist options
  • Select an option

  • Save steveblue/d003740efd08983f78d9d3e49e61072d to your computer and use it in GitHub Desktop.

Select an option

Save steveblue/d003740efd08983f78d9d3e49e61072d to your computer and use it in GitHub Desktop.
Express middleware for server side rendering web components
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