// runs Ace's demo or builds the HTML static files
'use strict';
const express = require('express');
const extend = require('xtend');
const path = require('path');
const fs = require('fs');
const pretty = require('pretty');
const constants = require('./app/node/constants');
const { Page, Display, HbsHelpers } = require('./app/node/hbs-helpers');
let build = process.env.BUILD;
let htmlOutput = process.env.HTML == 'true';
let isForOnlineDemo = build === 'dist';
class App {
constructor() {
this.base = `./views`;
this.data = `./views/data`;
this.app = express();
this.display = new Display(this.base, this.data);
this.display.connect(this.app);
this.baseHref = path.relative(constants.HTML_FOLDER, '.')
if (this.baseHref == '') this.baseHref = './'
else this.baseHref = this.baseHref.replace(/\\/g, '/')+'/'
this.outputPath = constants.HTML_FOLDER;
if (this.outputPath.length == 0) this.outputPath = '.'
}
runServer() {
this.app
.get('/', function (req, res) {
res.redirect('/'+constants.DEFAULT_PAGE);
})
.get('/favicon.ico', (req, res) => {
res.redirect('/assets/favicon.png');
})
.get('/docs', (req, res) => {
res.redirect('/docs/index.html');
})
.get('/:page', (req, res) => {
let requestedPageId = req.params.page || 'page-error';
this._renderPage(requestedPageId, res);
})
this.app.use('/node_modules', express.static(path.join(__dirname, './node_modules')));
this.app.use('/assets', express.static(path.join(__dirname, './assets')));
this.app.use('/dist', express.static(path.join(__dirname, './dist')));
this.app.use('/docs', express.static(path.join(__dirname, './docs')));
this.app.use(`/views`, express.static(path.join(__dirname, `./views`)));
this.app.use(`/app/browser`, express.static(path.join(__dirname, `./app/browser`)));
this.app.listen(process.env.PORT || constants.DEFAULT_PORT);
}
generateHTML() {
let path = this.data + '/layouts/sidebar.json';
let sidebarData = null;
try {
sidebarData = JSON.parse(fs.readFileSync(path, 'utf-8'));
}
catch(err) {
//if (!(err instanceof Error) || err.code !== 'MODULE_NOT_FOUND') throw err;
console.log("Unable to generate HTML files");
return;
}
HbsHelpers.keepRequiredAssets(!isForOnlineDemo);
for(let d in sidebarData) {
let pageInfo = sidebarData[d];
if(pageInfo.link != false && pageInfo.id != null) {
this._renderPage(pageInfo.id, `${this.outputPath}/${pageInfo.id}.html`);
}
}
}
_renderPage(requestedPageId, outputStream) {
let page = new Page(requestedPageId, this.base, this.data);
page.setLayout(this.display.getLayout());
let layoutInfo = page.getLayoutInfo() || constants.DEFAULT_LAYOUT;//which is 'main'
layoutInfo = `${layoutInfo}/#index.hbs`
this.display.updatePagePartialsDirFor(page);
this.app.render(page.getTemplate(), {
useCDN: isForOnlineDemo,
staticHTML: htmlOutput,
baseHref: this.baseHref,
layout: layoutInfo,
// assign the variables
pageId: page.id,
title: page.getTitle(),
description: page.getDescription(),
sidebarItems: page.getSidebar(),
breadcrumbs: page.getBreadcrumbs(),
appFolder: constants.APP_FOLDER,
helpers: extend(
HbsHelpers.Helpers(page),
{
getPageLink: (uri) => {
return uri ? (htmlOutput ? `${this.outputPath}/${uri}.html` : uri) : '#';
}
}
)
}, (err, output) => {
if(err) console.log(err);
if( typeof outputStream === 'string' ) {
let prettyHtml = pretty(output);// , {ocd: true}
fs.writeFileSync(outputStream, prettyHtml);//save to file
}
else outputStream.send(output);//send to browser
}
);
}
}
let app = new App();
if (htmlOutput) {
if( app.outputPath.length > 0 && !fs.existsSync(app.outputPath) ) fs.mkdirSync(app.outputPath, { recursive: true });
app.generateHTML();
if (!isForOnlineDemo) {
// save the list of required assets to be put in final zip file
// because 'render' function is async, we do this on 'exit'
process.on('exit', () => {
let requireDemoAssets = HbsHelpers.getRequiredAssets();
requireDemoAssets = [...new Set(requireDemoAssets)]; //convert to `Set` to remove duplicates
requireDemoAssets = requireDemoAssets.filter((item) => item.match(/node_modules/))
requireDemoAssets = requireDemoAssets.map(item => {
return item.replace(/^(\W)*node_modules/ , 'node_modules')
// or include the whole folder (but package size will be too much)
// return item.replace(/^(?:\W)*(node_modules\/(?:[^\/]+)).*$/ , '$1')
});
fs.writeFileSync("required-assets.txt", JSON.stringify(requireDemoAssets, null, " "))
});
}
}
else {
app.runServer();
}