UNPKG

@platform/react.ssr

Version:

A lightweight SSR (server-side-rendering) system for react apps bundled with ParcelJS and hosted on S3.

92 lines (91 loc) 2.99 kB
import { fs, http, util, cheerio } from '../common'; import { pathToRegexp } from 'path-to-regexp'; export class Route { constructor(args) { this.site = args.site; this.def = args.route; } static format(args) { const { input } = args; if (typeof input !== 'object') { return undefined; } const entry = util.asString(input.entry); const paths = Array.isArray(input.path) ? input.path : [input.path]; const path = paths.filter(path => Boolean(path) && typeof path === 'string'); return { entry, path }; } get paths() { return this.def.path; } get version() { return util.firstSemver(this.site.bundle) || '0.0.0'; } get bundleUrl() { const base = util.stripSlashes(this.site.baseUrl); const path = util.stripSlashes(this.site.bundle); return `${base}/${path}`; } async entry(args = {}) { if (this._entry && !args.force) { return this._entry; } const filename = this.def.entry; const url = `${this.bundleUrl}/${filename}`; const res = await http.get(url); let status = 200; if (!res.ok) { status = res.status; } let html = res.ok ? res.text : ''; const version = this.version; html = this.formatHtml({ html, filename, version }); const ok = status.toString().startsWith('2'); const entry = { ok, status, url, html, }; this._entry = entry; return entry; } isMatch(path) { if (!this._regexps) { this._regexps = this.paths.map(pattern => pathToRegexp(pattern)); } return this._regexps.some(regex => Boolean(regex.exec(path))); } toObject() { return Object.assign({}, this.def); } formatHtml(args) { const { filename, html, version } = args; if (!html) { return html; } const site = this.site; const files = site.files; const entry = site.entries.find(item => item.file === filename); const $ = cheerio.load(html); $('html').attr('data-version', version); $('html').attr('data-size', site.size); if (entry) { $(`div#${entry.id}`).html(entry.html); $('head').append(`<style>${entry.css}</style>`); } files .filter(file => file.path.endsWith('.js')) .forEach(file => sizeAttr(file.bytes, $(`script[src="${fs.basename(file.path)}"]`))); files .filter(file => file.path.endsWith('.css')) .forEach(file => sizeAttr(file.bytes, $(`link[href="${fs.basename(file.path)}"]`))); return $.html(); } } Route.create = (args) => new Route(args); function sizeAttr(bytes, el) { if (el.length > 0) { el.attr('data-size', fs.size.toString(bytes, { round: 0 })); } }