const gulp = require('gulp'), concat = require('gulp-concat'), git = require('gulp-git'), log = require('fancy-log-levels'), noop = require('gulp-noop'), postcss = require('gulp-postcss'), shell = require('gulp-shell'), sort = require('gulp-sort'), sourcemaps = require('gulp-sourcemaps'), autoprefixer = require('autoprefixer'), which = require('which'), fs = require('fs'), path = require('path'), os = require('os'), yargs = require('yargs'), cfg = require('./build.config.json'); const args = yargs.options({ verbosity: {type: 'number', default: 0}, release: {type: 'boolean', default: false}, embedsourcemaps: {type: 'boolean', default: false}, sourcemapsincludecontent: {type: 'boolean', default: false} }).argv; const htmlOut = "tmp.html"; log(args.verbosity); function tweeCompilerExecutable() { const systemTweego = which.sync('tweego', {nothrow: true}); if (systemTweego) { log.info('Found system tweego at ', systemTweego); return systemTweego; } const archSuffix = os.arch() === 'x64' ? '64' : '86'; const platformSuffix = { 'Darwin': 'osx', 'Linux': 'nix', 'Windows_NT': 'win' }[os.type()]; const extension = os.type() === 'Windows_NT' ? '.exe' : ''; const res = path.join('.', 'devTools', 'tweeGo', `tweego_${platformSuffix}${archSuffix}${extension}`); log.info('Using bundled tweego at ', res); return res; } function concatFiles(srcGlob, destDir, destFileName) { return gulp.src(srcGlob) .pipe(sort()) .pipe(concat(destFileName)) .pipe(gulp.dest(destDir)); } function processScripts(srcGlob, destDir, destFileName) { const addSourcemaps = !args.release; const prefix = path.relative(destDir, srcGlob.substr(0, srcGlob.indexOf('*'))); return gulp.src(srcGlob) .pipe(sort()) .pipe(addSourcemaps ? sourcemaps.init() : noop()) .pipe(concat(destFileName)) .pipe(addSourcemaps ? sourcemaps.write(args.embedsourcemaps ? undefined : '.', { includeContent: args.sourcemapsincludecontent, sourceRoot: prefix, sourceMappingURLPrefix: path.relative(cfg.dirs.output, destDir) }) : noop()) .pipe(gulp.dest(destDir)); } function processStylesheets(srcGlob, destDir, destFileName) { const addSourcemaps = !args.release; const prefix = path.relative(destDir, srcGlob.substr(0, srcGlob.indexOf('*'))); return gulp.src(srcGlob) .pipe(sort()) .pipe(addSourcemaps ? sourcemaps.init() : noop()) .pipe(concat(destFileName)) .pipe(cfg.options.css.autoprefix ? postcss([autoprefixer({overrideBrowserslist: ['last 2 versions']})]) : noop()) .pipe(addSourcemaps ? sourcemaps.write(args.embedsourcemaps ? undefined : '.', { includeContent: args.sourcemapsincludecontent, sourceRoot: prefix, sourceMappingURLPrefix: path.relative(cfg.dirs.output, destDir) }) : noop()) .pipe(gulp.dest(destDir)); } function processSrc(name, processorFunc, globs, destDir, destFileName, ...args) { let tasks = []; if (!Array.isArray(globs) || globs.length === 1) { const src = Array.isArray(globs) ? globs[0] : globs; tasks.push(() => processorFunc(src, destDir, destFileName, args)); tasks[tasks.length - 1].displayName = "process-" + name; } else { // many globs const ext = path.extname(destFileName); const bn = path.basename(destFileName, ext); for (let i = 0; i < globs.length; ++i) { tasks.push(() => processorFunc(globs[i], destDir, `${bn}-${i}${ext}`, args)); tasks[tasks.length - 1].displayName = `process-${name}-${i}`; } } const res = gulp.parallel(...tasks); res.displayName = name; return res; } function injectGitCommit(cb) { git.revParse({args: '--short HEAD'}, function(err, hash) { if (!err) { log.info('current git hash: ', hash); fs.writeFile(cfg.gitVersionFile, `App.Version.commitHash = '${hash}';\n`, cb); } else { cb(); } }); } function cleanupGit(cb) { if (fs.existsSync(cfg.gitVersionFile)) { fs.unlink(cfg.gitVersionFile, cb); } else { cb(); } } function compileStory() { let sources = [path.join(cfg.dirs.intermediate, "story")]; sources.push(...cfg.sources.story.media); let modules = [path.join(cfg.dirs.intermediate, "module")]; let moduleArgs = modules.map(fn => `--module=${fn}`); const cmdLine = `${tweeCompilerExecutable()} -f ${cfg.twineformat} --head=${cfg.sources.head} -o ${path.join(cfg.dirs.intermediate, htmlOut)} ${moduleArgs.join(' ')} ${sources.join(' ')}`; log.info(cmdLine); return gulp.src(sources, {read: false}) .pipe(shell(cmdLine, {env: cfg.options.twee.environment})); } const processors = { "css": { func: processStylesheets, output: "styles.css" }, "js": { func: processScripts, output: "script.js" }, "twee": { func: concatFiles, output: "story.twee" }, "media": { func: null } }; function prepareComponent(name) { const c = cfg.sources[name]; const outDir = path.join(cfg.dirs.intermediate, name); const subTasks = []; for (const srcType in c) { const proc = processors[srcType]; if (proc.func) { subTasks.push(processSrc(`${name}-${srcType}`, proc.func, c[srcType], outDir, proc.output, cfg.options[srcType])); } } let r = gulp.parallel(subTasks); r.displayName = "prepare-" + name; return r; } function moveHTMLInPlace(cb) { fs.rename(path.join(cfg.dirs.intermediate, htmlOut), path.join(cfg.dirs.output, cfg.output), cb); } function clean(cb) { if (fs.existsSync(cfg.gitVersionFile)) { fs.unlinkSync(cfg.gitVersionFile); } fs.rmdirSync(cfg.dirs.intermediate, {recursive: true}); cb(); } function prepare(cb) { return gulp.series(clean, injectGitCommit, gulp.parallel(prepareComponent("module"), prepareComponent("story")))(cb); } if (fs.statSync('.git').isDirectory()) { gulp.task('buildHTML', gulp.series(prepare, compileStory, cleanupGit)); } else { gulp.task('buildHTML', gulp.series(prepare, compileStory)); } exports.clean = clean; exports.default = gulp.series('buildHTML', moveHTMLInPlace);