@codedoc/core
Version:
Create beautiful modern documentation websites.
116 lines • 6.44 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { utimesSync } from 'fs';
import express from 'express';
import ws from 'express-ws';
import chalk from 'chalk';
import { join } from 'path';
import { Subject, BehaviorSubject } from 'rxjs';
import { take } from 'rxjs/operators';
import { compile } from '@connectv/sdh';
import { _dropExt } from 'rxline/fs';
import { merge } from 'webpack-merge';
import { build } from '../build';
import { rebuild } from '../build/rebuild';
import { files } from '../build/files';
import { loadToC } from '../build/toc';
import { StatusCheckURL, StatusBuildingResponse, StatusReadyResponse, StatusErrorResponse } from './config';
import { watch } from './watch';
import { watchAssets } from './watch-assets';
import { reloadOnChange$ } from './reload';
import { buildingHtml } from './building-html';
export function serve(root, config, builder, themeInstaller, webpackConfig) {
let state = new BehaviorSubject({ status: StatusBuildingResponse });
config = Object.assign(Object.assign({}, config), { bundle: Object.assign(Object.assign({}, config.bundle), { init: [...config.bundle.init, reloadOnChange$] }) });
const wpconf = merge({ mode: 'development' }, webpackConfig || {});
state.next({ status: StatusBuildingResponse });
build(config, builder, themeInstaller, wpconf).then(assets => {
state.next({ status: StatusReadyResponse });
console.log(chalk `{greenBright #} Documents built!`);
const notifier = new Subject();
watch(root, config, notifier).subscribe((buildreq) => __awaiter(this, void 0, void 0, function* () {
if (buildreq === 'queued')
state.next({ status: StatusBuildingResponse });
else {
if (buildreq === 'all') {
assets.toc = yield loadToC(config);
}
rebuild(buildreq === 'all' ? files(config) : files(buildreq, config), config, builder, assets, wpconf).then(() => {
console.log(chalk `{greenBright #} Documents Rebuilt!`);
state.next({ status: StatusReadyResponse });
notifier.next();
}).catch(error => {
console.log(chalk `{redBright # REBUILD FAILED!!}`);
console.log((error === null || error === void 0 ? void 0 : error.message) || error);
state.next({ status: StatusErrorResponse, error: (error === null || error === void 0 ? void 0 : error.message) || error });
notifier.next();
});
}
}));
watchAssets(root, config, state).subscribe(filename => {
console.log(chalk `{gray # change in ${filename}, issuing reload to client ...}`);
state.next({ status: StatusBuildingResponse });
setTimeout(() => state.next({ status: StatusReadyResponse }), 300);
});
}).catch(error => {
console.log(chalk `{redBright # BUILD FAILED!!}`);
console.log((error === null || error === void 0 ? void 0 : error.message) || error);
state.next({ status: StatusErrorResponse, error: (error === null || error === void 0 ? void 0 : error.message) || error });
watch(root, config).pipe(take(1)).subscribe(() => {
// --> so this is shaky and requires explanation:
// --> we need to restart the whole process when the initial build fails.
// --> in order to do so, we simply touch the current file.
// --> since this file is imported, saving it should restart ts-node-dev's process.
utimesSync(__filename, new Date(), new Date());
});
});
const app = express();
ws(app);
app.get(StatusCheckURL, (_, res) => res.json(state.value));
app.ws(StatusCheckURL, ws => {
const sub = state.subscribe(v => ws.send(JSON.stringify(v)));
ws.on('error', () => sub.unsubscribe());
ws.on('close', () => sub.unsubscribe());
});
app.use(config.dest.namespace, express.static(config.dest.assets, { dotfiles: 'allow' }));
app.get(`${config.dest.namespace}/*`, (req, res) => {
const normalUrl = req.originalUrl.substr(config.dest.namespace.length).split('?')[0];
const filename = (normalUrl === '/' ? 'index' : normalUrl) + '.html';
const filepath = join(root, config.dest.html, filename);
res.sendFile(filepath, {}, err => {
if (err) {
if (state.value.status === StatusBuildingResponse) {
compile(buildingHtml)
.serialize()
.then(html => res.status(200).send(html));
}
else {
console.log();
console.log(chalk.red('# Not Found::'));
console.log(chalk.red('# ') + req.originalUrl);
console.log(chalk.red('# '));
console.log(chalk.red('# ') + chalk.gray('tried the following paths:'));
console.log(chalk.red('# ') + chalk.gray(join(root, config.dest.assets, req.originalUrl.substr(config.dest.namespace.length))));
console.log(chalk.red('# ') + chalk.gray(filepath));
console.log();
res.sendFile(join(root, config.dest.html, _dropExt(config.src.not_found) + '.html'), {}, err => {
if (err)
res.status(404).send('Not Found!!');
});
}
}
});
});
app.listen(config.dev.port, () => {
console.log(chalk.greenBright('# ') + 'Serving docs on '
+ chalk.cyan(`http://localhost:${config.dev.port}${config.dest.namespace}`));
});
}
//# sourceMappingURL=index.js.map