UNPKG

7.05 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright Google LLC All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.io/license
8 */
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.BundleActionCache = void 0;
11const cacache = require("cacache");
12const crypto_1 = require("crypto");
13const fs = require("fs");
14const copy_file_1 = require("./copy-file");
15const environment_options_1 = require("./environment-options");
16const packageVersion = require('../../package.json').version;
17class BundleActionCache {
18 constructor(cachePath, integrityAlgorithm) {
19 this.cachePath = cachePath;
20 this.integrityAlgorithm = integrityAlgorithm;
21 }
22 static copyEntryContent(entry, dest) {
23 copy_file_1.copyFile(typeof entry === 'string' ? entry : entry.path, dest);
24 if (process.platform !== 'win32') {
25 // The cache writes entries as readonly and when using copyFile the permissions will also be copied.
26 // See: https://github.com/npm/cacache/blob/073fbe1a9f789ba42d9a41de7b8429c93cf61579/lib/util/move-file.js#L36
27 fs.chmodSync(dest, 0o644);
28 }
29 }
30 generateIntegrityValue(content) {
31 const algorithm = this.integrityAlgorithm || 'sha1';
32 const codeHash = crypto_1.createHash(algorithm).update(content).digest('base64');
33 return `${algorithm}-${codeHash}`;
34 }
35 generateBaseCacheKey(content) {
36 // Create base cache key with elements:
37 // * package version - different build-angular versions cause different final outputs
38 // * code length/hash - ensure cached version matches the same input code
39 const integrity = this.generateIntegrityValue(content);
40 let baseCacheKey = `${packageVersion}|${content.length}|${integrity}`;
41 if (!environment_options_1.allowMangle) {
42 baseCacheKey += '|MD';
43 }
44 return baseCacheKey;
45 }
46 generateCacheKeys(action) {
47 // Postfix added to sourcemap cache keys when vendor, hidden sourcemaps are present
48 // Allows non-destructive caching of both variants
49 const sourceMapVendorPostfix = action.sourceMaps && action.vendorSourceMaps ? '|vendor' : '';
50 // sourceMappingURL is added at the very end which causes the code to be the same when sourcemaps are enabled/disabled
51 // When using hiddenSourceMaps we can omit the postfix since sourceMappingURL will not be added.
52 // When having sourcemaps a hashed file and non hashed file can have the same content. But the sourceMappingURL will differ.
53 const sourceMapPostFix = action.sourceMaps && !action.hiddenSourceMaps ? `|sourcemap|${action.filename}` : '';
54 const baseCacheKey = this.generateBaseCacheKey(action.code);
55 // Determine cache entries required based on build settings
56 const cacheKeys = [];
57 // If optimizing and the original is not ignored, add original as required
58 if (!action.ignoreOriginal) {
59 cacheKeys[0 /* OriginalCode */] = baseCacheKey + sourceMapPostFix + '|orig';
60 // If sourcemaps are enabled, add original sourcemap as required
61 if (action.sourceMaps) {
62 cacheKeys[1 /* OriginalMap */] = baseCacheKey + sourceMapVendorPostfix + '|orig-map';
63 }
64 }
65 // If not only optimizing, add downlevel as required
66 if (!action.optimizeOnly) {
67 cacheKeys[2 /* DownlevelCode */] = baseCacheKey + sourceMapPostFix + '|dl';
68 // If sourcemaps are enabled, add downlevel sourcemap as required
69 if (action.sourceMaps) {
70 cacheKeys[3 /* DownlevelMap */] = baseCacheKey + sourceMapVendorPostfix + '|dl-map';
71 }
72 }
73 return cacheKeys;
74 }
75 async getCacheEntries(cacheKeys) {
76 // Attempt to get required cache entries
77 const cacheEntries = [];
78 for (const key of cacheKeys) {
79 if (key) {
80 const entry = await cacache.get.info(this.cachePath, key);
81 if (!entry) {
82 return false;
83 }
84 cacheEntries.push({
85 path: entry.path,
86 // eslint-disable-next-line @typescript-eslint/no-explicit-any
87 size: entry.size,
88 integrity: entry.metadata && entry.metadata.integrity,
89 });
90 }
91 else {
92 cacheEntries.push(null);
93 }
94 }
95 return cacheEntries;
96 }
97 async getCachedBundleResult(action) {
98 const entries = action.cacheKeys && (await this.getCacheEntries(action.cacheKeys));
99 if (!entries) {
100 return null;
101 }
102 const result = {
103 name: action.name,
104 integrity: this.generateIntegrityValue(action.code),
105 };
106 let cacheEntry = entries[0 /* OriginalCode */];
107 if (cacheEntry) {
108 result.original = {
109 filename: action.filename,
110 size: cacheEntry.size,
111 integrity: cacheEntry.integrity,
112 };
113 BundleActionCache.copyEntryContent(cacheEntry, result.original.filename);
114 cacheEntry = entries[1 /* OriginalMap */];
115 if (cacheEntry) {
116 result.original.map = {
117 filename: action.filename + '.map',
118 size: cacheEntry.size,
119 };
120 BundleActionCache.copyEntryContent(cacheEntry, result.original.filename + '.map');
121 }
122 }
123 else if (!action.ignoreOriginal) {
124 // If the original wasn't processed (and therefore not cached), add info
125 result.original = {
126 filename: action.filename,
127 size: Buffer.byteLength(action.code, 'utf8'),
128 map: action.map === undefined
129 ? undefined
130 : {
131 filename: action.filename + '.map',
132 size: Buffer.byteLength(action.map, 'utf8'),
133 },
134 };
135 }
136 cacheEntry = entries[2 /* DownlevelCode */];
137 if (cacheEntry) {
138 result.downlevel = {
139 filename: action.filename.replace(/\-(es20\d{2}|esnext)/, '-es5'),
140 size: cacheEntry.size,
141 integrity: cacheEntry.integrity,
142 };
143 BundleActionCache.copyEntryContent(cacheEntry, result.downlevel.filename);
144 cacheEntry = entries[3 /* DownlevelMap */];
145 if (cacheEntry) {
146 result.downlevel.map = {
147 filename: action.filename.replace(/\-(es20\d{2}|esnext)/, '-es5') + '.map',
148 size: cacheEntry.size,
149 };
150 BundleActionCache.copyEntryContent(cacheEntry, result.downlevel.filename + '.map');
151 }
152 }
153 return result;
154 }
155}
156exports.BundleActionCache = BundleActionCache;