gulpfile.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. // Gulp Tools
  2. var gulp = require("gulp");
  3. var uglify = require("gulp-uglify");
  4. var typescript = require("gulp-typescript");
  5. var sourcemaps = require("gulp-sourcemaps");
  6. var srcToVariable = require("gulp-content-to-variable");
  7. var merge2 = require("merge2");
  8. var concat = require("gulp-concat");
  9. var rename = require("gulp-rename");
  10. var cleants = require("gulp-clean-ts-extends");
  11. var replace = require("gulp-replace");
  12. var expect = require("gulp-expect-file");
  13. var optimisejs = require("gulp-optimize-js");
  14. var filter = require('gulp-filter');
  15. var path = require("path");
  16. var webpack = require('webpack');
  17. var webpackStream = require("webpack-stream");
  18. var fs = require("fs");
  19. var dtsBundle = require('dts-bundle');
  20. var through = require('through2');
  21. // Gulp Helpers
  22. var addDtsExport = require("./helpers/gulp-addDtsExport");
  23. var addDecorateAndExtends = require("./helpers/gulp-decorateAndExtends");
  24. var addModuleExports = require("./helpers/gulp-addModuleExports");
  25. var addES6Exports = require("./helpers/gulp-addES6Exports");
  26. var uncommentShader = require("./helpers/gulp-removeShaderComments");
  27. var processDeclaration = require('./helpers/gulp-processTypescriptDeclaration');
  28. var rmDir = require("./helpers/gulp-rmDir");
  29. // Import Gulp Tasks
  30. require("./tasks/gulpTasks-tsLint");
  31. require("./tasks/gulpTasks-netlify");
  32. require("./tasks/gulpTasks-whatsNew");
  33. require("./tasks/gulpTasks-localRun");
  34. require("./tasks/gulpTasks-watch");
  35. require("./tasks/gulpTasks-typedoc");
  36. require("./tasks/gulpTasks-intellisense");
  37. require("./tasks/gulpTasks-tests");
  38. // Import Build Config
  39. var config = require("./config.json");
  40. var includeShadersStream;
  41. var shadersStream;
  42. var workersStream;
  43. var extendsSearchRegex = /var\s__extends[\s\S]+?\}\)\(\);/g;
  44. var decorateSearchRegex = /var\s__decorate[\s\S]+?\};/g;
  45. /**
  46. * TS configurations shared in the gulp file.
  47. */
  48. var tsConfig = {
  49. noResolve: true,
  50. target: "ES5",
  51. declarationFiles: true,
  52. typescript: require("typescript"),
  53. experimentalDecorators: true,
  54. isolatedModules: false,
  55. noImplicitAny: true,
  56. noImplicitReturns: true,
  57. noImplicitThis: true,
  58. noUnusedLocals: true,
  59. strictNullChecks: true,
  60. strictFunctionTypes: true,
  61. types: [],
  62. lib: [
  63. "dom",
  64. "es2015.promise",
  65. "es5"
  66. ]
  67. };
  68. var tsProject = typescript.createProject(tsConfig);
  69. function processDependency(kind, dependency, filesToLoad, firstLevelOnly) {
  70. if (!firstLevelOnly && dependency.dependUpon) {
  71. for (var i = 0; i < dependency.dependUpon.length; i++) {
  72. var dependencyName = dependency.dependUpon[i];
  73. var parent = config.workloads[dependencyName];
  74. processDependency(kind, parent, filesToLoad);
  75. }
  76. }
  77. var content = dependency[kind];
  78. if (!content) {
  79. return;
  80. }
  81. for (var i = 0; i < content.length; i++) {
  82. var file = content[i];
  83. if (filesToLoad.indexOf(file) === -1) {
  84. filesToLoad.push(file);
  85. }
  86. }
  87. }
  88. function determineFilesToProcess(kind) {
  89. var currentConfig = config.build.currentConfig;
  90. var buildConfiguration = config.buildConfigurations[currentConfig];
  91. var filesToLoad = [];
  92. for (var index = 0; index < buildConfiguration.length; index++) {
  93. var dependencyName = buildConfiguration[index];
  94. var dependency = config.workloads[dependencyName];
  95. if (kind === "directFiles" && !dependency) {
  96. filesToLoad.push("../../dist/preview release/" + dependencyName);
  97. }
  98. else if (dependency) {
  99. processDependency(kind, dependency, filesToLoad);
  100. }
  101. }
  102. if (kind === "shaderIncludes") {
  103. for (var index = 0; index < filesToLoad.length; index++) {
  104. filesToLoad[index] = "../../src/Shaders/ShadersInclude/" + filesToLoad[index] + ".fx";
  105. }
  106. } else if (kind === "shaders") {
  107. for (var index = 0; index < filesToLoad.length; index++) {
  108. var name = filesToLoad[index];
  109. filesToLoad[index] = "../../src/Shaders/" + filesToLoad[index] + ".fx";
  110. }
  111. }
  112. return filesToLoad;
  113. }
  114. /*
  115. * Shader Management.
  116. */
  117. function shadersName(filename) {
  118. return path.basename(filename)
  119. .replace(".fragment", "Pixel")
  120. .replace(".vertex", "Vertex")
  121. .replace(".fx", "Shader");
  122. }
  123. function includeShadersName(filename) {
  124. return path.basename(filename).replace(".fx", "");
  125. }
  126. /*
  127. * Main necessary files stream Management.
  128. */
  129. gulp.task("includeShaders", function(cb) {
  130. var filesToProcess = determineFilesToProcess("shaderIncludes");
  131. includeShadersStream = gulp.src(filesToProcess).
  132. pipe(expect.real({ errorOnFailure: true }, filesToProcess)).
  133. pipe(uncommentShader()).
  134. pipe(srcToVariable({
  135. variableName: "BABYLON.Effect.IncludesShadersStore", asMap: true, namingCallback: includeShadersName
  136. }));
  137. cb();
  138. });
  139. gulp.task("shaders", gulp.series("includeShaders", function(cb) {
  140. var filesToProcess = determineFilesToProcess("shaders");
  141. shadersStream = gulp.src(filesToProcess).
  142. pipe(expect.real({ errorOnFailure: true }, filesToProcess)).
  143. pipe(uncommentShader()).
  144. pipe(srcToVariable({
  145. variableName: "BABYLON.Effect.ShadersStore", asMap: true, namingCallback: shadersName
  146. }));
  147. cb();
  148. }));
  149. gulp.task("workers", function(cb) {
  150. workersStream = config.workers.map(function(workerDef) {
  151. return gulp.src(workerDef.files).
  152. pipe(expect.real({ errorOnFailure: true }, workerDef.files)).
  153. pipe(uglify()).
  154. pipe(srcToVariable({
  155. variableName: workerDef.variable
  156. }));
  157. });
  158. cb();
  159. });
  160. /**
  161. * Build tasks to concat minify uflify optimise the BJS js in different flavor (workers...).
  162. */
  163. gulp.task("buildWorker", gulp.series(gulp.parallel("workers", "shaders"), function() {
  164. var filesToProcess = determineFilesToProcess("files");
  165. return merge2(
  166. gulp.src(filesToProcess).
  167. pipe(expect.real({ errorOnFailure: true }, filesToProcess)),
  168. shadersStream,
  169. includeShadersStream,
  170. workersStream
  171. )
  172. .pipe(concat(config.build.minWorkerFilename))
  173. .pipe(cleants())
  174. .pipe(replace(extendsSearchRegex, ""))
  175. .pipe(replace(decorateSearchRegex, ""))
  176. .pipe(addDecorateAndExtends())
  177. .pipe(addModuleExports("BABYLON", {
  178. dependencies: config.build.dependencies
  179. }))
  180. .pipe(uglify())
  181. .pipe(optimisejs())
  182. .pipe(gulp.dest(config.build.outputDirectory));
  183. }));
  184. gulp.task("build", gulp.series("shaders", function build() {
  185. var filesToProcess = determineFilesToProcess("files");
  186. var directFilesToProcess = determineFilesToProcess("directFiles");
  187. let mergedStreams = merge2(gulp.src(filesToProcess)
  188. .pipe(expect.real({ errorOnFailure: true }, filesToProcess)),
  189. shadersStream,
  190. includeShadersStream);
  191. if (directFilesToProcess.length) {
  192. mergedStreams.add(gulp.src(directFilesToProcess));
  193. }
  194. return merge2(
  195. mergedStreams
  196. .pipe(concat(config.build.noModuleFilename))
  197. .pipe(cleants())
  198. .pipe(replace(extendsSearchRegex, ""))
  199. .pipe(replace(decorateSearchRegex, ""))
  200. .pipe(addDecorateAndExtends())
  201. .pipe(gulp.dest(config.build.outputDirectory))
  202. .pipe(rename(config.build.filename))
  203. .pipe(addModuleExports("BABYLON", {
  204. dependencies: config.build.dependencies
  205. }))
  206. .pipe(gulp.dest(config.build.outputDirectory))
  207. .pipe(rename(config.build.minFilename))
  208. .pipe(uglify())
  209. .pipe(optimisejs())
  210. .pipe(gulp.dest(config.build.outputDirectory)),
  211. mergedStreams
  212. .pipe(concat("es6.js"))
  213. .pipe(cleants())
  214. .pipe(replace(extendsSearchRegex, ""))
  215. .pipe(replace(decorateSearchRegex, ""))
  216. .pipe(addES6Exports("BABYLON"))
  217. .pipe(gulp.dest(config.build.outputDirectory))
  218. );
  219. }));
  220. /*
  221. * Compiles all typescript files and creating a js and a declaration file.
  222. */
  223. gulp.task("typescript-compile", function() {
  224. const dtsFilter = filter(['**', '!**/*.d.ts'], {restore: false});
  225. var tsResult = gulp.src(config.typescript)
  226. .pipe(dtsFilter)
  227. .pipe(sourcemaps.init())
  228. .pipe(tsProject({
  229. summarizeFailureOutput: true
  230. }));
  231. //If this gulp task is running on travis, file the build!
  232. if (process.env.TRAVIS) {
  233. tsResult.once("error", function() {
  234. tsResult.once("finish", function() {
  235. console.log("Typescript compile failed");
  236. process.exit(1);
  237. });
  238. });
  239. }
  240. return merge2([
  241. tsResult.dts
  242. .pipe(concat(config.build.declarationFilename))
  243. .pipe(addDtsExport("BABYLON", "babylonjs"))
  244. .pipe(gulp.dest(config.build.outputDirectory)),
  245. tsResult.js
  246. .pipe(sourcemaps.write("./",
  247. {
  248. includeContent: false,
  249. sourceRoot: (filePath) => {
  250. return "";
  251. }
  252. }))
  253. .pipe(gulp.dest(config.build.srcOutputDirectory))
  254. ])
  255. });
  256. /**
  257. * Build the releasable files.
  258. */
  259. gulp.task("typescript", gulp.series("typescript-compile", "buildWorker", "build"));
  260. var buildExternalLibrary = function(library, settings) {
  261. var outputDirectory = config.build.outputDirectory + settings.build.distOutputDirectory;
  262. if (!library.webpack) {
  263. throw "Missing Webpack configuration in " + library;
  264. }
  265. const sequence = [];
  266. if (settings.build.outputs) {
  267. settings.build.outputs.forEach(out => {
  268. let wpConfig = require(library.webpack);
  269. if (!out.minified) {
  270. wpConfig.mode = "development";
  271. }
  272. let wpBuild = webpackStream(wpConfig, require("webpack"));
  273. //shoud dtsBundle create the declaration?
  274. if (settings.build.dtsBundle) {
  275. let event = wpBuild
  276. .pipe(through.obj(function(file, enc, cb) {
  277. // only declaration files
  278. const isdts = /\.d\.ts$/.test(file.path);
  279. if (isdts) this.push(file);
  280. cb();
  281. }))
  282. .pipe(gulp.dest(outputDirectory));
  283. // dts-bundle does NOT support (gulp) streams, so files have to be saved and reloaded,
  284. // until I fix it
  285. event.on("end", function() {
  286. // create the file
  287. dtsBundle.bundle(settings.build.dtsBundle);
  288. // prepend the needed reference
  289. let fileLocation = path.join(path.dirname(settings.build.dtsBundle.main), settings.build.dtsBundle.out);
  290. fs.readFile(fileLocation, function(err, data) {
  291. if (err) throw err;
  292. data = (settings.build.dtsBundle.prependText || "") + '\n' + data.toString();
  293. fs.writeFileSync(fileLocation, data);
  294. if (settings.build.processDeclaration) {
  295. var newData = processDeclaration(data, settings.build.processDeclaration);
  296. fs.writeFileSync(fileLocation.replace('.module', ''), newData);
  297. }
  298. });
  299. });
  300. }
  301. let build = wpBuild
  302. .pipe(through.obj(function(file, enc, cb) {
  303. // only pipe js files
  304. const isJs = /\.js$/.test(file.path);
  305. if (isJs) this.push(file);
  306. cb();
  307. }))
  308. .pipe(addModuleExports(library.moduleDeclaration, { subModule: false, extendsRoot: false, externalUsingBabylon: true, noBabylonInit: library.babylonIncluded }));
  309. function processDestination(dest) {
  310. var outputDirectory = config.build.outputDirectory + dest.outputDirectory;
  311. build = build
  312. .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
  313. .pipe(gulp.dest(outputDirectory));
  314. if (library.babylonIncluded && dest.addBabylonDeclaration) {
  315. // include the babylon declaration
  316. if (dest.addBabylonDeclaration === true) {
  317. dest.addBabylonDeclaration = [config.build.declarationFilename];
  318. }
  319. var decsToAdd = dest.addBabylonDeclaration.map(function(dec) {
  320. return config.build.outputDirectory + '/' + dec;
  321. });
  322. sequence.unshift(gulp.src(decsToAdd)
  323. .pipe(rename(function(path) {
  324. path.dirname = '';
  325. }))
  326. .pipe(gulp.dest(outputDirectory)))
  327. }
  328. }
  329. out.destinations.forEach(dest => {
  330. processDestination(dest);
  331. });
  332. sequence.push(build);
  333. });
  334. } else {
  335. var wpConfig;
  336. if (library.entry) {
  337. wpConfig = require(settings.build.webpack);
  338. wpConfig.entry = {
  339. 'main': path.resolve(wpConfig.context, library.entry),
  340. };
  341. wpConfig.output.filename = library.output;
  342. }
  343. else {
  344. wpConfig = require(library.webpack);
  345. }
  346. let wpBuildMin = webpackStream(wpConfig, webpack);
  347. let buildEventMin = wpBuildMin.pipe(gulp.dest(outputDirectory));
  348. sequence.push(buildEventMin);
  349. // Generate unminified
  350. wpConfig.mode = "development";
  351. wpConfig.output.filename = wpConfig.output.filename.replace(".min", "");
  352. let wpBuildMax = webpackStream(wpConfig, webpack);
  353. let buildEventMax = wpBuildMax.pipe(gulp.dest(outputDirectory));
  354. sequence.push(buildEventMax);
  355. if (library.isMain) {
  356. if (settings.build.dtsBundle || settings.build.processDeclaration) {
  357. buildEventMin.on("end", function() {
  358. if (settings.build.dtsBundle) {
  359. dtsBundle.bundle(settings.build.dtsBundle);
  360. }
  361. if (settings.build.processDeclaration) {
  362. let fileLocation = path.join(outputDirectory, settings.build.processDeclaration.filename);
  363. fs.readFile(fileLocation, function(err, data) {
  364. if (err) throw err;
  365. // For Raanan, litteral import hack TO BETTER INTEGRATE
  366. data = data + "";
  367. data = data.replace('import "../sass/main.scss";', "");
  368. var newData = processDeclaration(data, settings.build.processDeclaration);
  369. fs.writeFileSync(fileLocation.replace('.module', ''), newData);
  370. //legacy module support
  371. fs.writeFileSync(fileLocation, data + "\n" + newData);
  372. });
  373. }
  374. });
  375. }
  376. }
  377. }
  378. return merge2(sequence);
  379. }
  380. /**
  381. * Dynamic module creation In Serie for WebPack leaks.
  382. */
  383. function buildExternalLibraries(settings) {
  384. var tasks = settings.libraries.map(function(library) {
  385. var build = function(cb) {
  386. return buildExternalLibrary(library, settings);
  387. }
  388. return build;
  389. });
  390. return gulp.series.apply(this, tasks);
  391. }
  392. /**
  393. * Dynamic module creation.
  394. */
  395. config.modules.map(function(module) {
  396. var settings = config[module];
  397. // Clean up old build files.
  398. rmDir(settings.build.dtsBundle.baseDir);
  399. // Build the libraries.
  400. gulp.task(module, buildExternalLibraries(settings));
  401. });
  402. /**
  403. * Build all libs.
  404. */
  405. gulp.task("typescript-libraries", gulp.series(config.modules));
  406. /**
  407. * Custom build with full path file control; used by profile.html
  408. */
  409. gulp.task("build-custom", gulp.series("typescript-compile", "build"));
  410. /**
  411. * Validate compile the code and check the comments and style case convention through typedoc
  412. */
  413. gulp.task("typedoc-check", gulp.series("typescript-compile", "gui", "loaders", "serializers", "typedoc-generate", "typedoc-validate"));
  414. /**
  415. * Combine Webserver and Watch as long as vscode does not handle multi tasks.
  416. */
  417. gulp.task("run", gulp.series("watch", "webserver"));
  418. /**
  419. * Do it all (Build).
  420. */
  421. gulp.task("typescript-all", gulp.series("typescript", "typescript-libraries", "netlify-cleanup"));
  422. /**
  423. * Do it all (tests).
  424. */
  425. gulp.task("tests-all", gulp.series("tests-unit", "tests-modules", "tests-validation-virtualscreen", "tests-validation-browserstack"));
  426. /**
  427. * The default task, concat and min the main BJS files.
  428. */
  429. gulp.task("default", gulp.series("tsLint", "typescript-all", "intellisense", "typedoc-all", "tests-all"));