From a2477d9a6081e3540ac534f91fce5b25ffe61f7a Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 20 Oct 2016 11:48:37 +0200 Subject: [PATCH] Move /build/gulpfile.common to /build/lib/optimize.ts --- build/gulpfile.editor.js | 2 +- build/gulpfile.vscode.js | 2 +- build/lib/optimize.js | 233 ++++++++++++++++++ build/{gulpfile.common.js => lib/optimize.ts} | 22 +- 4 files changed, 247 insertions(+), 12 deletions(-) create mode 100644 build/lib/optimize.js rename build/{gulpfile.common.js => lib/optimize.ts} (94%) diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index fad226a6ee5..7db3921bb5c 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -6,7 +6,7 @@ var gulp = require('gulp'); var path = require('path'); var util = require('./lib/util'); -var common = require('./gulpfile.common'); +var common = require('./lib/optimize'); var es = require('event-stream'); var File = require('vinyl'); diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 5d121698199..fb4884b7f4b 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -21,7 +21,7 @@ const _ = require('underscore'); const util = require('./lib/util'); const ext = require('./lib/extensions'); const buildfile = require('../src/buildfile'); -const common = require('./gulpfile.common'); +const common = require('./lib/optimize'); const nlsDev = require('vscode-nls-dev'); const root = path.dirname(__dirname); const commit = util.getVersion(root); diff --git a/build/lib/optimize.js b/build/lib/optimize.js new file mode 100644 index 00000000000..d3c338f0bf1 --- /dev/null +++ b/build/lib/optimize.js @@ -0,0 +1,233 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; +var path = require('path'); +var gulp = require('gulp'); +var sourcemaps = require('gulp-sourcemaps'); +var filter = require('gulp-filter'); +var minifyCSS = require('gulp-cssnano'); +var uglify = require('gulp-uglify'); +var es = require('event-stream'); +var concat = require('gulp-concat'); +var VinylFile = require('vinyl'); +var bundle = require('./bundle'); +var util = require('./util'); +var i18n = require('./i18n'); +var gulpUtil = require('gulp-util'); +var flatmap = require('gulp-flatmap'); +var pump = require('pump'); +var REPO_ROOT_PATH = path.join(__dirname, '../..'); +function log(prefix, message) { + gulpUtil.log(gulpUtil.colors.cyan('[' + prefix + ']'), message); +} +exports.loaderConfig = function (emptyPaths) { + var result = { + paths: { + 'vs': 'out-build/vs', + 'vscode': 'empty:' + }, + nodeModules: emptyPaths || [] + }; + result['vs/css'] = { inlineResources: true }; + return result; +}; +var IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i; +function loader(bundledFileHeader, bundleLoader) { + var sources = [ + 'out-build/vs/loader.js' + ]; + if (bundleLoader) { + sources = sources.concat([ + 'out-build/vs/css.js', + 'out-build/vs/nls.js' + ]); + } + var isFirst = true; + return (gulp + .src(sources, { base: 'out-build' }) + .pipe(es.through(function (data) { + if (isFirst) { + isFirst = false; + this.emit('data', new VinylFile({ + path: 'fake', + base: '', + contents: new Buffer(bundledFileHeader) + })); + this.emit('data', data); + } + else { + this.emit('data', data); + } + })) + .pipe(util.loadSourcemaps()) + .pipe(concat('vs/loader.js')) + .pipe(es.mapSync(function (f) { + f.sourceMap.sourceRoot = util.toFileUri(path.join(REPO_ROOT_PATH, 'src')); + return f; + }))); +} +function toConcatStream(bundledFileHeader, sources, dest) { + var useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest); + // If a bundle ends up including in any of the sources our copyright, then + // insert a fake source at the beginning of each bundle with our copyright + var containsOurCopyright = false; + for (var i = 0, len = sources.length; i < len; i++) { + var fileContents = sources[i].contents; + if (IS_OUR_COPYRIGHT_REGEXP.test(fileContents)) { + containsOurCopyright = true; + break; + } + } + if (containsOurCopyright) { + sources.unshift({ + path: null, + contents: bundledFileHeader + }); + } + var treatedSources = sources.map(function (source) { + var root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : ''; + var base = source.path ? root + '/out-build' : ''; + return new VinylFile({ + path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake', + base: base, + contents: new Buffer(source.contents) + }); + }); + return es.readArray(treatedSources) + .pipe(useSourcemaps ? util.loadSourcemaps() : es.through()) + .pipe(concat(dest)); +} +function toBundleStream(bundledFileHeader, bundles) { + return es.merge(bundles.map(function (bundle) { + return toConcatStream(bundledFileHeader, bundle.sources, bundle.dest); + })); +} +/** + * opts: + * - entryPoints (for AMD files, will get bundled and get Copyright treatment) + * - otherSources (for non-AMD files that should get Copyright treatment) + * - resources (svg, etc.) + * - loaderConfig + * - bundleLoader (boolean - true by default - append css and nls to loader) + * - header (basically the Copyright treatment) + * - bundleInfo (boolean - emit bundleInfo.json file) + * - out (out folder name) + */ +exports.optimizeTask = function (opts) { + var entryPoints = opts.entryPoints; + var otherSources = opts.otherSources; + var resources = opts.resources; + var loaderConfig = opts.loaderConfig; + var bundledFileHeader = opts.header; + var bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); + var out = opts.out; + 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)); + } + toBundleStream(bundledFileHeader, result.files).pipe(bundlesStream); + // Remove css inlined resources + var filteredResources = resources.slice(); + result.cssInlinedResources.forEach(function (resource) { + if (process.env['VSCODE_BUILD_VERBOSE']) { + log('optimizer', 'excluding inlined: ' + resource); + } + filteredResources.push('!' + resource); + }); + gulp.src(filteredResources, { base: 'out-build' }).pipe(resourcesStream); + var bundleInfoArray = []; + if (opts.bundleInfo) { + bundleInfoArray.push(new VinylFile({ + path: 'bundleInfo.json', + base: '.', + contents: new Buffer(JSON.stringify(result.bundleData, null, '\t')) + })); + } + es.readArray(bundleInfoArray).pipe(bundleInfoStream); + }); + var otherSourcesStream = es.through(); + var otherSourcesStreamArr = []; + gulp.src(otherSources, { base: 'out-build' }) + .pipe(es.through(function (data) { + otherSourcesStreamArr.push(toConcatStream(bundledFileHeader, [data], data.relative)); + }, function () { + if (!otherSourcesStreamArr.length) { + setTimeout(function () { otherSourcesStream.emit('end'); }, 0); + } + else { + es.merge(otherSourcesStreamArr).pipe(otherSourcesStream); + } + })); + var result = es.merge(loader(bundledFileHeader, bundleLoader), bundlesStream, otherSourcesStream, resourcesStream, bundleInfoStream); + return result + .pipe(sourcemaps.write('./', { + sourceRoot: null, + addComment: true, + includeContent: true + })) + .pipe(i18n.processNlsFiles({ + fileHeader: bundledFileHeader + })) + .pipe(gulp.dest(out)); + }; +}; +/** + * Wrap around uglify and allow the preserveComments function + * to have a file "context" to include our copyright only once per file. + */ +function uglifyWithCopyrights() { + var preserveComments = function (f) { return function (node, comment) { + var text = comment.value; + var type = comment.type; + if (/@minifier_do_not_preserve/.test(text)) { + return false; + } + var isOurCopyright = IS_OUR_COPYRIGHT_REGEXP.test(text); + if (isOurCopyright) { + if (f.__hasOurCopyright) { + return false; + } + f.__hasOurCopyright = true; + return true; + } + if ('comment2' === type) { + // check for /*!. Note that text doesn't contain leading /* + return (text.length > 0 && text[0] === '!') || /@preserve|license|@cc_on|copyright/i.test(text); + } + else if ('comment1' === type) { + return /license|copyright/i.test(text); + } + return false; + }; }; + var input = es.through(); + var output = input + .pipe(flatmap(function (stream, f) { + return stream + .pipe(uglify({ preserveComments: preserveComments(f) })); + })); + return es.duplex(input, output); +} +exports.minifyTask = function (src, sourceMapBaseUrl) { + var sourceMappingURL = sourceMapBaseUrl && (function (f) { return (sourceMapBaseUrl + "/" + f.relative + ".map"); }); + return function (cb) { + var jsFilter = filter('**/*.js', { restore: true }); + var cssFilter = filter('**/*.css', { restore: true }); + pump(gulp.src([src + '/**', '!' + src + '/**/*.map']), jsFilter, sourcemaps.init({ loadMaps: true }), uglifyWithCopyrights(), jsFilter.restore, cssFilter, minifyCSS({ reduceIdents: false }), cssFilter.restore, sourcemaps.write('./', { + sourceMappingURL: sourceMappingURL, + sourceRoot: null, + includeContent: true, + addComment: true + }), gulp.dest(src + '-min'), function (err) { + if (err instanceof uglify.GulpUglifyError) { + console.error("Uglify error in '" + (err.cause && err.cause.filename) + "'"); + } + cb(err); + }); + }; +}; diff --git a/build/gulpfile.common.js b/build/lib/optimize.ts similarity index 94% rename from build/gulpfile.common.js rename to build/lib/optimize.ts index c1897763746..30310cfc82a 100644 --- a/build/gulpfile.common.js +++ b/build/lib/optimize.ts @@ -13,14 +13,16 @@ const minifyCSS = require('gulp-cssnano'); const uglify = require('gulp-uglify'); const es = require('event-stream'); const concat = require('gulp-concat'); -const File = require('vinyl'); -const bundle = require('./lib/bundle'); -const util = require('./lib/util'); -const i18n = require('./lib/i18n'); +const VinylFile = require('vinyl'); +const bundle = require('./bundle'); +const util = require('./util'); +const i18n = require('./i18n'); const gulpUtil = require('gulp-util'); const flatmap = require('gulp-flatmap'); const pump = require('pump'); +const REPO_ROOT_PATH = path.join(__dirname, '../..'); + function log(prefix, message) { gulpUtil.log(gulpUtil.colors.cyan('[' + prefix + ']'), message); } @@ -59,7 +61,7 @@ function loader(bundledFileHeader, bundleLoader) { .pipe(es.through(function(data) { if (isFirst) { isFirst = false; - this.emit('data', new File({ + this.emit('data', new VinylFile({ path: 'fake', base: '', contents: new Buffer(bundledFileHeader) @@ -72,7 +74,7 @@ function loader(bundledFileHeader, bundleLoader) { .pipe(util.loadSourcemaps()) .pipe(concat('vs/loader.js')) .pipe(es.mapSync(function (f) { - f.sourceMap.sourceRoot = util.toFileUri(path.join(path.dirname(__dirname), 'src')); + f.sourceMap.sourceRoot = util.toFileUri(path.join(REPO_ROOT_PATH, 'src')); return f; })) ); @@ -100,10 +102,10 @@ function toConcatStream(bundledFileHeader, sources, dest) { } const treatedSources = sources.map(function(source) { - const root = source.path ? path.dirname(__dirname).replace(/\\/g, '/') : ''; + const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : ''; const base = source.path ? root + '/out-build' : ''; - return new File({ + return new VinylFile({ path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake', base: base, contents: new Buffer(source.contents) @@ -163,7 +165,7 @@ exports.optimizeTask = function(opts) { const bundleInfoArray = []; if (opts.bundleInfo) { - bundleInfoArray.push(new File({ + bundleInfoArray.push(new VinylFile({ path: 'bundleInfo.json', base: '.', contents: new Buffer(JSON.stringify(result.bundleData, null, '\t')) @@ -280,4 +282,4 @@ exports.minifyTask = function (src, sourceMapBaseUrl) { cb(err); }); }; -}; \ No newline at end of file +}; -- GitLab