const path = require('path'); const gulp = require('gulp'); const debug = require('gulp-debug'); const del = require("del"); const through = require('through2'); const Vinyl = require("vinyl"); const merge = require('merge-stream'); const rename = require("gulp-rename"); const concat = require('gulp-concat'); const add = require('gulp-add'); const sourcemaps = require('gulp-sourcemaps'); const runSequence = require('run-sequence'); const uglify = require('gulp-uglify'); const babel = require('gulp-babel'); const browserify = require('browserify'); const buffer = require("vinyl-buffer"); const source = require('vinyl-source-stream'); const argv = require('yargs').argv; const gulpif = require('gulp-if'); const gutil = require('gulp-util'); const modulifyHeaders = { model: `exports.model = Model = { Game: {}, Board: {}, Move: {} }; ` , view: `exports.view = View = { Game: {}, Board: {}, Move: {} }; ` }; const allGames = {}; function HandleModuleGames(modelOnly) { return through.obj(function(file,enc,next) { // this is executed for every game module var push = this.push.bind(this); var moduleName = path.basename(file.path); var moduleManifest = require(file.path); var streams = []; moduleManifest.games.forEach((game) => { // this is executed for every game in the game module if(game.config.model.obsolete) return; // same some game data so we can list all games later allGames[game.name] = { title: game.config.model["title-en"], summary: game.config.model.summary, thumbnail: game.config.model.thumbnail, module: moduleName }; // create the game config file push(new Vinyl({ path: moduleName+"/"+game.name+"-config.js", contents: new Buffer('exports.config = '+JSON.stringify(game.config)) })); // create some specified resources if(!modelOnly) { var resources = { model: ["thumbnail","rules","description","credits"], view: ["css"] }; ["model","view"].forEach((modelView)=>{ resources[modelView].forEach((field)=>{ var files = []; switch(typeof game.config[modelView][field]) { case "string": files.push(game.config[modelView][field]); break; case "object": for(var f in game.config[modelView][field]) files.push(game.config[modelView][field][f]); break; } files = files.map((file)=>{ return "src/games/"+moduleName+"/"+file; }); var stream = gulp.src(files) .pipe(rename(function(path) { path.dirname = moduleName; })) .pipe(through.obj(function(file,enc,next) { push(file); next(); })) ; streams.push(stream); }); }); } // create model and view script files function Scripts(which) { var scripts = game[which+"Scripts"].map((script) => { return "src/games/"+moduleName+"/"+script; }); var fileName = moduleName+"/"+game.name+"-"+which+".js"; var stream = gulp.src(scripts) .pipe(gulpif(!argv.prod,sourcemaps.init())) .pipe(add('_',modulifyHeaders[which],true)) .pipe(concat(fileName)) .pipe(gulpif(argv.prod,uglify())) .pipe(gulpif(!argv.prod,sourcemaps.write('.'))) .pipe(through.obj(function(file,enc,next) { push(file); next(); })) streams.push(stream); } if(modelOnly) Scripts("model"); else ["model","view"].forEach(Scripts); }); // create module common resources if(!modelOnly) { var stream = gulp.src("src/games/"+moduleName+"/res/**/*") .pipe(rename(function(path) { path.dirname = moduleName + "/res/" +path.dirname; })) .pipe(through.obj(function(file,enc,next) { push(file); next(); })) ; streams.push(stream); } merge(streams) .on("finish",function() { next(); }) }); } gulp.task("build-node-games",function() { return gulp.src("src/games/*") .pipe(HandleModuleGames(true)) .pipe(gulp.dest("dist/node/games")); }); function ProcessJS(stream,concatName,skipBabel) { if(!argv.prod) stream = stream.pipe(sourcemaps.init()); if(!skipBabel) stream = stream.pipe(babel({ presets: ['es2015'], compact: !!argv.prod })); if(argv.prod) stream = stream.pipe(uglify()) .on('error', function(err) { gutil.log(gutil.colors.red('[Error]'), err.toString()); this.emit('end'); }) if(concatName) stream = stream.pipe(concat(concatName)); if(!argv.prod) stream = stream.pipe(sourcemaps.write(".")); return stream; } gulp.task("build-node-core",function() { var joclyCoreStream = ProcessJS(gulp.src([ "src/core/jocly.core.js", ])); var joclyBaseStream = ProcessJS(gulp.src([ "src/core/jocly.util.js", "src/core/jocly.uct.js", "src/core/jocly.game.js" ])); var joclyExtraStream = gulp.src([ "src/node/package.json", ]); var allGamesStream = source('jocly-allgames.js'); allGamesStream.end('exports.games = '+JSON.stringify(allGames)); allGamesStream = ProcessJS(allGamesStream.pipe(buffer())); return merge(joclyCoreStream,allGamesStream,joclyBaseStream,joclyExtraStream) .pipe(gulp.dest("dist/node")); }) function CopyLicense(target) { return gulp.src(["COPYING.md","CONTRIBUTING.md","AGPL-3.0.txt"]) .pipe(gulp.dest(target)); } gulp.task("copy-browser-license",function() { return CopyLicense("dist/browser"); }); gulp.task("copy-node-license",function() { return CopyLicense("dist/node"); }); gulp.task("build-node",function(callback) { runSequence("build-node-games",["build-node-core","copy-node-license"],callback); }); gulp.task("build-browser-games",function() { return gulp.src("src/games/*") .pipe(HandleModuleGames(false)) .pipe(gulp.dest("dist/browser/games")); }); gulp.task("build-browser-core",function() { var _ProcessJS = function(s) { return s; } var b = browserify({ entries: "src/browser/jocly.js", debug: true, standalone: "Jocly" }); var joclyBrowserStream = ProcessJS(b.bundle() .pipe(source('jocly.js')) .pipe(buffer())); var joclyCoreStream = ProcessJS(gulp.src([ "src/core/jocly.core.js", ])); var joclyBaseStream = ProcessJS(gulp.src([ "src/core/jocly.util.js", "src/core/jocly.uct.js", "src/core/jocly.game.js" ]),"jocly.game.js",true); var joclyExtraScriptsStream = ProcessJS(gulp.src([ "src/browser/jocly.aiworker.js", "src/browser/jocly.embed.js" ])); var joclyExtraStream = gulp.src([ "src/browser/jocly.embed.html" ]); var joclyResStream = gulp.src("src/browser/res/**/*") .pipe(rename(function(path) { path.dirname = "res/"+path.dirname; })); var allGamesStream = source('jocly-allgames.js'); allGamesStream.end('exports.games = '+JSON.stringify(allGames)); allGamesStream = ProcessJS(allGamesStream.pipe(buffer())); return merge(joclyBrowserStream,joclyCoreStream,allGamesStream,joclyBaseStream, joclyExtraStream,joclyExtraScriptsStream,joclyResStream) .pipe(gulp.dest("dist/browser")); }); gulp.task("build-browser-xdview",function() { const lib = "third-party/"; const src = "src/"; const srcLib = "src/lib/"; const nmLib = "node_modules/"; var libs = ProcessJS(gulp.src([ lib+"three.js", nmLib+"jquery/dist/jquery.js" ])); var packedLibs = ProcessJS(gulp.src([ lib+"SubdivisionModifier.js", lib+"tween.js", lib+"tween.fix.js", srcLib+"JoclyOrbitControls.js", lib+"DeviceOrientationControls.js", lib+"Projector.js", lib+"threex.domevent.js", lib+"threex.domevent.object3d.js", lib+"StereoEffect.js", lib+"AnaglyphEffect.js", srcLib+"VRGamepad.js", lib+"VRControls.js", lib+"VREffect.js", src+"browser/jocly.ar.js", src+"browser/jocly.state-machine.js", src+"browser/jocly.xd-view.js" ]),"jocly-xdview.js",true); return merge(libs,packedLibs) .pipe(gulp.dest("dist/browser")) ; }); gulp.task("build-browser",function(callback) { runSequence("build-browser-games",["build-browser-core", "build-browser-xdview","copy-browser-license"],callback); }); gulp.task("build",function(callback) { runSequence("clean",["build-browser","build-node"],callback); }); gulp.task("clean",function() { return del(["dist/*"],{force:true}); }); gulp.task("watch",function() { gulp.watch("src/games/**/*",["build-node-games","build-browser-games"]); gulp.watch("src/{browser,core,lib}/**/*",["build-browser-core","build-browser-xdview"]); gulp.watch("src/{node,core}/**/*",["build-node-core"]); }); gulp.task("help", function() { var help = ` usage: gulp [] [] commands: build: generate clean project build watch: watch project and build dynamically on changes options: --prod: generate for production `; console.log(help); process.exit(0); });