Bläddra i källkod

Merge pull request #4824 from RaananW/gulp-4

Moving to gulp 4, updating dependencies
Raanan Weber 7 år sedan
förälder
incheckning
7e4fca444a

+ 1 - 0
.travis.yml

@@ -33,6 +33,7 @@ jobs:
     - gulp tests-unit
     - travis_retry gulp tests-validation-virtualscreen
     - travis_retry gulp tests-validation-browserstack
+    - gulp tests-modules
     - travis_retry gulp tests-viewer-validation-virtualscreen
     - travis_retry gulp tests-viewer-validation-browserstack
 notifications:

+ 1 - 1
Tools/Gulp/gulp-addDtsExport.js

@@ -46,7 +46,7 @@ declare module '${moduleName}' {
         }
 
         try {
-            file.contents = new Buffer(moduleExportsAddition + String(file.contents));
+            file.contents = Buffer.from(moduleExportsAddition + String(file.contents));
             this.push(file);
 
         } catch (err) {

+ 2 - 2
Tools/Gulp/gulp-addES6Exports.js

@@ -75,10 +75,10 @@ ${exportsText}
         try {
             if (externalUsingBabylon) {
                 //file.contents = new Buffer(optionalRequire.concat(String(file.contents)));
-                file.contents = new Buffer(optionalRequire.concat(new Buffer(String(file.contents).concat(moduleExportAddition(baseModule)))));
+                file.contents = Buffer.from(optionalRequire.concat(Buffer.from(String(file.contents).concat(moduleExportAddition(baseModule)))));
             } else {
                 let pretext = subModule ? optionalRequire : '';
-                file.contents = new Buffer(pretext.concat(decorateAddition).concat(new Buffer(extendsAddition.concat(String(file.contents)).concat(moduleExportAddition(baseModule)))));
+                file.contents = Buffer.from(pretext.concat(decorateAddition).concat(Buffer.from(extendsAddition.concat(String(file.contents)).concat(moduleExportAddition(baseModule)))));
             }
             this.push(file);
         } catch (err) {

+ 1 - 1
Tools/Gulp/gulp-addModuleExports.js

@@ -99,7 +99,7 @@ if(typeof earcut !== 'undefined') {
 
         try {
             //if (config.externalUsingBabylon) {
-            file.contents = new Buffer(String('').concat(moduleExportAddition(varName)));
+            file.contents = Buffer.from(String('').concat(moduleExportAddition(varName)));
             /*} else {
                 let pretext = '';
                 file.contents = new Buffer(decorateAddition.concat(new Buffer(extendsAddition.concat(String('')).concat(moduleExportAddition(varName)))));

+ 1 - 1
Tools/Gulp/gulp-appendSrcToVariable.js

@@ -85,7 +85,7 @@ module.exports["${name}"] = data;
             cwd: firstFile.cwd,
             base: firstFile.base,
             path: joinedPath,
-            contents: new Buffer(content)
+            contents: Buffer.from(content)
         });
 
         this.push(joinedFile);

+ 1 - 1
Tools/Gulp/gulp-babylonModule.js

@@ -123,7 +123,7 @@ if(typeof require !== 'undefined'){
         }
 
         try {
-            file.contents = new Buffer(dependenciesText.concat(new Buffer(String(content).concat(exportsText))));
+            file.contents = Buffer.from(dependenciesText.concat(Buffer.from(String(content).concat(exportsText))));
             this.push(file);
         } catch (err) {
             this.emit('error', new gutil.PluginError('gulp-add-babylon-module', err, { fileName: file.path }));

+ 1 - 1
Tools/Gulp/gulp-decorateAndExtends.js

@@ -27,7 +27,7 @@ module.exports = function (varName, config) {
         }
 
         try {
-            file.contents = new Buffer(decorateAddition.concat(extendsAddition).concat(file.contents));
+            file.contents = Buffer.from(decorateAddition.concat(extendsAddition).concat(file.contents));
             this.push(file);
         } catch (err) {
             this.emit('error', new gutil.PluginError('gulp-decorate-and-extends', err, { fileName: file.path }));

+ 1 - 1
Tools/Gulp/gulp-dtsModuleSupport.js

@@ -84,7 +84,7 @@ module.exports = function (moduleName, inject, declarations, perFile, dependency
         }
 
         try {
-            file.contents = new Buffer(String(file.contents) + '\n' + importsString);
+            file.contents = Buffer.from(String(file.contents) + '\n' + importsString);
             this.push(file);
 
         } catch (err) {

+ 1 - 1
Tools/Gulp/gulp-es6ModuleExports.js

@@ -204,7 +204,7 @@ globalObject["BABYLON"] = BABYLON;
         }
 
         try {
-            file.contents = new Buffer(dependenciesText.concat(new Buffer(String(content).concat(exportsText))));
+            file.contents = Buffer.from(dependenciesText.concat(Buffer.from(String(content).concat(exportsText))));
             this.push(file);
         } catch (err) {
             this.emit('error', new gutil.PluginError('gulp-es6-module-exports', err, { fileName: file.path }));

+ 42 - 42
Tools/Gulp/gulp-removeShaderComments.js

@@ -8,12 +8,12 @@ var multiComment = 2;
 function uncomment(str, opts) {
     opts = opts || {};
 
-	var currentChar;
-	var nextChar;
-	var insideString = false;
-	var insideComment = 0;
-	var offset = 0;
-	var ret = '';
+    var currentChar;
+    var nextChar;
+    var insideString = false;
+    var insideComment = 0;
+    var offset = 0;
+    var ret = '';
 
     str = str.replace(/\r\n/g, '\n');
     str = str.replace(/[ \f\t\v]+/g, ' ');
@@ -34,45 +34,45 @@ function uncomment(str, opts) {
     str = str.replace(/, /g, ',');
     str = str.replace(/\n\n/g, '\n');
     str = str.replace(/\n /g, '\n');
-    
-	for (var i = 0; i < str.length; i++) {
-		currentChar = str[i];
-		nextChar = str[i + 1];
 
-		if (!insideComment && currentChar === '"') {
-			var escaped = str[i - 1] === '\\' && str[i - 2] !== '\\';
-			if (!escaped) {
-				insideString = !insideString;
-			}
-		}
+    for (var i = 0; i < str.length; i++) {
+        currentChar = str[i];
+        nextChar = str[i + 1];
 
-		if (insideString) {
-			continue;
-		}
+        if (!insideComment && currentChar === '"') {
+            var escaped = str[i - 1] === '\\' && str[i - 2] !== '\\';
+            if (!escaped) {
+                insideString = !insideString;
+            }
+        }
+
+        if (insideString) {
+            continue;
+        }
 
-		if (!insideComment && currentChar + nextChar === '//') {
-			ret += str.slice(offset, i);
-			offset = i;
-			insideComment = singleComment;
-			i++;
-		} else if (insideComment === singleComment && currentChar === '\n') {
-			insideComment = 0;
-			offset = i;
-		} else if (!insideComment && currentChar + nextChar === '/*') {
-			ret += str.slice(offset, i);
-			offset = i;
-			insideComment = multiComment;
-			i++;
-			continue;
-		} else if (insideComment === multiComment && currentChar + nextChar === '*/') {
-			i++;
-			insideComment = 0;
-			offset = i + 1;
-			continue;
-		}
-	}
+        if (!insideComment && currentChar + nextChar === '//') {
+            ret += str.slice(offset, i);
+            offset = i;
+            insideComment = singleComment;
+            i++;
+        } else if (insideComment === singleComment && currentChar === '\n') {
+            insideComment = 0;
+            offset = i;
+        } else if (!insideComment && currentChar + nextChar === '/*') {
+            ret += str.slice(offset, i);
+            offset = i;
+            insideComment = multiComment;
+            i++;
+            continue;
+        } else if (insideComment === multiComment && currentChar + nextChar === '*/') {
+            i++;
+            insideComment = 0;
+            offset = i + 1;
+            continue;
+        }
+    }
 
-	return ret + (insideComment ? '' : str.substr(offset));
+    return ret + (insideComment ? '' : str.substr(offset));
 }
 
 function gulpUncomment(options) {
@@ -88,7 +88,7 @@ function main(options, func) {
         if (file.isStream()) {
             cb(new PluginError("Remove Shader Comments", "Streaming not supported."));
         }
-        file.contents = new Buffer(func(file.contents.toString(), options));
+        file.contents = Buffer.from(func(file.contents.toString(), options));
         this.push(file);
         return cb();
     });

+ 30 - 30
Tools/Gulp/gulp-validateTypedoc.js

@@ -11,19 +11,19 @@ var supportsColor = require('color-support');
 
 var hasColors = supportsColor();
 
-var red =       hasColors ? '\x1b[31m' : '';
-var yellow =    hasColors ? '\x1b[33m' : '';
-var green =     hasColors ? '\x1b[32m' : '';
-var gray =      hasColors ? '\x1b[90m' : '';
-var white =     hasColors ? '\x1b[97m' : '';
-var clear =     hasColors ? '\x1b[0m' : '';
+var red = hasColors ? '\x1b[31m' : '';
+var yellow = hasColors ? '\x1b[33m' : '';
+var green = hasColors ? '\x1b[32m' : '';
+var gray = hasColors ? '\x1b[90m' : '';
+var white = hasColors ? '\x1b[97m' : '';
+var clear = hasColors ? '\x1b[0m' : '';
 
 var currentColor = undefined;
 
 function getTimestamp() {
     var time = new Date();
-    var timeInString = ("0" + time.getHours()).slice(-2) + ":" + 
-        ("0" + time.getMinutes()).slice(-2) + ":" + 
+    var timeInString = ("0" + time.getHours()).slice(-2) + ":" +
+        ("0" + time.getMinutes()).slice(-2) + ":" +
         ("0" + time.getSeconds()).slice(-2);
 
     if (currentColor) {
@@ -59,7 +59,7 @@ function err() {
     var time = getTimestamp();
     process.stderr.write(time + ' ');
     currentColor = undefined;
-    
+
     console.error.apply(console, arguments);
     return this;
 }
@@ -86,13 +86,13 @@ function Validate(validationBaselineFileName, namespaceName, validateNamingConve
     this.validateNamingConvention = validateNamingConvention;
     this.generateBaseLine = generateBaseLine;
 
-    this.previousResults = { };
+    this.previousResults = {};
     this.results = {
         errors: 0
     };
 }
 
-Validate.hasTag = function(node, tagName) {
+Validate.hasTag = function (node, tagName) {
     tagName = tagName.trim().toLowerCase();
 
     if (node.comment && node.comment.tags) {
@@ -106,7 +106,7 @@ Validate.hasTag = function(node, tagName) {
     return false;
 }
 
-Validate.position = function(node) {
+Validate.position = function (node) {
     if (!node.sources) {
         log(node);
     }
@@ -126,12 +126,12 @@ Validate.prototype.errorCallback = function (parent, node, nodeKind, category, t
     if (node === "toString") {
         node = "ToString";
     }
-    
+
     // Checks against previous results.
     var previousResults = this.previousResults[this.filePath];
     if (previousResults) {
         var previousRootName = parent ? parent : node;
-        var needCheck = true; 
+        var needCheck = true;
 
         if (Array.isArray(previousRootName)) {
             while (previousRootName.length > 1) {
@@ -165,7 +165,7 @@ Validate.prototype.errorCallback = function (parent, node, nodeKind, category, t
                             if (previousType) {
                                 // Early exit as it was already in the previous build.
                                 return;
-                            }    
+                            }
                         }
                     }
                 }
@@ -179,19 +179,19 @@ Validate.prototype.errorCallback = function (parent, node, nodeKind, category, t
     if (Array.isArray(rootName)) {
         while (rootName.length > 1) {
             var first = rootName.shift();
-            current = current[first] = current[first] || { };
+            current = current[first] = current[first] || {};
         }
         rootName = rootName.shift();
     }
 
-    current = current[rootName] = current[rootName] || { };
-    current = current[nodeKind] = current[nodeKind] || { };    
+    current = current[rootName] = current[rootName] || {};
+    current = current[nodeKind] = current[nodeKind] || {};
     if (parent) {
-        current = current[node] = current[node] || { };
+        current = current[node] = current[node] || {};
     }
-    current = current[category] = current[category] || { };
+    current = current[category] = current[category] || {};
     current = current[type] = true;
-    
+
     results.errors++;
 
     if (!this.generateBaseLine) {
@@ -216,7 +216,7 @@ Validate.prototype.add = function (filePath, content) {
     this.filePath = filePath && unixStylePath(filePath);
 
     if (!Buffer.isBuffer(content)) {
-        content = new Buffer(content);
+        content = Buffer.from(content);
     }
 
     var contentString = content.toString();
@@ -271,7 +271,7 @@ Validate.prototype.validateTypedocNamespaces = function (namespaces) {
 /**
  * Validate classes and modules attach to a declaration file from a TypeDoc JSON file
  */
-Validate.prototype.validateTypedocNamespace = function(namespace) {
+Validate.prototype.validateTypedocNamespace = function (namespace) {
     var containerNode;
     var childNode;
     var children;
@@ -294,7 +294,7 @@ Validate.prototype.validateTypedocNamespace = function(namespace) {
         if (!containerNode.flags.isPublic &&
             !containerNode.flags.isPrivate &&
             !containerNode.flags.isProtected) {
-                containerNode.flags.isPublic = true;
+            containerNode.flags.isPublic = true;
         }
         isPublic = containerNode.flags.isPublic;
 
@@ -408,7 +408,7 @@ Validate.prototype.validateTypedocNamespace = function(namespace) {
 /**
  * Validate that tags are recognized
  */
-Validate.prototype.validateTags = function(node) {
+Validate.prototype.validateTags = function (node) {
     var tags;
     var errorTags = [];
 
@@ -433,7 +433,7 @@ Validate.prototype.validateTags = function(node) {
 /**
  * Validate that a JSON node has the correct TypeDoc comments
  */
-Validate.prototype.validateComment = function(node) {
+Validate.prototype.validateComment = function (node) {
 
     // Return-only methods are allowed to just have a @return tag
     if ((node.kindString === "Call signature" || node.kindString === "Accessor") && !node.parameters && node.comment && node.comment.returns) {
@@ -453,7 +453,7 @@ Validate.prototype.validateComment = function(node) {
     // Return true for overwrited properties
     if (node.overwrites) {
         return true;
-    } 
+    }
 
     // Check comments.
     if (node.comment) {
@@ -475,7 +475,7 @@ Validate.prototype.validateComment = function(node) {
 /**
  * Validate comments for paramters on a node
  */
-Validate.prototype.validateParameters = function(containerNode, method, signature, parameters, isPublic) {
+Validate.prototype.validateParameters = function (containerNode, method, signature, parameters, isPublic) {
     var parametersNode;
     for (var parameter in parameters) {
         parametersNode = parameters[parameter];
@@ -504,7 +504,7 @@ Validate.prototype.validateParameters = function(containerNode, method, signatur
 /**
  * Validate naming conventions of a node
  */
-Validate.prototype.validateNaming = function(parent, node) {
+Validate.prototype.validateNaming = function (parent, node) {
     if (!this.validateNamingConvention) {
         return;
     }
@@ -712,7 +712,7 @@ function gulpValidateTypedoc(validationBaselineFileName, namespaceName, validate
 
         var action = generateBaseLine ? "baseline generation" : "validation";
         var self = this;
-        var error = function(message) {
+        var error = function (message) {
             generateBaseLine ? warn : err;
             if (generateBaseLine) {
                 warn(message);

+ 288 - 150
Tools/Gulp/gulpfile.js

@@ -16,7 +16,6 @@ var merge2 = require("merge2");
 var concat = require("gulp-concat");
 var rename = require("gulp-rename");
 var cleants = require("gulp-clean-ts-extends");
-var runSequence = require("run-sequence");
 var replace = require("gulp-replace");
 var uncommentShader = require("./gulp-removeShaderComments");
 var expect = require("gulp-expect-file");
@@ -181,7 +180,7 @@ gulp.task("includeShaders", function (cb) {
     cb();
 });
 
-gulp.task("shaders", ["includeShaders"], function (cb) {
+gulp.task("shaders", gulp.series("includeShaders", function (cb) {
     var filesToProcess = determineFilesToProcess("shaders");
     shadersStream = gulp.src(filesToProcess).
         pipe(expect.real({ errorOnFailure: true }, filesToProcess)).
@@ -190,7 +189,7 @@ gulp.task("shaders", ["includeShaders"], function (cb) {
             variableName: "BABYLON.Effect.ShadersStore", asMap: true, namingCallback: shadersName
         }));
     cb();
-});
+}));
 
 gulp.task("workers", function (cb) {
     workersStream = config.workers.map(function (workerDef) {
@@ -207,7 +206,7 @@ gulp.task("workers", function (cb) {
 /**
  * Build tasks to concat minify uflify optimise the BJS js in different flavor (workers...).
  */
-gulp.task("buildWorker", ["workers", "shaders"], function () {
+gulp.task("buildWorker", gulp.series("workers", "shaders", function () {
     var filesToProcess = determineFilesToProcess("files");
     return merge2(
         gulp.src(filesToProcess).
@@ -227,18 +226,19 @@ gulp.task("buildWorker", ["workers", "shaders"], function () {
         .pipe(uglify())
         .pipe(optimisejs())
         .pipe(gulp.dest(config.build.outputDirectory));
-});
+}));
 
-gulp.task("build", ["shaders"], function () {
+gulp.task("build", gulp.series("shaders", function build() {
     var filesToProcess = determineFilesToProcess("files");
     var directFilesToProcess = determineFilesToProcess("directFiles");
-    let mergedStreams = merge2(
-        gulp.src(filesToProcess).
-            pipe(expect.real({ errorOnFailure: true }, filesToProcess)),
+    let merged = [gulp.src(filesToProcess).
+        pipe(expect.real({ errorOnFailure: true }, filesToProcess)),
         shadersStream,
-        includeShadersStream,
-        gulp.src(directFilesToProcess)
-    )
+        includeShadersStream];
+    if (directFilesToProcess.length) {
+        merged.push(gulp.src(directFilesToProcess));
+    }
+    let mergedStreams = merge2(merged);
     return merge2(
         mergedStreams
             .pipe(concat(config.build.noModuleFilename))
@@ -264,7 +264,7 @@ gulp.task("build", ["shaders"], function () {
             .pipe(addES6Exports("BABYLON"))
             .pipe(gulp.dest(config.build.outputDirectory))
     );
-});
+}));
 
 /*
 * Compiles all typescript files and creating a js and a declaration file.
@@ -357,36 +357,64 @@ var buildExternalLibraries = function (settings) {
 }
 
 var buildExternalLibrary = function (library, settings, watch) {
-    var tsProcess = gulp.src(library.files, { base: settings.build.srcOutputDirectory })
-        .pipe(sourcemaps.init())
-        .pipe(typescript(externalTsConfig));
-
-    var includeShader = gulp.src(library.shadersIncludeFiles || [], { base: settings.build.srcOutputDirectory })
-        .pipe(uncommentShader())
-        .pipe(appendSrcToVariable("BABYLON.Effect.IncludesShadersStore", includeShadersName, library.output + ".include.fx"))
-        .pipe(gulp.dest(settings.build.srcOutputDirectory));
-
-    var shader = gulp.src(library.shaderFiles || [], { base: settings.build.srcOutputDirectory })
-        .pipe(uncommentShader())
-        .pipe(appendSrcToVariable("BABYLON.Effect.ShadersStore", shadersName, library.output + ".fx"))
-        .pipe(gulp.dest(settings.build.srcOutputDirectory));
-
-    var dev = tsProcess.js
-        .pipe(sourcemaps.write("./", {
-            includeContent: false,
-            sourceRoot: (filePath) => {
-                return "";
-            }
-        })).pipe(gulp.dest(settings.build.srcOutputDirectory));
+    var tsProcess;
+    if (library.files && library.files.length) {
+        tsProcess = gulp.src(library.files, { base: settings.build.srcOutputDirectory })
+            .pipe(sourcemaps.init())
+            .pipe(typescript(externalTsConfig));
+    }
+
+    let tasks = [];
+
+    let shaderTask;
+
+    let shadersIndlueTask;
+
+    if (library.shadersIncludeFiles && library.shadersIncludeFiles.length) {
+        shadersIndlueTask = gulp.src(library.shadersIncludeFiles, { base: settings.build.srcOutputDirectory })
+            .pipe(uncommentShader())
+            .pipe(appendSrcToVariable("BABYLON.Effect.IncludesShadersStore", includeShadersName, library.output + ".include.fx"))
+            .pipe(gulp.dest(settings.build.srcOutputDirectory));
+        tasks.push(shadersIndlueTask);
+    }
+
+    if (library.shaderFiles && library.shaderFiles.length) {
+        shaderTask = gulp.src(library.shaderFiles, { base: settings.build.srcOutputDirectory })
+            .pipe(uncommentShader())
+            .pipe(appendSrcToVariable("BABYLON.Effect.ShadersStore", shadersName, library.output + ".fx"))
+            .pipe(gulp.dest(settings.build.srcOutputDirectory));
+        tasks.push(shaderTask);
+    }
+
+    var dev;
+
+    if (tsProcess) {
+        dev = tsProcess.js
+            .pipe(sourcemaps.write("./", {
+                includeContent: false,
+                sourceRoot: (filePath) => {
+                    return "";
+                }
+            })).pipe(gulp.dest(settings.build.srcOutputDirectory));
+
+        tasks.push(dev);
+    }
 
     var outputDirectory = config.build.outputDirectory + settings.build.distOutputDirectory;
-    var css = gulp.src(library.sassFiles || [])
-        .pipe(sass().on("error", sass.logError))
-        .pipe(concat(library.output.replace(".js", ".css")))
-        .pipe(gulp.dest(outputDirectory));
+
+    let cssTask;
+
+    if (library.sassFiles && library.sassFiles.length) {
+        cssTask = gulp.src(library.sassFiles)
+            .pipe(sass().on("error", sass.logError))
+            .pipe(concat(library.output.replace(".js", ".css")))
+            .pipe(gulp.dest(outputDirectory));
+        tasks.push(cssTask);
+    }
+
 
     if (watch) {
-        return merge2([shader, includeShader, dev, css]);
+        return merge2(tasks);
     }
     else {
         /*if (library.bundle) {
@@ -405,48 +433,88 @@ var buildExternalLibrary = function (library, settings, watch) {
                 .pipe(optimisejs())
                 .pipe(gulp.dest(outputDirectory));
         } else {*/
-        var code = merge2([tsProcess.js, shader, includeShader])
-            .pipe(concat(library.output))
+        let currentTasks = [];
+        if (tsProcess) {
+            currentTasks.push(tsProcess.js);
+        }
+        if (shaderTask) {
+            currentTasks.push(shaderTask);
+        }
+        if (shadersIndlueTask) {
+            currentTasks.push(shadersIndlueTask);
+        }
+        var code;
+
+        if (currentTasks.length) {
+            code = merge2(currentTasks)
+                .pipe(concat(library.output));
+        }
 
-        if (library.buildAsModule) {
+        if (library.buildAsModule && code) {
             code = code.pipe(replace(extendsSearchRegex, ""))
                 .pipe(replace(decorateSearchRegex, ""))
                 .pipe(addDecorateAndExtends())
                 .pipe(addModuleExports(library.moduleDeclaration, { subModule: true, extendsRoot: library.extendsRoot }))
         }
 
-        code = code.pipe(gulp.dest(outputDirectory))
-            .pipe(cleants())
-            .pipe(rename({ extname: ".min.js" }))
-            .pipe(uglify())
-            .pipe(optimisejs())
-            .pipe(gulp.dest(outputDirectory));
-        /*}*/
+        if (code) {
+
+            code = code.pipe(gulp.dest(outputDirectory))
+                .pipe(cleants())
+                .pipe(rename({ extname: ".min.js" }))
+                .pipe(uglify())
+                .pipe(optimisejs())
+                .pipe(gulp.dest(outputDirectory));
+            /*}*/
 
+        }
 
+        var dts;
 
-        var dts = tsProcess.dts
-            .pipe(concat(library.output))
-            .pipe(replace(referenceSearchRegex, ""))
-            .pipe(rename({ extname: ".d.ts" }))
-            .pipe(gulp.dest(outputDirectory));
+        if (tsProcess) {
+            dts = tsProcess.dts
+                .pipe(concat(library.output))
+                .pipe(replace(referenceSearchRegex, ""))
+                .pipe(rename({ extname: ".d.ts" }))
+                .pipe(gulp.dest(outputDirectory));
+        }
 
         var waitAll;
+        let waitAllTasks = [];
+        if (cssTask) {
+            waitAllTasks.push(cssTask);
+        }
+
+        if (dev) {
+            waitAllTasks.push(dev);
+        }
+
+        if (code) {
+            waitAllTasks.push(code);
+        }
+
+        if (dts) {
+            waitAllTasks.push(dts);
+        }
 
-        if (library.buildAsModule) {
+        if (library.buildAsModule && tsProcess) {
             var dts2 = tsProcess.dts
                 .pipe(concat(library.output))
                 .pipe(replace(referenceSearchRegex, ""))
                 .pipe(addDtsExport(library.moduleDeclaration, library.moduleName, true, library.extendsRoot, config.build.extraTypesDependencies))
                 .pipe(rename({ extname: ".module.d.ts" }))
                 .pipe(gulp.dest(outputDirectory));
-            waitAll = merge2([dev, code, css, dts, dts2]);
-        } else {
-            waitAll = merge2([dev, code, css, dts]);
+            waitAllTasks.push(dts2);
+        }
+        if (waitAllTasks.length) {
+            waitAll = merge2(waitAllTasks);
         }
 
         if (library.webpack) {
-            let sequence = [waitAll];
+            let sequence = [];
+            if (waitAll) {
+                sequence.push(waitAll);
+            }
 
             if (settings.build.outputs) {
 
@@ -477,10 +545,10 @@ var buildExternalLibrary = function (library, settings, watch) {
                             fs.readFile(fileLocation, function (err, data) {
                                 if (err) throw err;
                                 data = (settings.build.dtsBundle.prependText || "") + '\n' + data.toString();
-                                fs.writeFile(fileLocation, data);
+                                fs.writeFileSync(fileLocation, data);
                                 if (settings.build.processDeclaration) {
                                     var newData = processDeclaration(data, settings.build.processDeclaration);
-                                    fs.writeFile(fileLocation.replace('.module', ''), newData);
+                                    fs.writeFileSync(fileLocation.replace('.module', ''), newData);
                                 }
                             });
                         });
@@ -556,9 +624,9 @@ var buildExternalLibrary = function (library, settings, watch) {
                             fs.readFile(fileLocation, function (err, data) {
                                 if (err) throw err;
                                 var newData = processDeclaration(data, settings.build.processDeclaration);
-                                fs.writeFile(fileLocation.replace('.module', ''), newData);
+                                fs.writeFileSync(fileLocation.replace('.module', ''), newData);
                                 //legacy module support
-                                fs.writeFile(fileLocation, data + "\n" + newData);
+                                fs.writeFileSync(fileLocation, data + "\n" + newData);
                             });
                         }
                     });
@@ -581,28 +649,17 @@ var buildExternalLibrary = function (library, settings, watch) {
             return merge2(sequence);
         }
         else {
-            return waitAll;
+            return waitAll || Promise.resolve();
         }
     }
 }
 
-/**
- * The default task, concat and min the main BJS files.
- */
-gulp.task("default", function (cb) {
-    runSequence("typescript-all", "intellisense", "typedoc-all", "tests-unit", "tests-validation-virtualscreen", "tests-validation-browserstack", cb);
-});
-
-gulp.task("mainBuild", function (cb) {
-    runSequence("buildWorker", "build", cb);
-});
+gulp.task("mainBuild", gulp.series("buildWorker", "build"));
 
 /**
  * Build the releasable files.
  */
-gulp.task("typescript", function (cb) {
-    runSequence("typescript-compile", "mainBuild", cb);
-});
+gulp.task("typescript", gulp.series("typescript-compile", "mainBuild"));
 
 /**
  * Dynamic module creation.
@@ -613,22 +670,12 @@ config.modules.map(function (module) {
     });
 });
 
-gulp.task("typescript-libraries", config.modules, function () {
-});
+gulp.task("typescript-libraries", gulp.series(config.modules));
 
 /**
  * Custom build with full path file control; used by profile.html
  */
-gulp.task("build-custom", function (cb) {
-    runSequence("typescript-compile", "build", cb);
-});
-
-/**
- * Do it all.
- */
-gulp.task("typescript-all", function (cb) {
-    runSequence("typescript", "typescript-libraries", "netlify-cleanup", cb);
-});
+gulp.task("build-custom", gulp.series("typescript-compile", "build"));
 
 /**
  * Watch ts files from typescript .
@@ -639,12 +686,13 @@ gulp.task("srcTscWatch", function () {
     process.argv[3] = "-p";
     process.argv[4] = "../../src/tsconfig.json";
     require("./node_modules/typescript/lib/tsc.js");
+    return Promise.resolve();
 });
 
 /**
  * Watch ts files and fire repective tasks.
  */
-gulp.task("watch", ["srcTscWatch"], function () {
+gulp.task("watch", gulp.series("srcTscWatch", function startWatch() {
     var interval = 1000;
 
     var tasks = [];
@@ -682,11 +730,13 @@ gulp.task("watch", ["srcTscWatch"], function () {
         });
     });
 
-    return tasks;
-});
+    console.log(tasks.length);
+
+    return Promise.resolve();
+}));
 
 gulp.task("intellisense", function () {
-    gulp.src(config.build.intellisenseSources)
+    return gulp.src(config.build.intellisenseSources)
         .pipe(concat(config.build.intellisenseFile))
         .pipe(replace(/^\s+_.*?;/gm, ""))
         .pipe(replace(/^\s+_[\S\s]*?}/gm, ""))
@@ -700,7 +750,7 @@ gulp.task("intellisense", function () {
  * Embedded local dev env management.
  */
 gulp.task("deployLocalDev", function () {
-    gulp.src("../../localDev/template/**.*")
+    return gulp.src("../../localDev/template/**.*")
         .pipe(gulp.dest("../../localDev/src/"));
 });
 
@@ -718,14 +768,13 @@ gulp.task("webserver", function () {
         options.host = "0.0.0.0";
     }
 
-    gulp.src("../../.").pipe(webserver(options));
+    return gulp.src("../../.").pipe(webserver(options));
 });
 
 /**
  * Combine Webserver and Watch as long as vscode does not handle multi tasks.
  */
-gulp.task("run", ["watch", "webserver"], function () {
-});
+gulp.task("run", gulp.series("watch", "webserver"));
 
 /**
  * Cleans map and js files from the src folder.
@@ -745,7 +794,7 @@ gulp.task("netlify-cleanup", function () {
         ], { force: true });
     }
     else {
-        return true;
+        return Promise.resolve();
     }
 })
 
@@ -807,7 +856,7 @@ gulp.task('prepare-for-modules', /*["modules-compile"],*/ function () {
     return merge2(tasks);
 });
 
-gulp.task('prepare-dependency-tree', ["prepare-for-modules"], function () {
+gulp.task('prepare-dependency-tree', gulp.series("prepare-for-modules", function () {
     let tasks = [];
 
     // now calculate internal dependencies in the .ts files!
@@ -820,11 +869,11 @@ gulp.task('prepare-dependency-tree', ["prepare-for-modules"], function () {
     });
 
     return merge2(tasks);
-});
+}));
 
 // generate the modules directory, along with commonjs modules and es6 modules
 // Note - the generated modules are UNMINIFIED! The user will choose whether they want to minify or not.
-gulp.task("modules", ["prepare-dependency-tree"], function () {
+gulp.task("modules", gulp.series("prepare-dependency-tree", function () {
     let tasks = [];
 
     Object.keys(config.workloads)
@@ -947,7 +996,7 @@ gulp.task("modules", ["prepare-dependency-tree"], function () {
 
     // run da tasks man!
     return merge2(tasks);
-})
+}));
 
 /**
  * Generate the TypeDoc JSON output in order to create code metadata.
@@ -1004,17 +1053,13 @@ gulp.task("typedoc-generateValidationBaseline", function () {
  * Validate the code comments and style case convention through typedoc and
  * generate the new baseline.
  */
-gulp.task("typedoc-all", function (cb) {
-    runSequence("typedoc-generate", "typedoc-validate", "typedoc-generateValidationBaseline", cb);
-});
+gulp.task("typedoc-all", gulp.series("typedoc-generate", "typedoc-validate", "typedoc-generateValidationBaseline"));
 
 
 /**
  * Validate compile the code and check the comments and style case convention through typedoc
  */
-gulp.task("typedoc-check", function (cb) {
-    runSequence("typescript-compile", "gui", "loaders", "serializers", "typedoc-generate", "typedoc-validate", cb);
-});
+gulp.task("typedoc-check", gulp.series("typescript-compile", "gui", "loaders", "serializers", "typedoc-generate", "typedoc-validate"));
 
 /**
  * Launches the KARMA validation tests in chrome in order to debug them.
@@ -1087,7 +1132,7 @@ gulp.task("tests-unit-transpile", function (done) {
  * Launches the KARMA unit tests in phantomJS.
  * (Can only be launch on any branches.)
  */
-gulp.task("tests-unit-debug", ["tests-unit-transpile"], function (done) {
+gulp.task("tests-unit-debug", gulp.series("tests-unit-transpile", function (done) {
     var kamaServerOptions = {
         configFile: __dirname + "/../../tests/unit/karma.conf.js",
         singleRun: false,
@@ -1096,9 +1141,9 @@ gulp.task("tests-unit-debug", ["tests-unit-transpile"], function (done) {
 
     var server = new karmaServer(kamaServerOptions, done);
     server.start();
-});
+}));
 
-gulp.task("tests-babylon-unit", ["tests-unit-transpile"], function (done) {
+gulp.task("tests-babylon-unit", gulp.series("tests-unit-transpile", function (done) {
     var kamaServerOptions = {
         configFile: __dirname + "/../../tests/unit/karma.conf.js",
         singleRun: true
@@ -1106,15 +1151,7 @@ gulp.task("tests-babylon-unit", ["tests-unit-transpile"], function (done) {
 
     var server = new karmaServer(kamaServerOptions, done);
     server.start();
-});
-
-/**
- * Launches the KARMA unit tests in phantomJS.
- * (Can only be launch on any branches.)
- */
-gulp.task("tests-unit", function (cb) {
-    runSequence("tests-babylon-unit", "tests-viewer-unit", cb);
-});
+}));
 
 var rmDir = function (dirPath) {
     try { var files = fs.readdirSync(dirPath); }
@@ -1131,10 +1168,29 @@ var rmDir = function (dirPath) {
 };
 
 /**
+ * Transpiles viewer typescript unit tests. 
+ */
+gulp.task("tests-viewer-validation-transpile", function () {
+
+    let wpBuild = webpackStream(require('../../Viewer/webpack.gulp.config.js'), webpack);
+
+    // clean the built directory
+    rmDir("../../Viewer/tests/build/");
+
+    return wpBuild
+        .pipe(rename(function (path) {
+            if (path.extname === '.js') {
+                path.basename = "test";
+            }
+        }))
+        .pipe(gulp.dest("../../Viewer/tests/build/"));
+});
+
+/**
  * Launches the viewer's KARMA validation tests in chrome in order to debug them.
  * (Can only be launch locally.)
  */
-gulp.task("tests-viewer-validation-karma", ["tests-viewer-validation-transpile"], function (done) {
+gulp.task("tests-viewer-validation-karma", gulp.series("tests-viewer-validation-transpile", function (done) {
     var kamaServerOptions = {
         configFile: __dirname + "/../../Viewer/tests/validation/karma.conf.js",
         singleRun: false
@@ -1142,13 +1198,13 @@ gulp.task("tests-viewer-validation-karma", ["tests-viewer-validation-transpile"]
 
     var server = new karmaServer(kamaServerOptions, done);
     server.start();
-});
+}));
 
 /**
  * Launches the KARMA validation tests in ff or virtual screen ff on travis for a quick analysis during the build.
  * (Can only be launch on any branches.)
  */
-gulp.task("tests-viewer-validation-virtualscreen", ["tests-viewer-validation-transpile"], function (done) {
+gulp.task("tests-viewer-validation-virtualscreen", gulp.series("tests-viewer-validation-transpile", function (done) {
     var kamaServerOptions = {
         configFile: __dirname + "/../../Viewer/tests/validation/karma.conf.js",
         singleRun: true,
@@ -1157,13 +1213,13 @@ gulp.task("tests-viewer-validation-virtualscreen", ["tests-viewer-validation-tra
 
     var server = new karmaServer(kamaServerOptions, done);
     server.start();
-});
+}));
 
 /**
  * Launches the KARMA validation tests in browser stack for remote and cross devices validation tests.
  * (Can only be launch from secure branches.)
  */
-gulp.task("tests-viewer-validation-browserstack", ["tests-viewer-validation-transpile"], function (done) {
+gulp.task("tests-viewer-validation-browserstack", gulp.series("tests-viewer-validation-transpile", function (done) {
     if (!process.env.BROWSER_STACK_USERNAME) {
         done();
         return;
@@ -1176,32 +1232,12 @@ gulp.task("tests-viewer-validation-browserstack", ["tests-viewer-validation-tran
 
     var server = new karmaServer(kamaServerOptions, done);
     server.start();
-});
-
+}));
 
 /**
  * Transpiles viewer typescript unit tests. 
  */
-gulp.task("tests-viewer-validation-transpile", function (done) {
-
-    let wpBuild = webpackStream(require('../../Viewer/webpack.gulp.config.js'), webpack);
-
-    // clean the built directory
-    rmDir("../../Viewer/tests/build/");
-
-    return wpBuild
-        .pipe(rename(function (path) {
-            if (path.extname === '.js') {
-                path.basename = "test";
-            }
-        }))
-        .pipe(gulp.dest("../../Viewer/tests/build/"));
-});
-
-/**
- * Transpiles viewer typescript unit tests. 
- */
-gulp.task("tests-viewer-transpile", function (done) {
+gulp.task("tests-viewer-transpile", function () {
 
     let wpBuild = webpackStream(require('../../Viewer/tests/unit/webpack.config.js'), webpack);
 
@@ -1221,7 +1257,7 @@ gulp.task("tests-viewer-transpile", function (done) {
  * Launches the KARMA unit tests in chrome.
  * (Can be launch on any branches.)
  */
-gulp.task("tests-viewer-unit-debug", ["tests-viewer-transpile"], function (done) {
+gulp.task("tests-viewer-unit-debug", gulp.series("tests-viewer-transpile", function (done) {
     var kamaServerOptions = {
         configFile: __dirname + "/../../Viewer/tests/karma.conf.js",
         singleRun: false,
@@ -1230,13 +1266,13 @@ gulp.task("tests-viewer-unit-debug", ["tests-viewer-transpile"], function (done)
 
     var server = new karmaServer(kamaServerOptions, done);
     server.start();
-});
+}));
 
 /**
  * Launches the KARMA unit tests in phantomJS.
  * (Can be launch on any branches.)
  */
-gulp.task("tests-viewer-unit", ["tests-viewer-transpile"], function (done) {
+gulp.task("tests-viewer-unit", gulp.series("tests-viewer-transpile", function (done) {
     var kamaServerOptions = {
         configFile: __dirname + "/../../Viewer/tests/karma.conf.js",
         singleRun: true
@@ -1244,6 +1280,98 @@ gulp.task("tests-viewer-unit", ["tests-viewer-transpile"], function (done) {
 
     var server = new karmaServer(kamaServerOptions, done);
     server.start();
+}));
+
+/**
+ * Launches the KARMA unit tests in phantomJS.
+ * (Can only be launch on any branches.)
+ */
+gulp.task("tests-unit", gulp.series("tests-babylon-unit", "tests-viewer-unit"));
+
+gulp.task("tests-modules", function () {
+    let testsToRun = require('../../tests/modules/tests.json');
+
+    let sequencePromise = Promise.resolve();
+
+    testsToRun.tests.forEach(test => {
+        sequencePromise = sequencePromise.then(() => {
+            console.log("Running " + test.name);
+            let basePath = '../../tests/modules/' + test.name + '/';
+            rmDir("../../tests/modules/build/");
+            let compilePromise = Promise.resolve();
+
+            if (test.dependencies) {
+                compilePromise = new Promise(function (resolve, reject) {
+                    let counter = 0;
+                    let copyTask = gulp.src(test.dependencies.map(dep => config.build.outputDirectory + '/' + dep)).pipe(rename(function (path) {
+                        path.basename = (counter++) + '';
+                    })).pipe(gulp.dest("../../tests/modules/build/dependencies/"))
+                    copyTask.once("finish", resolve);
+                })
+            }
+            // any compilation needed?
+            if (test.typescript || test.bundler) {
+                //typescript only
+                if (test.typescript && !test.bundler) {
+                    compilePromise = compilePromise.then(() => {
+                        return new Promise(function (resolve, reject) {
+                            var tsProject = typescript.createProject(basePath + (test.tsconfig || 'tsconfig.json'));
+
+                            var tsResult = gulp.src(basePath + '/src/**/*.ts', { base: basePath })
+                                .pipe(tsProject());
+
+                            let error = false;
+                            tsResult.once("error", function () {
+                                error = true;
+                            });
+
+                            let jsPipe = tsResult.js.pipe(gulp.dest("../../tests/modules/"));
+
+                            jsPipe.once("finish", function () {
+                                if (error)
+                                    reject('error compiling test');
+                                else
+                                    resolve();
+                            });
+                        });
+                    });
+                } else {
+                    if (test.bundler === 'webpack') {
+                        console.log("webpack");
+                        compilePromise = compilePromise.then(() => {
+                            return new Promise(function (resolve, reject) {
+                                let wpBuild = webpackStream(require(basePath + '/webpack.config.js'), webpack);
+
+                                wpBuild = wpBuild
+                                    .pipe(rename(function (path) {
+                                        if (path.extname === '.js') {
+                                            path.basename = "tests-loader";
+                                        }
+                                    }))
+                                    .pipe(gulp.dest("../../tests/modules/build/"));
+
+                                wpBuild.once("finish", resolve);
+                            })
+                        });
+                    }
+                }
+            }
+
+            return compilePromise.then(() => {
+                return new Promise(function (resolve, reject) {
+                    var kamaServerOptions = {
+                        configFile: __dirname + "/../../tests/modules/karma.conf.js",
+                        singleRun: true
+                    };
+
+                    var server = new karmaServer(kamaServerOptions, resolve);
+                    server.start();
+                });
+            })
+        })
+    });
+
+    return sequencePromise;
 });
 
 gulp.task("tests-whatsnew", function (done) {
@@ -1287,3 +1415,13 @@ gulp.task("tests-whatsnew", function (done) {
         });
     });
 });
+
+/**
+ * Do it all.
+ */
+gulp.task("typescript-all", gulp.series("typescript", "typescript-libraries", "netlify-cleanup"));
+
+/**
+ * The default task, concat and min the main BJS files.
+ */
+gulp.task("default", gulp.series("typescript-all", "intellisense", "typedoc-all", "tests-unit", "tests-validation-virtualscreen", "tests-validation-browserstack"));

+ 27 - 36
Tools/Gulp/package.json

@@ -10,37 +10,31 @@
     "license": "(Apache-2.0)",
     "devDependencies": {
         "@types/node": "^8.10.21",
-        "base64-font-loader": "0.0.4",
         "base64-image-loader": "^1.2.1",
         "chai": "^4.1.2",
         "color-support": "^1.1.3",
-        "css-loader": "^0.25.0",
+        "css-loader": "^1.0.0",
         "deepmerge": "^2.1.1",
-        "del": "2.2.2",
-        "es6-promise": "^4.2.4",
-        "exports-loader": "^0.6.4",
-        "gulp": "^3.9.1",
-        "gulp-changed-in-place": "2.0.3",
+        "del": "3.0.0",
+        "gulp": "^4.0.0",
         "gulp-clean-ts-extends": "~0.1.1",
-        "gulp-concat": "~2.5.2",
+        "gulp-concat": "~2.6.1",
         "gulp-content-to-variable": "^0.1.0",
-        "gulp-debug": "^3.2.0",
-        "gulp-expect-file": "^0.0.7",
-        "gulp-optimize-js": "^1.0.2",
-        "gulp-rename": "^1.2.3",
-        "gulp-replace": "~0.5.3",
-        "gulp-sass": "3.1.0",
-        "gulp-sourcemaps": "~1.9.1",
-        "gulp-typedoc": "^2.1.2",
-        "gulp-typescript": "^3.2.4",
-        "gulp-uglify": "^2.1.2",
-        "gulp-util": "~3.0.4",
+        "gulp-debug": "^4.0.0",
+        "gulp-expect-file": "^1.0.0",
+        "gulp-optimize-js": "^1.1.0",
+        "gulp-rename": "^1.4.0",
+        "gulp-replace": "~1.0.0",
+        "gulp-sass": "^4.0.1",
+        "gulp-sourcemaps": "~2.6.4",
+        "gulp-typedoc": "^2.2.0",
+        "gulp-typescript": "4.0.2",
+        "gulp-uglify": "^3.0.1",
         "gulp-webserver": "^0.9.1",
         "handlebars": "^4.0.11",
         "html-loader": "^0.5.5",
-        "imports-loader": "^0.7.1",
         "json-loader": "^0.5.7",
-        "karma": "^2.0.4",
+        "karma": "^2.0.5",
         "karma-browserstack-launcher": "^1.3.0",
         "karma-chai": "^0.1.0",
         "karma-chrome-launcher": "^2.2.0",
@@ -48,26 +42,23 @@
         "karma-mocha": "^1.3.0",
         "karma-phantomjs-launcher": "^1.0.4",
         "karma-sinon": "^1.0.5",
-        "merge2": "~0.3.5",
+        "merge2": "~1.2.2",
         "minimist": "^1.2.0",
-        "mocha": "^4.0.1",
-        "phantomjs": "^2.1.7",
-        "run-sequence": "~1.1.0",
-        "sinon": "^4.5.0",
-        "style-loader": "^0.13.2",
-        "through2": "~0.6.5",
-        "ts-loader": "^2.3.7",
-        "typedoc": "^0.9.0",
-        "typescript": "^2.8.4",
-        "webpack": "^4.16.1",
-        "webpack-stream": "^4.0.3"
+        "mocha": "^5.2.0",
+        "phantomjs-prebuilt": "^2.1.16",
+        "sinon": "^6.1.4",
+        "through2": "~2.0.3",
+        "ts-loader": "^4.4.2",
+        "typedoc": "^0.11.0",
+        "typescript": "^2.9.2",
+        "webpack": "^4.16.2",
+        "webpack-stream": "^5.0.0"
     },
     "scripts": {
         "install": "cd ../../gui && npm install && cd ../Tools/Gulp/ &&  cd ../../inspector && npm install && cd ../Tools/Gulp/ && npm --prefix ../../Playground/ install ../../Playground/ && npm --prefix ../../tests/unit/ install ../../tests/unit/ && npm --prefix ../../Viewer/tests/ install ../../Viewer/tests/ && cd ../../Viewer && npm install && cd ../Tools/Gulp/ && gulp deployLocalDev"
     },
     "dependencies": {
         "dts-bundle": "^0.7.3",
-        "gulp-clean": "^0.4.0",
-        "npm": "^5.10.0"
+        "gulp-clean": "^0.4.0"
     }
-}
+}

+ 1 - 0
dist/preview release/what's new.md

@@ -41,6 +41,7 @@
 - All NPM packages have `latest`and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
 - Added New Tools Tab in the inspector (env texture and screenshot tools so far) ([sebavan](http://www.github.com/sebavan))
 - Added `TextBlock.computeExpectedHeight`, added `TextWrapping.Ellipsis` as `TextBlock.wordWrapping` possible value ([adrientetar](https://github.com/adrientetar))
+- Moved to gulp 4, updated dependencies to latest ([RaananW](https://github.com/RaananW))
 
 ### Core Engine
 

+ 4 - 4
inspector/package.json

@@ -24,7 +24,7 @@
     },
     "homepage": "https://github.com/BabylonJS/Babylon.js#readme",
     "devDependencies": {
-        "@types/node": "^10.5.2",
+        "@types/node": "^10.5.3",
         "clean-webpack-plugin": "^0.1.19",
         "css-loader": "^1.0.0",
         "dts-bundle-webpack": "^1.0.0",
@@ -34,9 +34,9 @@
         "style-loader": "^0.21.0",
         "ts-loader": "^4.0.0",
         "typescript": "^2.9.2",
-        "webpack": "^4.16.0",
-        "webpack-cli": "^3.0.8",
-        "webpack-dev-server": "^3.1.4"
+        "webpack": "^4.16.2",
+        "webpack-cli": "^3.1.0",
+        "webpack-dev-server": "^3.1.5"
     },
     "peerDependencies": {
         "babylonjs": ">3.2.0",

+ 2 - 1
src/Cameras/babylon.targetCamera.ts

@@ -78,6 +78,7 @@
 
         /**
          * Restored camera state. You must call storeState() first
+         * @returns whether it was successful or not
          */
         public _restoreStateValues(): boolean {
             if (!super._restoreStateValues()) {
@@ -393,4 +394,4 @@
             return "TargetCamera";
         }
     }
-} 
+} 

+ 39 - 0
tests/modules/karma.conf.js

@@ -0,0 +1,39 @@
+module.exports = function (config) {
+    config.set({
+        basePath: '../../',
+        captureTimeout: 3e5,
+        browserNoActivityTimeout: 3e5,
+        browserDisconnectTimeout: 3e5,
+        browserDisconnectTolerance: 3,
+        concurrency: 1,
+
+        urlRoot: '/karma/',
+
+        frameworks: ['mocha', 'chai', 'sinon'],
+
+        files: [
+            './tests/modules/tests-karma.js',
+            // load the latest build
+            { pattern: './tests/modules/build/dependencies/**/*.js', watched: false, included: true, served: true },
+            './tests/modules/build/tests-loader.js',
+            { pattern: 'assets/**/*', watched: false, included: false, served: true },
+            { pattern: 'Playground/scenes/**/*', watched: false, included: false, served: true },
+            { pattern: 'Playground/textures/**/*', watched: false, included: false, served: true },
+            { pattern: 'Playground/sounds/**/*', watched: false, included: false, served: true }
+        ],
+        proxies: {
+            '/': '/base/'
+        },
+
+        port: 3000,
+        colors: true,
+        autoWatch: false,
+        singleRun: false,
+
+        // level of logging
+        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+        logLevel: config.LOG_INFO,
+
+        browsers: ['PhantomJS']
+    })
+}

+ 47 - 0
tests/modules/tests-karma.js

@@ -0,0 +1,47 @@
+
+
+function runTests(testType, BABYLON, GUI, INSPECTOR) {
+
+    console.log("running tests");
+
+    describe(testType + ' module tests', function () {
+
+        it("should have the dependencies loaded", function () {
+            assert.isDefined(BABYLON);
+            assert.isDefined(GUI);
+            assert.isDefined(INSPECTOR);
+            assert.isDefined(BABYLON.GLTF2);
+        })
+
+        var subject;
+
+        /**
+         * Create a nu engine subject before each test.
+         */
+        beforeEach(function () {
+            subject = new BABYLON.NullEngine({
+                renderHeight: 256,
+                renderWidth: 256,
+                textureSize: 256,
+                deterministicLockstep: false,
+                lockstepMaxSteps: 1
+            });
+        });
+        /**
+         * This test is more an integration test than a regular unit test but highlights how to rely
+         * on the BABYLON.NullEngine in order to create complex test cases.
+         */
+        describe('#GLTF', function () {
+            it('should load BoomBox GLTF', function (done) {
+                mocha.timeout(10000);
+                var scene = new BABYLON.Scene(subject);
+                BABYLON.SceneLoader.Append("/Playground/scenes/BoomBox/", "BoomBox.gltf", scene, function () {
+                    scene.meshes.length.should.be.equal(2);
+                    scene.materials.length.should.be.equal(1);
+                    scene.multiMaterials.length.should.be.equal(0);
+                    done();
+                });
+            });
+        });
+    });
+}

+ 4 - 0
tests/modules/tests-loader.js

@@ -0,0 +1,4 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+/// <reference path="../../../../dist/preview release/gui/babylon.gui.d.ts"/>
+// an error in typescript prevents us from using types instead of path
+runTests("typescript-vanilla", BABYLON, BABYLON.GUI, window.INSPECTOR);

+ 20 - 0
tests/modules/tests.json

@@ -0,0 +1,20 @@
+{
+    "tests": [
+        {
+            "name": "typescript-webpack",
+            "typescript": true,
+            "bundler": "webpack"
+        },
+        {
+            "name": "typescript-vanilla",
+            "typescript": true,
+            "tsconfig": "tsconfig.json",
+            "dependencies": [
+                "babylon.js",
+                "gui/babylon.gui.min.js",
+                "inspector/babylon.inspector.bundle.js",
+                "loaders/babylonjs.loaders.min.js"
+            ]
+        }
+    ]
+}

+ 8 - 0
tests/modules/typescript-vanilla/src/tests-loader.ts

@@ -0,0 +1,8 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+/// <reference path="../../../../dist/preview release/gui/babylon.gui.d.ts"/>
+// an error in typescript prevents us from using types instead of path
+
+
+declare function runTests(name: string, babylon: any, gui: any, inspector: any);
+
+runTests("typescript-vanilla", BABYLON, BABYLON.GUI, (<any>window).INSPECTOR);

+ 31 - 0
tests/modules/typescript-vanilla/tsconfig.json

@@ -0,0 +1,31 @@
+{
+    "compilerOptions": {
+        "target": "es5",
+        "module": "none",
+        "declaration": true,
+        "experimentalDecorators": true,
+        "emitDecoratorMetadata": true,
+        "strictNullChecks": true,
+        "noImplicitAny": false,
+        "noFallthroughCasesInSwitch": true,
+        "sourceMap": true,
+        "lib": [
+            "es5",
+            "dom",
+            "es2015.promise",
+            "es2015.collection",
+            "es2015.iterable"
+        ],
+        "baseUrl": "./src/",
+        "rootDir": "./src/",
+        "outDir": "../build/",
+        "paths": {
+            "babylonjs-gui": [
+                "../../../../dist/preview release/gui/babylon.gui.modules.d.ts"
+            ]
+        }
+    },
+    "exclude": [
+        "node_modules"
+    ]
+}

+ 12 - 0
tests/modules/typescript-webpack/index.ts

@@ -0,0 +1,12 @@
+import * as BABYLON from "babylonjs";
+import * as GUI from "babylonjs-gui";
+import * as INSPECTOR from "babylonjs-inspector";
+
+import "babylonjs-loaders";
+import "babylonjs-serializers";
+// an error in typescript prevents us from using types instead of path
+
+
+declare function runTests(name: string, babylon: any, gui: any, inspector: any);
+
+runTests("typescript-vanilla", BABYLON, GUI, INSPECTOR);

+ 41 - 0
tests/modules/typescript-webpack/tsconfig.json

@@ -0,0 +1,41 @@
+{
+    "compilerOptions": {
+        "target": "es5",
+        "module": "commonjs",
+        "noResolve": false,
+        "noImplicitAny": false,
+        "removeComments": true,
+        "preserveConstEnums": true,
+        "sourceMap": true,
+        "experimentalDecorators": true,
+        "isolatedModules": false,
+        "lib": [
+            "dom",
+            "es2015.promise",
+            "es5"
+        ],
+        "declaration": true,
+        "outDir": "./",
+        "baseUrl": "./",
+        "paths": {
+            "babylonjs": [
+                "../../../dist/preview release/babylon.d.ts"
+            ],
+            "babylonjs-gui": [
+                "../../../dist/preview release/gui/babylon.gui.module.d.ts"
+            ],
+            "babylonjs-inspector": [
+                "../../../dist/preview release/inspector/babylon.inspector.module.d.ts"
+            ],
+            "babylonjs-loaders": [
+                "../../../dist/preview release/loaders/babylonjs.loaders.module.d.ts"
+            ],
+            "babylonjs-gltf2interface": [
+                "../../../dist/babylon.glTF2Interface.d.ts"
+            ],
+        }
+    },
+    "exclude": [
+        "node_modules"
+    ]
+}

+ 26 - 0
tests/modules/typescript-webpack/webpack.config.js

@@ -0,0 +1,26 @@
+const path = require("path");
+
+module.exports = {
+    entry: __dirname + '/index.ts',
+    output: {
+        filename: 'bundle.js',
+        path: path.resolve(__dirname, 'dist')
+    },
+    resolve: {
+        extensions: ['.ts', '.js'],
+        alias: {
+            "babylonjs": __dirname + '/../../../dist/preview release/babylon.max.js',
+            "babylonjs-gui": __dirname + '/../../../dist/preview release/gui/babylon.gui.js',
+            "babylonjs-inspector": __dirname + '/../../../dist/preview release/inspector/babylon.inspector.js',
+            "babylonjs-loaders": __dirname + '/../../../dist/preview release/loaders/babylonjs.loaders.js',
+            "babylonjs-serializers": __dirname + '/../../../dist/preview release/serializers/babylonjs.serializers.js',
+        }
+    },
+    devtool: "source-map",
+    module: {
+        rules: [
+            { test: /\.tsx?$/, loader: "ts-loader" },
+        ]
+    },
+    mode: "development"
+};