UNPKG

@platform/react.ssr

Version:

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

112 lines (111 loc) 3.93 kB
import { bundler } from '../bundler'; import { Config } from '../config'; import { exec, fs, log, npm } from './common'; import * as push from './cmd.push'; export async function run(args) { const { cli } = args; const config = args.config || (await Config.create()); const { endpoint } = config.s3; let manifest; await fs.ensureDir(config.builder.bundles); const pkgPath = await fs.ancestor(config.builder.bundles).first('package.json'); const pkg = npm.pkg(pkgPath); log.info.gray(fs.dirname(pkgPath)); log.info(); const version = args.version || (await npm.prompt.incrementVersion({ path: pkgPath, noChange: true, save: true })); const bundleDir = fs.resolve(fs.join(config.builder.bundles, version)); const isPush = args.push !== undefined ? args.push : (await cli.prompt.list({ message: 'push to S3', items: ['yes', 'no'] })) === 'yes'; if (isPush && !endpoint) { throw new Error(`The S3 endpoint has not been configured in [ssr.yml].`); } log.info(); const tasks = cli .task('build', async (e) => execScript(pkg, e, 'build'), { skip: args.manifest }) .task('bundle', async (e) => execScript(pkg, e, 'bundle'), { skip: args.manifest }) .task('manifest', async (e) => { const { entries, error } = await getEntries(config); if (error) { throw error; } else { const res = await bundler.prepare({ bundleDir, entries, silent: true }); manifest = res.manifest; } }); const res = await tasks.run({ concurrent: false, exitOnError: true }); if (!res.ok) { log.info(); res.errors.forEach(item => { log.error(`ERROR ${item.title}`); log.warn(item.error); log.info(); }); return cli.exit(1); } if (isPush) { await push.bundle({ cli, config, version }); } else if (manifest) { bundler.log.bundle({ bundleDir, manifest }); } log.info(); } async function execScript(pkg, e, scriptName) { const exists = Boolean(pkg.scripts.bundle); if (!exists) { e.error(`Package.json does not have a "${scriptName}" script.`); return; } const cwd = pkg.dir; const res = await exec.command(`yarn ${scriptName}`).run({ cwd, silent: true }); if (!res.ok) { throw new Error(`Failed while executing '${scriptName}' script of package '${pkg.name}'`); } } const getRootDir = async (source) => { let path = ''; await fs.ancestor(source).walk(async (e) => { if ((await fs.readdir(e.dir)).includes('package.json')) { return e.stop(); } else { path = e.dir; } }); return path; }; const getEntries = async (config) => { const done = (entries, errorMessage) => { const error = errorMessage ? new Error(errorMessage) : undefined; return { ok: !Boolean(error), entries, error }; }; let source = config.builder.entries; if (!source) { return done([]); } source = fs.resolve(source); const sourceRoot = await getRootDir(source); const sourcePath = source.substring(sourceRoot.length); const localRoot = fs.resolve(`tmp/${fs.basename(sourceRoot)}`); const localPath = fs.join(localRoot, sourcePath); await fs.ensureDir(fs.dirname(localRoot)); await fs.remove(localRoot); await fs.copy(sourceRoot, localRoot); const err = `Failed to load bundle entries at path: ${source}.`; try { const res = require(localPath); if (Array.isArray(res.default)) { return done(res.default); } return done([], `${err} Ensure the array is exported as the module default.`); } catch (error) { return done([], `${err} ${error.message}`); } finally { await fs.remove(fs.resolve('tmp')); } };