nodram
Version:
A Really MEAN Web Framework
232 lines (165 loc) • 7.75 kB
text/typescript
import {Observable, Observer} from "rxjs";
import * as spinner from '../../../helpers/spinner';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as chalk from 'chalk';
import * as _ from 'lodash';
import * as globby from 'globby';
import * as UglifyJS from 'uglify-js';
import {exec} from 'child_process';
import {Utils} from "../../../helpers/Utils";
import {RConfig} from "../../../helpers/RConfig";
export class ProdAppTask{
protected config;
constructor(protected ROOT_DIR){
this.config = new RConfig();
}
/**
* Refractor app
*/
public refactorApp() {
let start = new Date();
return Observable.create(observer => {
spinner.start('Refactoring app...');
let subscriber = this.generateHTML()
.concat(this.copyFiles())
.concat(this.rewriteProcfile())
.concat(this.removeModuleIdFromComponents());
subscriber.subscribe(
data => {},
err => {observer.error(err)},
() => {
let time: number = new Date().getTime() - start.getTime();
spinner.stop();
observer.next(`${chalk.green('✔')} ${chalk.blue(`Refactored App: ${Utils.timeHuman(time)}`)}`);
observer.complete();
});
})
}
public runWebpack(){
let start = new Date();
return Observable.create(observer => {
spinner.start('Bundling app...');
exec('node_modules\\.bin\\webpack', {cwd : process.cwd(), maxBuffer: 1024 * 500}, (err, stdout, stderr) => {
if (err) return observer.error(err);
/* observer.next(stdout);
observer.next(stderr);*/
let time: number = new Date().getTime() - start.getTime();
spinner.stop();
observer.next(`${chalk.green('✔')} ${chalk.blue(`Bundled App: ${Utils.timeHuman(time)}`)}`);
return observer.complete();
});
})
}
private generateHTML(){
const config = this.config;
const indexHTML = path.join(this.ROOT_DIR,"/src/templates/index.prod.html");
const content = _.template(fs.readFileSync(indexHTML).toString());
const dest = path.join(process.cwd(),"/server/views/index.html");
//get settings
const staticSite = config.get("staticSite");
const scriptsArray = config.get("scripts.bundles");
const scripts = Object.keys(scriptsArray).map(v => `${staticSite}/scripts/bundles/${v}.min.js`);
const stylesArray = config.get("styles.bundles");
const styles = Object.keys(stylesArray).map(v => `${staticSite}/styles/bundles/${v}.min.css`);
styles.push(`${staticSite}/styles/main.css`);
const title = config.get("indexHTML.title");
const metas = config.get("indexHTML.metas");
const favicons = config.get("indexHTML.favicons");
const scriptsOutDir = config.get("scripts.outDir");
const clientBundleFile = config.get('scripts.clientBundleFile');
const clientScriptBundle = `${staticSite}/scripts/${clientBundleFile}`;
return new Observable(observer => {
fs.outputFile(dest, content({
title: title, metas: metas, favicons : favicons,
styles : styles, scripts: scripts,
clientScriptBundle : clientScriptBundle
}), err => {
if (err) {
observer.error(err);
}
observer.complete();
});
});
}
public copyFiles(){
const scriptRootDir= this.config.get("scripts.rootDir");
const src = path.join(this.ROOT_DIR,"/src/templates/browser.bootstrap.prod.ts");
const dest = path.join(process.cwd(),scriptRootDir,"browser.bootstrap.ts");
const src2 = path.join(this.ROOT_DIR,"/src/templates/server.prod.ts");
const dest2 = path.join(process.cwd(),"/server/server.ts");
const src3 = path.join(this.ROOT_DIR,"/src/templates/browser.module.prod.ts");
const dest3 = path.join(process.cwd(),scriptRootDir,"browser.module.ts");
const src4 = path.join(this.ROOT_DIR,"/src/templates/prod.gitignore");
const dest4 = path.join(process.cwd(),".gitignore");
return new Observable(observer => {
try {
fs.copySync(src, dest);
fs.copySync(src2, dest2);
fs.copySync(src3, dest3);
fs.copySync(src4, dest4);
observer.complete();
}catch(err){observer.error(err);}
});
}
private rewriteProcfile(){
return new Observable(observer => {
let filename = path.join(process.cwd(),"Procfile");
fs.writeFile(filename,"web: node bin/server.js",'utf8',(err) =>{
if(err) return observer.error(err);
return observer.complete();
})
});
}
private removeModuleIdFromComponents(): Observable<any> {
const rootDir = this.config.get("scripts.rootDir");
const patterns = `${rootDir}/**/*.component.ts`;
return new Observable(observer => {
let srcFiles = globby.sync(`${rootDir}/**/*.component.ts`);
srcFiles.forEach(srcFile => {
let contents = fs.readFileSync(srcFile).toString().split('\n');
let index = contents.findIndex(line => line.includes('moduleId: module.id'));
if (index !== -1) {
contents.splice(index, 1);
fs.writeFileSync(srcFile, contents.join('\n'), 'utf8');
}
});
observer.complete();
});
}
public minifyBundleFiles(){
const srcFiles = this.config.get("scripts.bundles");
let bundles = Object.keys(srcFiles);
return new Observable(observer => {
spinner.start('Minifying library files...');
let start: Date = new Date();
Observable.from(bundles)
.map(bundle => {
let dest = path.join(process.cwd(), `/static/scripts/bundles/${bundle}.min.js`);
return Observable.create(ob => this.minifyBundleFile(srcFiles[bundle], dest, ob))
}).concatAll().subscribe(
data => observer.next(data),
err => this.handleTaskError(err, observer),
() => this.completeTask("Minified Library files", start, observer)
);
});
}
private minifyBundleFile(srcFiles: string[], dest: string, observer: Observer<string>){
const result = UglifyJS.minify(srcFiles);
fs.ensureDir(path.dirname(dest), err => {
if(err) return observer.error(err);
fs.writeFileSync(dest, result.code, "utf8");
observer.complete();
});
}
private completeTask(message: string, startDate: Date, observer: Observer<string>){
spinner.stop();
let time: number = new Date().getTime() - startDate.getTime();
observer.next(`${chalk.green('✔')} ${chalk.blue(`${message}: ${time}ms`)}`);
observer.complete();
}
private handleTaskError(message: string, observer: Observer<string>){
spinner.stop();
observer.error(`${chalk.red('✖')} ${chalk.yellow(message)}`);
}
}