gulpfile.js 16 KB

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