build.js 10.1 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
gulp.task('frontend-copies', ['fonts', 'icons', 'assets', 'index:prod', 'clean-dist'], function() {
  return createFrontendCopies([path.join(conf.paths.distPre, conf.arch.default, 'public')]);
B
bryk 已提交
93 94 95
});

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

/**
 * 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); });

117 118 119
/**
 * Copies icons to the dist directory for current architecture.
 */
120
gulp.task('icons', ['clean-dist'], function() { return icons([conf.paths.distPublic]); });
121 122 123 124

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

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

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

B
bryk 已提交
137 138 139 140 141 142 143 144 145 146
/**
 * 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.
 */
147
gulp.task('clean-dist', function() { return del([conf.paths.distRoot, conf.paths.distPre]); });
B
bryk 已提交
148

149
/**
150 151
 * Builds production version of the frontend application and copies it to all
 * the specified outputDirs, creating one copy per (outputDir x locale) tuple.
152 153 154 155
 *
 * Following steps are done here:
 *  1. Vendor CSS and JS files are concatenated and minified.
 *  2. index.html is minified.
156 157
 *  3. Everything is saved in the .tmp/dist directory, ready to be localized and revisioned.
 *
158
 * @param {!Array<string>} outputDirs
B
bryk 已提交
159
 * @return {stream}
160
 */
161
function createFrontendCopies(outputDirs) {
162 163 164 165 166 167
  // 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 已提交
168 169 170 171 172 173
  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),
  ];
174 175

  return gulp.src(path.join(conf.paths.prodTmp, '*.html'))
B
bryk 已提交
176
      .pipe(gulpUseref({searchPath: searchPath}))
177 178 179 180 181 182 183
      .pipe(gulpIf('**/vendor.css', gulpMinifyCss()))
      .pipe(gulpIf('**/vendor.js', gulpUglify({preserveComments: uglifySaveLicense})))
      .pipe(gulpIf('*.html', gulpHtmlmin({
                     removeComments: true,
                     collapseWhitespace: true,
                     conservativeCollapse: true,
                   })))
184 185 186 187 188 189 190 191 192 193 194 195 196
      .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 =
197
      new GulpRevAll({dontRenameFile: ['index.html'], dontSearchFile: [/^(?!.*index\.html$).*$/]});
198 199 200 201 202 203
  return gulp.src([path.join(conf.paths.distPre, '**'), '!**/assets/**/*'])
      .pipe(revAll.revision())
      .pipe(gulp.dest(conf.paths.distRoot));
}

/**
204 205
 * Copies the localized app.js files for each supported language in outputDir/<locale>/static
 * for each of the specified output dirs.
206
 * @param {!Array<string>} outputDirs - list of all arch directories
207
 * @return {stream}
208
 */
209 210
function localize(outputDirs) {
  let streams = conf.translations.map((translation) => {
211 212
    let localizedOutputDirs =
        outputDirs.map((outputDir) => { return path.join(outputDir, translation.key, 'static'); });
213 214
    return gulp.src(path.join(conf.paths.i18nProd, translation.key, '*.js'))
        .pipe(multiDest(localizedOutputDirs));
215
  });
216 217

  return mergeStream.apply(null, streams);
B
bryk 已提交
218
}
219 220

/**
221 222 223 224 225 226 227 228 229 230 231 232 233
 * 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 已提交
234
 * @return {stream}
235
 */
B
bryk 已提交
236
function assets(outputDirs) {
237
  let localizedOutputDirs = createLocalizedOutputs(outputDirs);
238
  return gulp.src(path.join(conf.paths.assets, '/**/*'), {base: conf.paths.app})
239
      .pipe(multiDest(localizedOutputDirs));
B
bryk 已提交
240
}
241 242

/**
243 244
 * Copies the icons files to all dist directories per arch and locale.
 * @param {!Array<string>} outputDirs
245 246 247
 * @return {stream}
 */
function icons(outputDirs) {
248
  let localizedOutputDirs = createLocalizedOutputs(outputDirs, 'static');
B
bryk 已提交
249 250 251 252
  return gulp
      .src(
          path.join(conf.paths.materialIcons, '/**/*.+(woff2|woff|eot|ttf)'),
          {base: conf.paths.materialIcons})
253
      .pipe(multiDest(localizedOutputDirs));
254 255 256
}

/**
257 258
 * Copies the font files to all dist directories per arch and locale.
 * @param {!Array<string>} outputDirs
259 260 261
 * @return {stream}
 */
function fonts(outputDirs) {
262
  let localizedOutputDirs = createLocalizedOutputs(outputDirs, 'fonts');
B
bryk 已提交
263 264
  return gulp
      .src(path.join(conf.paths.robotoFonts, '/**/*.+(woff2)'), {base: conf.paths.robotoFonts})
265
      .pipe(multiDest(localizedOutputDirs));
266
}
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284

/**
 * 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);
    }));
  }, []);
}