UNPKG

@platform/react.ssr

Version:

An SSR (server-side-render) system for react apps bundled with ParcelJS and hosted on S3.

116 lines (115 loc) 4.12 kB
import * as dotenv from 'dotenv'; import { fs, semver, util } from './common'; import { Manifest } from './manifest'; const { stripSlashes } = util; dotenv.config(); export class Config { constructor(args) { this.def = args.def; } get secret() { return toValue(this.def.secret); } get builder() { const builder = this.def.builder || {}; builder.bundles = builder.bundles || 'bundles'; builder.entries = builder.entries || ''; return builder; } get s3() { const s3 = this.def.s3 || {}; const path = s3.path || {}; const endpoint = util.stripHttp(s3.endpoint || ''); const cdn = util.stripHttp(s3.cdn || ''); const accessKey = toValue(s3.accessKey); const secret = toValue(s3.secret); const bucket = s3.bucket || ''; const api = { endpoint, cdn, accessKey, secret, bucket, path: { base: stripSlashes(path.base || ''), manifest: stripSlashes(path.manifest || ''), bundles: stripSlashes(path.bundles || ''), }, get config() { return { endpoint, accessKey, secret }; }, get fs() { return fs.s3(api.config); }, async versions(options = {}) { const s3 = api.fs; const prefix = `${api.path.base}/${api.path.bundles}`; const list = s3.list({ bucket, prefix, }); const dirs = (await list.dirs).items.map(({ key }) => ({ key, version: fs.basename(key) })); const versions = semver.sort(dirs.map(item => item.version)); return options.sort === 'DESC' ? versions.reverse() : versions; }, }; return api; } get manifest() { const filePath = fs.resolve(this.def.manifest || 'manifest.yml'); const s3 = this.s3; const urlPath = `${s3.bucket}/${s3.path.base}`; const manifestUrl = `https://${s3.endpoint}/${urlPath}/${s3.path.manifest}`; const baseUrl = `https://${s3.cdn || s3.endpoint}/${urlPath}`; const config = this; const api = { local: { path: filePath, get exists() { return fs.pathExists(filePath); }, async load() { return Manifest.fromFile({ path: filePath, baseUrl: baseUrl }); }, async ensureLatest(options = {}) { if (!(await api.local.exists)) { await config.createFromTemplate(); } const remote = await api.s3.get({ force: true }); if (remote.ok) { const { minimal } = options; await remote.save(filePath, { minimal }); } return api.local.load(); }, }, s3: { url: manifestUrl, async get(args = {}) { return Manifest.get(Object.assign({}, args, { manifestUrl, baseUrl })); }, }, }; return api; } async createFromTemplate() { const source = fs.join(__dirname, '../tmpl/manifest.yml'); const target = this.manifest.local.path; await fs.ensureDir(fs.dirname(target)); await fs.copy(source, target); return { source, target }; } } Config.create = async (options = {}) => { const path = fs.resolve(options.path || './ssr.yml'); if (!(await fs.pathExists(path))) { throw new Error(`An "ssr.yml" configuration file does not exist at: ${path}`); } const def = await fs.file.loadAndParse(path); return new Config({ def }); }; const toValue = (value) => { value = value || ''; value = process.env[value] ? process.env[value] : value; return value || ''; };