@angular-devkit/build-angular
Version:
Angular Webpack Build Facade
158 lines (157 loc) • 6.99 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.BundleActionCache = void 0;
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const crypto_1 = require("crypto");
const fs = require("fs");
const copy_file_1 = require("./copy-file");
const environment_options_1 = require("./environment-options");
const cacache = require('cacache');
const packageVersion = require('../../package.json').version;
class BundleActionCache {
constructor(cachePath, integrityAlgorithm) {
this.cachePath = cachePath;
this.integrityAlgorithm = integrityAlgorithm;
}
static copyEntryContent(entry, dest) {
copy_file_1.copyFile(typeof entry === 'string' ? entry : entry.path, dest);
if (process.platform !== 'win32') {
// The cache writes entries as readonly and when using copyFile the permissions will also be copied.
// See: https://github.com/npm/cacache/blob/073fbe1a9f789ba42d9a41de7b8429c93cf61579/lib/util/move-file.js#L36
fs.chmodSync(dest, 0o644);
}
}
generateIntegrityValue(content) {
const algorithm = this.integrityAlgorithm || 'sha1';
const codeHash = crypto_1.createHash(algorithm)
.update(content)
.digest('base64');
return `${algorithm}-${codeHash}`;
}
generateBaseCacheKey(content) {
// Create base cache key with elements:
// * package version - different build-angular versions cause different final outputs
// * code length/hash - ensure cached version matches the same input code
const integrity = this.generateIntegrityValue(content);
let baseCacheKey = `${packageVersion}|${content.length}|${integrity}`;
if (!environment_options_1.allowMangle) {
baseCacheKey += '|MD';
}
return baseCacheKey;
}
generateCacheKeys(action) {
// Postfix added to sourcemap cache keys when vendor, hidden sourcemaps are present
// Allows non-destructive caching of both variants
const sourceMapVendorPostfix = action.sourceMaps && action.vendorSourceMaps ? '|vendor' : '';
// sourceMappingURL is added at the very end which causes the code to be the same when sourcemaps are enabled/disabled
// When using hiddenSourceMaps we can omit the postfix since sourceMappingURL will not be added.
// When having sourcemaps a hashed file and non hashed file can have the same content. But the sourceMappingURL will differ.
const sourceMapPostFix = action.sourceMaps && !action.hiddenSourceMaps ? `|sourcemap|${action.filename}` : '';
const baseCacheKey = this.generateBaseCacheKey(action.code);
// Determine cache entries required based on build settings
const cacheKeys = [];
// If optimizing and the original is not ignored, add original as required
if (!action.ignoreOriginal) {
cacheKeys[0 /* OriginalCode */] = baseCacheKey + sourceMapPostFix + '|orig';
// If sourcemaps are enabled, add original sourcemap as required
if (action.sourceMaps) {
cacheKeys[1 /* OriginalMap */] = baseCacheKey + sourceMapVendorPostfix + '|orig-map';
}
}
// If not only optimizing, add downlevel as required
if (!action.optimizeOnly) {
cacheKeys[2 /* DownlevelCode */] = baseCacheKey + sourceMapPostFix + '|dl';
// If sourcemaps are enabled, add downlevel sourcemap as required
if (action.sourceMaps) {
cacheKeys[3 /* DownlevelMap */] = baseCacheKey + sourceMapVendorPostfix + '|dl-map';
}
}
return cacheKeys;
}
async getCacheEntries(cacheKeys) {
// Attempt to get required cache entries
const cacheEntries = [];
for (const key of cacheKeys) {
if (key) {
const entry = await cacache.get.info(this.cachePath, key);
if (!entry) {
return false;
}
cacheEntries.push({
path: entry.path,
size: entry.size,
integrity: entry.metadata && entry.metadata.integrity,
});
}
else {
cacheEntries.push(null);
}
}
return cacheEntries;
}
async getCachedBundleResult(action) {
const entries = action.cacheKeys && await this.getCacheEntries(action.cacheKeys);
if (!entries) {
return null;
}
const result = {
name: action.name,
integrity: this.generateIntegrityValue(action.code),
};
let cacheEntry = entries[0 /* OriginalCode */];
if (cacheEntry) {
result.original = {
filename: action.filename,
size: cacheEntry.size,
integrity: cacheEntry.integrity,
};
BundleActionCache.copyEntryContent(cacheEntry, result.original.filename);
cacheEntry = entries[1 /* OriginalMap */];
if (cacheEntry) {
result.original.map = {
filename: action.filename + '.map',
size: cacheEntry.size,
};
BundleActionCache.copyEntryContent(cacheEntry, result.original.filename + '.map');
}
}
else if (!action.ignoreOriginal) {
// If the original wasn't processed (and therefore not cached), add info
result.original = {
filename: action.filename,
size: Buffer.byteLength(action.code, 'utf8'),
map: action.map === undefined
? undefined
: {
filename: action.filename + '.map',
size: Buffer.byteLength(action.map, 'utf8'),
},
};
}
cacheEntry = entries[2 /* DownlevelCode */];
if (cacheEntry) {
result.downlevel = {
filename: action.filename.replace(/\-(es20\d{2}|esnext)/, '-es5'),
size: cacheEntry.size,
integrity: cacheEntry.integrity,
};
BundleActionCache.copyEntryContent(cacheEntry, result.downlevel.filename);
cacheEntry = entries[3 /* DownlevelMap */];
if (cacheEntry) {
result.downlevel.map = {
filename: action.filename.replace(/\-(es20\d{2}|esnext)/, '-es5') + '.map',
size: cacheEntry.size,
};
BundleActionCache.copyEntryContent(cacheEntry, result.downlevel.filename + '.map');
}
}
return result;
}
}
exports.BundleActionCache = BundleActionCache;
;