/* * Stairs * Copyright 2017 (c) Mark van Renswoude * * https://git.x2software.net/pub/Stairs */ 'use strict'; const gulp = require('gulp'); const htmlmin = require('gulp-htmlmin'); const cppstringify = require('./gulp-cppstringify'); const fs = require('fs'); const plumber = require('gulp-plumber'); const sass = require('gulp-sass'); const cleanCSS = require('gulp-clean-css'); const watch = require('gulp-debounced-watch'); const uglify = require('gulp-uglify'); const concat = require('gulp-concat'); const print = require('gulp-print'); const path = require('path'); const gzip = require('gulp-gzip'); const config = { assetsPath: 'web/', distPath: 'web/dist/', outputPath: 'src/assets/', firmwareArtifact: '.pioenvs/esp12e/firmware.bin', firmwareOutputPath: 'bin/' }; const HTMLMap = { 'index.html': 'Index' }; const JSMap = { 'bundle.js': 'BundleJS' }; const CSSMap = { 'bundle.css': 'BundleCSS' }; // There is an issue in the AsyncWebServer where it's apparantly running // out of memory on simultaneous requests. We'll work around it by // merging all the JS into one big file. // // https://github.com/me-no-dev/ESPAsyncWebServer/issues/256 const JSSrc = [ 'node_modules/axios/dist/axios.min.js', 'node_modules/vue/dist/vue.min.js', 'node_modules/vue-i18n/dist/vue-i18n.min.js', 'web/lang.js', 'web/app.js' ]; const SCSSSrc = [ 'web/site.scss' ] gulp.task('default', [ 'embedAssets' ], function(){}); gulp.task('watch', [ 'compileScss', 'compileJS' ], function() { watch(config.assetsPath + '*.scss', function() { gulp.start('compileScss'); }); watch(config.assetsPath + '*.js', function() { gulp.start('compileJS'); }); }); gulp.task('embedHTML', function() { return gulp.src(config.assetsPath + '*.html') .pipe(print(function(filepath) { return 'HTML: ' + filepath })) .pipe(htmlmin({ collapseWhitespace: true, removeComments: true, minifyCSS: true, minifyJS: true })) .pipe(gzip({ append: false })) .pipe(cppstringify('html.h', { headerDefineName: '__assets_html', map: HTMLMap, byteArray: true })) .pipe(gulp.dest(config.outputPath)); }); gulp.task('compileScss', function() { return gulp.src(SCSSSrc) .pipe(plumber({ errorHandler: function (error) { console.log(error.toString()); this.emit('end'); }})) .pipe(print(function(filepath) { return 'SCSS: ' + filepath })) .pipe(sass({ includePaths: ['node_modules/milligram/src'] })) .pipe(cleanCSS({compatibility: 'ie9'})) .pipe(concat('bundle.css')) .pipe(gulp.dest(config.distPath)); }); gulp.task('compileJS', function() { return gulp.src(JSSrc) .pipe(plumber({ errorHandler: function (error) { console.log(error.toString()); this.emit('end'); }})) .pipe(print(function(filepath) { return 'JS: ' + filepath })) .pipe(concat('bundle.js')) .pipe(uglify()) .pipe(gulp.dest(config.distPath)); }); gulp.task('embedJS', ['compileJS'], function() { return gulp.src([config.distPath + 'bundle.js']) .pipe(gzip({ append: false })) .pipe(cppstringify('js.h', { headerDefineName: '__assets_js', map: JSMap, byteArray: true })) .pipe(gulp.dest(config.outputPath)); }); gulp.task('embedCSS', ['compileScss'], function() { return gulp.src([config.distPath + 'bundle.css']) .pipe(gzip({ append: false })) .pipe(cppstringify('css.h', { headerDefineName: '__embed_css', map: CSSMap, byteArray: true })) .pipe(gulp.dest(config.outputPath)); }); var version = false; function getVersion(callback) { if (version !== false) { callback(version); return; } var versionData = ''; const cmd = spawn('gitversion'); cmd.stdout.on('data', function(data) { versionData += data; }); cmd.stderr.on('data', function(data) { console.log(data.toString().trim()); }); cmd.on('exit', function(code) { if (code != 0) return; var version = JSON.parse(versionData); callback(version); }); } gulp.task('embedVersion', function(cb) { getVersion(function(version) { var headerFile = "#ifndef __assets_version\r\n"; headerFile += "#define __assets_version\r\n\r\n"; headerFile += "const uint8_t VersionMajor = " + version.Major + ";\r\n"; headerFile += "const uint8_t VersionMinor = " + version.Minor + ";\r\n"; headerFile += "const uint8_t VersionPatch = " + version.Patch + ";\r\n"; headerFile += "const uint8_t VersionMetadata = " + version.BuildMetaData + ";\r\n"; headerFile += "const char VersionBranch[] = \"" + version.BranchName + "\";\r\n"; headerFile += "const char VersionSha[] = \"" + version.Sha + "\";\r\n"; headerFile += "const char VersionSemVer[] = \"" + version.SemVer + "\";\r\n"; headerFile += "const char VersionFullSemVer[] = \"" + version.FullSemVer + "\";\r\n"; headerFile += "const char VersionCommitDate[] = \"" + version.CommitDate + "\";\r\n"; headerFile += "\r\n#endif\r\n"; fs.writeFile(config.outputPath + 'version.h', headerFile, function(err) { if (err) throw err; cb(); }); }); }); gulp.task('copyBinary', function(cb) { if (!fs.existsSync(config.firmwareOutputPath)) fs.mkdirSync(config.firmwareOutputPath, '0777', true); getVersion(function(version) { var target = path.join(config.firmwareOutputPath, version.FullSemVer + '.bin'); console.log('Target: ' + target); var reader = fs.createReadStream(config.firmwareArtifact); reader.pipe(fs.createWriteStream(target)); reader.on('end', cb); }); }); gulp.task('embedAssets', ['embedHTML', 'embedJS', 'embedCSS', 'embedVersion'], function() { }) // PlatformIO const spawn = require('child_process').spawn; const argv = require('yargs').argv; var platformio = function(target) { var args = ['run']; if ("e" in argv) { args.push('-e'); args.push(argv.e); } if ("p" in argv) { args.push('--upload-port'); args.push(argv.p); } if (target) { args.push('-t'); args.push(target); } const cmd = spawn('platformio', args); cmd.stdout.on('data', function(data) { console.log(data.toString().trim()); }); cmd.stderr.on('data', function(data) { console.log(data.toString().trim()); }); cmd.on('exit', function(code) { if (code != 0) return; gulp.start('copyBinary'); }); } gulp.task('upload', ['embedHTML', 'embedAssets'], function() { platformio('upload'); }); gulp.task('build', ['embedHTML', 'embedAssets'], function() { platformio(false); });