diff --git a/build/gulpfile.common.js b/build/gulpfile.common.js index 34bc3043e7c..f0b21202ce8 100644 --- a/build/gulpfile.common.js +++ b/build/gulpfile.common.js @@ -128,6 +128,7 @@ function toBundleStream(bundledFileHeader, bundles) { * - resources (svg, etc.) * - loaderConfig * - header (basically the Copyright treatment) + * - bundleInfo (boolean - emit bundleInfo.json file) * - out (out folder name) */ exports.optimizeTask = function(opts) { @@ -141,6 +142,7 @@ exports.optimizeTask = function(opts) { return function() { var bundlesStream = es.through(); // this stream will contain the bundled files var resourcesStream = es.through(); // this stream will contain the resources + var bundleInfoStream = es.through(); // this stream will contain bundleInfo.json bundle.bundle(entryPoints, loaderConfig, function(err, result) { if (err) { return bundlesStream.emit('error', JSON.stringify(err)); } @@ -155,6 +157,16 @@ exports.optimizeTask = function(opts) { filteredResources.push('!' + resource); }); gulp.src(filteredResources, { base: 'out-build' }).pipe(resourcesStream); + + var bundleInfoArray = []; + if (opts.bundleInfo) { + bundleInfoArray.push(new File({ + path: 'bundleInfo.json', + base: '.', + contents: new Buffer(JSON.stringify(result.bundleData, null, '\t')) + })); + } + es.readArray(bundleInfoArray).pipe(bundleInfoStream); }); var otherSourcesStream = es.through(); @@ -175,7 +187,8 @@ exports.optimizeTask = function(opts) { loader(bundledFileHeader), bundlesStream, otherSourcesStream, - resourcesStream + resourcesStream, + bundleInfoStream ); return result diff --git a/build/lib/bundle.js b/build/lib/bundle.js index dda8f22ad03..3ef7d8cbb26 100644 --- a/build/lib/bundle.js +++ b/build/lib/bundle.js @@ -23,11 +23,12 @@ function bundle(entryPoints, config, callback) { loader.config(config); loader(Object.keys(entryPointsMap), function () { var modules = loader.getBuildInfo(); - var resultFiles = emitEntryPoints(modules, entryPointsMap); + var partialResult = emitEntryPoints(modules, entryPointsMap); var cssInlinedResources = loader('vs/css').getInlinedResources(); callback(null, { - files: resultFiles, - cssInlinedResources: cssInlinedResources + files: partialResult.files, + cssInlinedResources: cssInlinedResources, + bundleData: partialResult.bundleData }); }, function (err) { return callback(err, null); }); } @@ -44,6 +45,10 @@ function emitEntryPoints(modules, entryPoints) { var sortedModules = topologicalSort(modulesGraph); var result = []; var usedPlugins = {}; + var bundleData = { + graph: modulesGraph, + bundles: {} + }; Object.keys(entryPoints).forEach(function (moduleToBundle) { var info = entryPoints[moduleToBundle]; var rootNodes = [moduleToBundle].concat(info.include || []); @@ -58,6 +63,7 @@ function emitEntryPoints(modules, entryPoints) { var includedModules = sortedModules.filter(function (module) { return allDependencies[module]; }); + bundleData.bundles[moduleToBundle] = includedModules; var res = emitEntryPoint(modulesMap, modulesGraph, moduleToBundle, includedModules); result = result.concat(res.files); for (var pluginName in res.usedPlugins) { @@ -79,7 +85,60 @@ function emitEntryPoints(modules, entryPoints) { plugin.finishBuild(write); } }); - return result; + return { + files: removeDuplicateTSBoilerplate(result), + bundleData: bundleData + }; +} +function removeDuplicateTSBoilerplate(destFiles) { + // Taken from typescript compiler => emitFiles + var BOILERPLATE = [ + { start: /^var __extends/, end: /^};$/ }, + { start: /^var __assign/, end: /^};$/ }, + { start: /^var __decorate/, end: /^};$/ }, + { start: /^var __metadata/, end: /^};$/ }, + { start: /^var __param/, end: /^};$/ }, + { start: /^var __awaiter/, end: /^};$/ }, + ]; + destFiles.forEach(function (destFile) { + var SEEN_BOILERPLATE = []; + destFile.sources.forEach(function (source) { + var lines = source.contents.split(/\r\n|\n|\r/); + var newLines = []; + var IS_REMOVING_BOILERPLATE = false, END_BOILERPLATE; + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + if (IS_REMOVING_BOILERPLATE) { + newLines.push(''); + if (END_BOILERPLATE.test(line)) { + IS_REMOVING_BOILERPLATE = false; + } + } + else { + for (var j = 0; j < BOILERPLATE.length; j++) { + var boilerplate = BOILERPLATE[j]; + if (boilerplate.start.test(line)) { + if (SEEN_BOILERPLATE[j]) { + IS_REMOVING_BOILERPLATE = true; + END_BOILERPLATE = boilerplate.end; + } + else { + SEEN_BOILERPLATE[j] = true; + } + } + } + if (IS_REMOVING_BOILERPLATE) { + newLines.push(''); + } + else { + newLines.push(line); + } + } + } + source.contents = newLines.join('\n'); + }); + }); + return destFiles; } function emitEntryPoint(modulesMap, deps, entryPoint, includedModules) { var mainResult = { diff --git a/build/lib/bundle.ts b/build/lib/bundle.ts index 4e5d767b151..bf5b02701ec 100644 --- a/build/lib/bundle.ts +++ b/build/lib/bundle.ts @@ -70,9 +70,20 @@ export interface IConcatFile { sources: IFile[]; } +export interface IBundleData { + graph: IGraph; + bundles: {[moduleId:string]:string[];}; +} + export interface IBundleResult { files: IConcatFile[]; cssInlinedResources: string[]; + bundleData: IBundleData; +} + +interface IPartialBundleResult { + files: IConcatFile[]; + bundleData: IBundleData; } export interface ILoaderConfig { @@ -100,16 +111,17 @@ export function bundle(entryPoints:IEntryPoint[], config:ILoaderConfig, callback loader(Object.keys(entryPointsMap), () => { let modules = loader.getBuildInfo(); - let resultFiles = emitEntryPoints(modules, entryPointsMap); + let partialResult = emitEntryPoints(modules, entryPointsMap); let cssInlinedResources = loader('vs/css').getInlinedResources(); callback(null, { - files: resultFiles, - cssInlinedResources: cssInlinedResources + files: partialResult.files, + cssInlinedResources: cssInlinedResources, + bundleData: partialResult.bundleData }); }, (err) => callback(err, null)); } -function emitEntryPoints(modules:IBuildModuleInfo[], entryPoints:IEntryPointMap): IConcatFile[] { +function emitEntryPoints(modules:IBuildModuleInfo[], entryPoints:IEntryPointMap): IPartialBundleResult { let modulesMap: IBuildModuleInfoMap = {}; modules.forEach((m:IBuildModuleInfo) => { modulesMap[m.id] = m; @@ -124,6 +136,10 @@ function emitEntryPoints(modules:IBuildModuleInfo[], entryPoints:IEntryPointMap) let result: IConcatFile[] = []; let usedPlugins: IPluginMap = {}; + let bundleData:IBundleData = { + graph: modulesGraph, + bundles: {} + }; Object.keys(entryPoints).forEach((moduleToBundle:string) => { let info = entryPoints[moduleToBundle]; @@ -142,6 +158,8 @@ function emitEntryPoints(modules:IBuildModuleInfo[], entryPoints:IEntryPointMap) return allDependencies[module]; }); + bundleData.bundles[moduleToBundle] = includedModules; + let res = emitEntryPoint(modulesMap, modulesGraph, moduleToBundle, includedModules); result = result.concat(res.files); @@ -166,7 +184,61 @@ function emitEntryPoints(modules:IBuildModuleInfo[], entryPoints:IEntryPointMap) } }); - return result; + return { + files: removeDuplicateTSBoilerplate(result), + bundleData: bundleData + }; +} + +function removeDuplicateTSBoilerplate(destFiles:IConcatFile[]):IConcatFile[] { + // Taken from typescript compiler => emitFiles + let BOILERPLATE = [ + { start: /^var __extends/, end: /^};$/ }, + { start: /^var __assign/, end: /^};$/ }, + { start: /^var __decorate/, end: /^};$/ }, + { start: /^var __metadata/, end: /^};$/ }, + { start: /^var __param/, end: /^};$/ }, + { start: /^var __awaiter/, end: /^};$/ }, + ]; + + destFiles.forEach((destFile) => { + let SEEN_BOILERPLATE = []; + destFile.sources.forEach((source) => { + let lines = source.contents.split(/\r\n|\n|\r/); + let newLines: string[] = []; + let IS_REMOVING_BOILERPLATE = false, END_BOILERPLATE: RegExp; + + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + if (IS_REMOVING_BOILERPLATE) { + newLines.push(''); + if (END_BOILERPLATE.test(line)) { + IS_REMOVING_BOILERPLATE = false; + } + } else { + for (let j = 0; j < BOILERPLATE.length; j++) { + let boilerplate = BOILERPLATE[j]; + if (boilerplate.start.test(line)) { + if (SEEN_BOILERPLATE[j]) { + IS_REMOVING_BOILERPLATE = true; + END_BOILERPLATE = boilerplate.end; + } else { + SEEN_BOILERPLATE[j] = true; + } + } + } + if (IS_REMOVING_BOILERPLATE) { + newLines.push(''); + } else { + newLines.push(line); + } + } + } + source.contents = newLines.join('\n'); + }); + }); + + return destFiles; } interface IPluginMap {