@platform/react.ssr
Version:
A lightweight SSR (server-side-rendering) system for react apps bundled with ParcelJS and hosted on S3.
93 lines (92 loc) • 3.21 kB
JavaScript
import { bundler } from '../bundler';
import { Config } from '../config';
import { cli, exec, fs, log, npm } from './common';
import * as push from './cmd.push';
export async function run(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
.tasks()
.task('build', async (e) => execScript(pkg, e, 'build'))
.task('bundle', async (e) => execScript(pkg, e, 'bundle'))
.task('manifest', async (e) => {
const entries = await getEntries(config);
const res = await bundler.prepare({ bundleDir, entries, silent: true });
manifest = res.manifest;
});
await tasks.run({ concurrent: false });
if (isPush) {
await push.bundle({ 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;
await exec.command(`yarn ${scriptName}`).run({ cwd, silent: true });
}
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) => {
let source = config.builder.entries;
if (!source) {
return [];
}
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 res.default;
}
log.error(`${err} Ensure the array is exported as the module default.`);
return [];
}
catch (error) {
log.error(`${err} ${error.message}`);
return [];
}
finally {
await fs.remove(fs.resolve('tmp'));
}
};