build.js 11.3 KB
Newer Older
B
bryk 已提交
1
// Copyright 2015 Google Inc. All Rights Reserved.
2 3 4 5 6
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
B
bryk 已提交
7
//     http://www.apache.org/licenses/LICENSE-2.0
8 9 10 11 12 13 14 15 16 17 18 19 20
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Gulp tasks for building the project.
 */
import del from 'del';
import gulp from 'gulp';
import gulpMinifyCss from 'gulp-minify-css';
B
bryk 已提交
21
import gulpHtmlmin from 'gulp-htmlmin';
22
import gulpUglify from 'gulp-uglify';
23
import gulpIf from 'gulp-if';
24
import gulpUseref from 'gulp-useref';
25 26
import GulpRevAll from 'gulp-rev-all';
import mergeStream from 'merge-stream';
27
import path from 'path';
28
import uglifySaveLicense from 'uglify-save-license';
29 30

import conf from './conf';
B
bryk 已提交
31
import {multiDest} from './multidest';
32

33
/**
B
bryk 已提交
34
 * Builds production package for current architecture and places it in the dist directory.
35
 */
36 37
gulp.task('build', ['backend:prod', 'build-frontend']);

B
bryk 已提交
38 39 40 41 42
/**
 * Builds production packages for all supported architecures and places them in the dist directory.
 */
gulp.task('build:cross', ['backend:prod:cross', 'build-frontend:cross']);

43 44 45
/**
 * Builds production version of the frontend application for the default architecture.
 */
46 47 48
gulp.task(
    'build-frontend', ['localize', 'locales-for-backend'], function() { return doRevision(); });

49 50 51
/**
 * Builds production version of the frontend application for all supported architectures.
 */
52 53 54 55 56
gulp.task('build-frontend:cross', ['localize:cross', 'locales-for-backend:cross'], function() {
  return doRevision();
});

/**
57
 * Localizes all pre-created frontend copies for the default arch, so that they are ready to serve.
58
 */
59 60
gulp.task('localize', ['frontend-copies'], function() {
  return localize([path.join(conf.paths.distPre, conf.arch.default, 'public')]);
61 62 63
});

/**
64 65
 * Localizes all pre-created frontend copies in all cross-arch directories, so that they are ready
 * to serve.
66
 */
67 68
gulp.task('localize:cross', ['frontend-copies:cross'], function() {
  return localize(conf.arch.list.map((arch) => path.join(conf.paths.distPre, arch, 'public')));
69 70 71 72 73 74 75
});

/**
 * Copies the locales configuration to the default arch directory.
 * This configuration file is then used by the backend to localize dashboard.
 */
gulp.task('locales-for-backend', ['clean-dist'], function() {
76
  return localesForBackend([conf.paths.dist]);
77 78 79 80 81 82 83
});

/**
 * Copies the locales configuration to each arch directory.
 * This configuration file is then used by the backend to localize dashboard.
 */
gulp.task('locales-for-backend:cross', ['clean-dist'], function() {
84
  return localesForBackend(conf.paths.distCross);
85 86
});

B
bryk 已提交
87
/**
88
 * Builds production version of the frontend application for the default architecture
89
 * (one copy per locale) and plcaes it under .tmp/dist , preparing it for localization and revision.
B
bryk 已提交
90
 */
91 92 93 94 95
gulp.task(
    'frontend-copies',
    ['fonts', 'icons', 'assets', 'dependency-images', 'index:prod', 'clean-dist'], function() {
      return createFrontendCopies([path.join(conf.paths.distPre, conf.arch.default, 'public')]);
    });
B
bryk 已提交
96 97

/**
98
 * Builds production versions of the frontend application for all architecures
99
 * (one copy per locale) and places them under .tmp, preparing them for localization and revision.
B
bryk 已提交
100
 */
101
gulp.task(
102
    'frontend-copies:cross',
103 104 105 106 107 108 109 110 111
    [
      'fonts:cross',
      'icons:cross',
      'assets:cross',
      'dependency-images:cross',
      'index:prod',
      'clean-dist',
    ],
    function() {
112
      return createFrontendCopies(
113 114
          conf.arch.list.map((arch) => path.join(conf.paths.distPre, arch, 'public')));
    });
B
bryk 已提交
115 116 117 118 119 120 121 122 123 124 125 126

/**
 * Copies assets to the dist directory for current architecture.
 */
gulp.task('assets', ['clean-dist'], function() { return assets([conf.paths.distPublic]); });

/**
 * Copies assets to the dist directory for all architectures.
 */
gulp.task(
    'assets:cross', ['clean-dist'], function() { return assets(conf.paths.distPublicCross); });

127 128 129
/**
 * Copies icons to the dist directory for current architecture.
 */
130
gulp.task('icons', ['clean-dist'], function() { return icons([conf.paths.distPublic]); });
131 132 133 134

/**
 * Copies icons to the dist directory for all architectures.
 */
135
gulp.task('icons:cross', ['clean-dist'], function() { return icons(conf.paths.distPublicCross); });
136 137 138 139

/**
 * Copies fonts to the dist directory for current architecture.
 */
140
gulp.task('fonts', ['clean-dist'], function() { return fonts([conf.paths.distPublic]); });
141 142 143 144

/**
 * Copies fonts to the dist directory for all architectures.
 */
145
gulp.task('fonts:cross', ['clean-dist'], function() { return fonts(conf.paths.distPublicCross); });
146

147 148 149 150 151 152 153 154 155 156 157 158 159 160
/**
 * Copies images from dependencies to the dist directory for current architecture.
 */
gulp.task('dependency-images', ['clean-dist'], function() {
  return dependencyImages([conf.paths.distPublic]);
});

/**
 * Copies images from dependencies to the dist directory for all architectures.
 */
gulp.task('dependency-images:cross', ['clean-dist'], function() {
  return dependencyImages(conf.paths.distPublicCross);
});

B
bryk 已提交
161 162 163 164 165 166 167 168 169 170
/**
 * Cleans all build artifacts.
 */
gulp.task('clean', ['clean-dist'], function() {
  return del([conf.paths.goWorkspace, conf.paths.tmp, conf.paths.coverage]);
});

/**
 * Cleans all build artifacts in the dist/ folder.
 */
171
gulp.task('clean-dist', function() { return del([conf.paths.distRoot, conf.paths.distPre]); });
B
bryk 已提交
172

173
/**
174 175
 * Builds production version of the frontend application and copies it to all
 * the specified outputDirs, creating one copy per (outputDir x locale) tuple.
176 177 178 179
 *
 * Following steps are done here:
 *  1. Vendor CSS and JS files are concatenated and minified.
 *  2. index.html is minified.
180 181
 *  3. Everything is saved in the .tmp/dist directory, ready to be localized and revisioned.
 *
182
 * @param {!Array<string>} outputDirs
B
bryk 已提交
183
 * @return {stream}
184
 */
185
function createFrontendCopies(outputDirs) {
186 187 188 189 190 191
  // create an output for each locale
  let localizedOutputDirs = outputDirs.reduce((localizedDirs, outputDir) => {
    return localizedDirs.concat(
        conf.translations.map((translation) => { return path.join(outputDir, translation.key); }));
  }, []);

B
bryk 已提交
192 193 194 195 196 197
  let searchPath = [
    // To resolve local paths.
    path.relative(conf.paths.base, conf.paths.prodTmp),
    // To resolve bower_components/... paths.
    path.relative(conf.paths.base, conf.paths.base),
  ];
198 199

  return gulp.src(path.join(conf.paths.prodTmp, '*.html'))
B
bryk 已提交
200
      .pipe(gulpUseref({searchPath: searchPath}))
201
      .pipe(gulpIf('**/vendor.css', gulpMinifyCss()))
202 203 204 205 206 207 208
      .pipe(gulpIf('**/vendor.js', gulpUglify({
                     preserveComments: uglifySaveLicense,
                     // Disable compression of unused vars. This speeds up minification a lot (like
                     // 10 times).
                     // See https://github.com/mishoo/UglifyJS2/issues/321
                     compress: {unused: false},
                   })))
209 210 211 212 213
      .pipe(gulpIf('*.html', gulpHtmlmin({
                     removeComments: true,
                     collapseWhitespace: true,
                     conservativeCollapse: true,
                   })))
214 215 216 217 218 219 220 221 222 223 224 225 226
      .pipe(multiDest(localizedOutputDirs));
}

/**
 * Creates revisions of all .js anc .css files at once (for production).
 * Replaces the occurances of those files in index.html with their new names.
 * index.html does not get renamed in the process.
 * The processed files are then moved to the dist directory.
 * @return {stream}
 */
function doRevision() {
  // Do not update references other than in index.html. Do not rev index.html itself.
  let revAll =
227
      new GulpRevAll({dontRenameFile: ['index.html'], dontSearchFile: [/^(?!.*index\.html$).*$/]});
228 229 230 231 232 233
  return gulp.src([path.join(conf.paths.distPre, '**'), '!**/assets/**/*'])
      .pipe(revAll.revision())
      .pipe(gulp.dest(conf.paths.distRoot));
}

/**
234 235
 * Copies the localized app.js files for each supported language in outputDir/<locale>/static
 * for each of the specified output dirs.
236
 * @param {!Array<string>} outputDirs - list of all arch directories
237
 * @return {stream}
238
 */
239 240
function localize(outputDirs) {
  let streams = conf.translations.map((translation) => {
241 242
    let localizedOutputDirs =
        outputDirs.map((outputDir) => { return path.join(outputDir, translation.key, 'static'); });
243 244
    return gulp.src(path.join(conf.paths.i18nProd, translation.key, '*.js'))
        .pipe(multiDest(localizedOutputDirs));
245
  });
246 247

  return mergeStream.apply(null, streams);
B
bryk 已提交
248
}
249 250

/**
251 252 253 254 255 256 257 258 259 260 261 262 263
 * Copies the locales configuration file at the base of each arch directory, next to
 * all of the localized subdirs. This file is meant to be used by the backend binary
 * to compare against and determine the right locale to serve at runtime.
 * @param {!Array<string>} outputDirs - list of all arch directories
 * @return {stream}
 */
function localesForBackend(outputDirs) {
  return gulp.src(path.join(conf.paths.base, 'i18n', '*.json')).pipe(multiDest(outputDirs));
}

/**
 * Copies the assets files to all dist directories per arch and locale.
 * @param {!Array<string>} outputDirs
B
bryk 已提交
264
 * @return {stream}
265
 */
B
bryk 已提交
266
function assets(outputDirs) {
267
  let localizedOutputDirs = createLocalizedOutputs(outputDirs);
268
  return gulp.src(path.join(conf.paths.assets, '/**/*'), {base: conf.paths.app})
269
      .pipe(multiDest(localizedOutputDirs));
B
bryk 已提交
270
}
271 272

/**
273 274
 * Copies the icons files to all dist directories per arch and locale.
 * @param {!Array<string>} outputDirs
275 276 277
 * @return {stream}
 */
function icons(outputDirs) {
278
  let localizedOutputDirs = createLocalizedOutputs(outputDirs, 'static');
B
bryk 已提交
279 280 281 282
  return gulp
      .src(
          path.join(conf.paths.materialIcons, '/**/*.+(woff2|woff|eot|ttf)'),
          {base: conf.paths.materialIcons})
283
      .pipe(multiDest(localizedOutputDirs));
284 285 286
}

/**
287 288
 * Copies the font files to all dist directories per arch and locale.
 * @param {!Array<string>} outputDirs
289 290 291
 * @return {stream}
 */
function fonts(outputDirs) {
292
  let localizedOutputDirs = createLocalizedOutputs(outputDirs, 'fonts');
B
bryk 已提交
293 294
  return gulp
      .src(path.join(conf.paths.robotoFonts, '/**/*.+(woff2)'), {base: conf.paths.robotoFonts})
295
      .pipe(multiDest(localizedOutputDirs));
296
}
297

298 299 300 301 302 303 304 305 306 307 308 309
/**
 * Copies the font files to all dist directories per arch and locale.
 * @param {!Array<string>} outputDirs
 * @return {stream}
 */
function dependencyImages(outputDirs) {
  let localizedOutputDirs = createLocalizedOutputs(outputDirs, 'static/img');
  return gulp
      .src(path.join(conf.paths.jsoneditorImages, '*.png'), {base: conf.paths.jsoneditorImages})
      .pipe(multiDest(localizedOutputDirs));
}

310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
/**
 * Returns one subdirectory path for each supported locale inside all of the specified
 * outputDirs. Optionally, a subdirectory structure can be passed to append after each locale path.
 * @param {!Array<string>} outputDirs
 * @param {undefined|string} opt_subdir - an optional sub directory inside each locale directory.
 * @return {!Array<string>} localized output directories
 */
function createLocalizedOutputs(outputDirs, opt_subdir) {
  return outputDirs.reduce((localizedDirs, outputDir) => {
    return localizedDirs.concat(conf.translations.map((translation) => {
      if (opt_subdir) {
        return path.join(outputDir, translation.key, opt_subdir);
      }
      return path.join(outputDir, translation.key);
    }));
  }, []);
}