From 5597f7fedc70d3093bb47716dd8372ced57a1963 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Mon, 21 Oct 2019 12:25:32 -0400 Subject: [PATCH] refactor(@angular-devkit/build-angular): allow control of cache location `NG_BUILD_CACHE` can specify an absolute path to be used as the cache location. Caching can also be disabled by setting the variable to 0 or false. --- .../models/webpack-configs/common.ts | 7 +++-- .../build_angular/src/browser/action-cache.ts | 8 ++--- .../src/browser/action-executor.ts | 31 +++++++++++-------- .../build_angular/src/browser/index.ts | 5 +-- .../build_angular/src/utils/cache-path.ts | 19 ++++++++++++ .../src/utils/environment-options.ts | 30 ++++++++++++++++++ .../build_angular/src/utils/mangle-options.ts | 10 ------ .../build_angular/src/utils/process-bundle.ts | 2 +- 8 files changed, 78 insertions(+), 34 deletions(-) create mode 100644 packages/angular_devkit/build_angular/src/utils/cache-path.ts create mode 100644 packages/angular_devkit/build_angular/src/utils/environment-options.ts delete mode 100644 packages/angular_devkit/build_angular/src/utils/mangle-options.ts diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts index 385963f807..7353eea88e 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts @@ -26,7 +26,8 @@ import { import { RawSource } from 'webpack-sources'; import { AssetPatternClass, ExtraEntryPoint } from '../../../browser/schema'; import { BuildBrowserFeatures } from '../../../utils'; -import { manglingDisabled } from '../../../utils/mangle-options'; +import { findCachePath } from '../../../utils/cache-path'; +import { cachingDisabled, manglingDisabled } from '../../../utils/environment-options'; import { BundleBudgetPlugin } from '../../plugins/bundle-budget'; import { CleanCssWebpackPlugin } from '../../plugins/cleancss-webpack-plugin'; import { NamedLazyChunksPlugin } from '../../plugins/named-chunks-plugin'; @@ -411,7 +412,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration { new TerserPlugin({ sourceMap: scriptsSourceMap, parallel: true, - cache: true, + cache: !cachingDisabled && findCachePath('terser-webpack'), extractComments: false, chunkFilter: (chunk: compilation.Chunk) => !globalScriptsByBundleName.some(s => s.bundleName === chunk.name), @@ -422,7 +423,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration { new TerserPlugin({ sourceMap: scriptsSourceMap, parallel: true, - cache: true, + cache: !cachingDisabled && findCachePath('terser-webpack'), extractComments: false, chunkFilter: (chunk: compilation.Chunk) => globalScriptsByBundleName.some(s => s.bundleName === chunk.name), diff --git a/packages/angular_devkit/build_angular/src/browser/action-cache.ts b/packages/angular_devkit/build_angular/src/browser/action-cache.ts index 59b1a9c341..ebd0fd407e 100644 --- a/packages/angular_devkit/build_angular/src/browser/action-cache.ts +++ b/packages/angular_devkit/build_angular/src/browser/action-cache.ts @@ -6,14 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ import { createHash } from 'crypto'; -import * as findCacheDirectory from 'find-cache-dir'; import * as fs from 'fs'; import { copyFile } from '../utils/copy-file'; -import { manglingDisabled } from '../utils/mangle-options'; +import { manglingDisabled } from '../utils/environment-options'; import { CacheKey, ProcessBundleOptions, ProcessBundleResult } from '../utils/process-bundle'; const cacache = require('cacache'); -const cacheDownlevelPath = findCacheDirectory({ name: 'angular-build-dl' }); const packageVersion = require('../../package.json').version; export interface CacheEntry { @@ -23,7 +21,7 @@ export interface CacheEntry { } export class BundleActionCache { - constructor(private readonly integrityAlgorithm?: string) {} + constructor(private readonly cachePath: string, private readonly integrityAlgorithm?: string) {} static copyEntryContent(entry: CacheEntry | string, dest: fs.PathLike): void { copyFile(typeof entry === 'string' ? entry : entry.path, dest); @@ -88,7 +86,7 @@ export class BundleActionCache { const cacheEntries = []; for (const key of cacheKeys) { if (key) { - const entry = await cacache.get.info(cacheDownlevelPath, key); + const entry = await cacache.get.info(this.cachePath, key); if (!entry) { return false; } diff --git a/packages/angular_devkit/build_angular/src/browser/action-executor.ts b/packages/angular_devkit/build_angular/src/browser/action-executor.ts index c9576e7078..f2995f8e77 100644 --- a/packages/angular_devkit/build_angular/src/browser/action-executor.ts +++ b/packages/angular_devkit/build_angular/src/browser/action-executor.ts @@ -9,6 +9,7 @@ import JestWorker from 'jest-worker'; import * as os from 'os'; import * as path from 'path'; import * as v8 from 'v8'; +import { I18nOptions } from '../utils/i18n-options'; import { InlineOptions, ProcessBundleOptions, ProcessBundleResult } from '../utils/process-bundle'; import { BundleActionCache } from './action-cache'; @@ -36,14 +37,16 @@ workerFile = export class BundleActionExecutor { private largeWorker?: JestWorker; private smallWorker?: JestWorker; - private cache: BundleActionCache; + private cache?: BundleActionCache; constructor( - private workerOptions: unknown, + private workerOptions: { cachePath?: string; i18n: I18nOptions }, integrityAlgorithm?: string, private readonly sizeThreshold = 32 * 1024, ) { - this.cache = new BundleActionCache(integrityAlgorithm); + if (workerOptions.cachePath) { + this.cache = new BundleActionCache(workerOptions.cachePath, integrityAlgorithm); + } } private static executeMethod(worker: JestWorker, method: string, input: unknown): Promise { @@ -87,16 +90,18 @@ export class BundleActionExecutor { } async process(action: ProcessBundleOptions): Promise { - const cacheKeys = this.cache.generateCacheKeys(action); - action.cacheKeys = cacheKeys; + if (this.cache) { + const cacheKeys = this.cache.generateCacheKeys(action); + action.cacheKeys = cacheKeys; - // Try to get cached data, if it fails fallback to processing - try { - const cachedResult = await this.cache.getCachedBundleResult(action); - if (cachedResult) { - return cachedResult; - } - } catch {} + // Try to get cached data, if it fails fallback to processing + try { + const cachedResult = await this.cache.getCachedBundleResult(action); + if (cachedResult) { + return cachedResult; + } + } catch {} + } return this.executeAction('process', action); } @@ -107,7 +112,7 @@ export class BundleActionExecutor { async inline( action: InlineOptions, - ): Promise<{ file: string; diagnostics: { type: string; message: string }[]; count: number; }> { + ): Promise<{ file: string; diagnostics: { type: string; message: string }[]; count: number }> { return this.executeAction('inlineLocales', action); } diff --git a/packages/angular_devkit/build_angular/src/browser/index.ts b/packages/angular_devkit/build_angular/src/browser/index.ts index 9840d61483..09403b1460 100644 --- a/packages/angular_devkit/build_angular/src/browser/index.ts +++ b/packages/angular_devkit/build_angular/src/browser/index.ts @@ -9,7 +9,6 @@ import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/ar import { EmittedFiles, WebpackLoggingCallback, runWebpack } from '@angular-devkit/build-webpack'; import { join, json, logging, normalize, tags, virtualFs } from '@angular-devkit/core'; import { NodeJsSyncHost } from '@angular-devkit/core/node'; -import * as findCacheDirectory from 'find-cache-dir'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; @@ -50,7 +49,9 @@ import { normalizeOptimization, normalizeSourceMaps, } from '../utils'; +import { findCachePath } from '../utils/cache-path'; import { copyAssets } from '../utils/copy-assets'; +import { cachingDisabled } from '../utils/environment-options'; import { emittedFilesToInlineOptions } from '../utils/i18n-inlining'; import { I18nOptions, createI18nOptions, mergeDeprecatedI18nOptions } from '../utils/i18n-options'; import { createTranslationLoader } from '../utils/load-translations'; @@ -69,7 +70,7 @@ import { import { BundleActionExecutor } from './action-executor'; import { Schema as BrowserBuilderSchema } from './schema'; -const cacheDownlevelPath = findCacheDirectory({ name: 'angular-build-dl' }); +const cacheDownlevelPath = cachingDisabled ? undefined : findCachePath('angular-build-dl'); export type BrowserBuilderOutput = json.JsonObject & BuilderOutput & { diff --git a/packages/angular_devkit/build_angular/src/utils/cache-path.ts b/packages/angular_devkit/build_angular/src/utils/cache-path.ts new file mode 100644 index 0000000000..a6eeffdd74 --- /dev/null +++ b/packages/angular_devkit/build_angular/src/utils/cache-path.ts @@ -0,0 +1,19 @@ +/** + * @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 + */ +import * as findCacheDirectory from 'find-cache-dir'; +import { tmpdir } from 'os'; +import { resolve } from 'path'; +import { cachingBasePath } from './environment-options'; + +export function findCachePath(name: string): string { + if (cachingBasePath) { + return resolve(cachingBasePath, name); + } + + return findCacheDirectory({ name }) || tmpdir(); +} diff --git a/packages/angular_devkit/build_angular/src/utils/environment-options.ts b/packages/angular_devkit/build_angular/src/utils/environment-options.ts new file mode 100644 index 0000000000..7d9e6b1931 --- /dev/null +++ b/packages/angular_devkit/build_angular/src/utils/environment-options.ts @@ -0,0 +1,30 @@ +/** + * @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 + */ +import * as path from 'path'; + +const mangleVariable = process.env['NG_BUILD_MANGLE']; +export const manglingDisabled = + !!mangleVariable && (mangleVariable === '0' || mangleVariable.toLowerCase() === 'false'); + +const cacheVariable = process.env['NG_BUILD_CACHE']; +export const cachingDisabled = + !!cacheVariable && (cacheVariable === '0' || cacheVariable.toLowerCase() === 'false'); +export const cachingBasePath = (() => { + if ( + cachingDisabled || + !cacheVariable || + (cacheVariable === '1' || cacheVariable.toLowerCase() === 'true') + ) { + return null; + } + if (!path.isAbsolute(cacheVariable)) { + throw new Error('NG_BUILD_CACHE path value must be absolute.'); + } + + return cacheVariable; +})(); diff --git a/packages/angular_devkit/build_angular/src/utils/mangle-options.ts b/packages/angular_devkit/build_angular/src/utils/mangle-options.ts deleted file mode 100644 index 84be67375d..0000000000 --- a/packages/angular_devkit/build_angular/src/utils/mangle-options.ts +++ /dev/null @@ -1,10 +0,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 mangleVariable = process.env['NG_BUILD_MANGLE']; -export const manglingDisabled = - !!mangleVariable && (mangleVariable === '0' || mangleVariable.toLowerCase() === 'false'); diff --git a/packages/angular_devkit/build_angular/src/utils/process-bundle.ts b/packages/angular_devkit/build_angular/src/utils/process-bundle.ts index 469f6c6532..1dabf9ab46 100644 --- a/packages/angular_devkit/build_angular/src/utils/process-bundle.ts +++ b/packages/angular_devkit/build_angular/src/utils/process-bundle.ts @@ -13,8 +13,8 @@ import { RawSourceMap, SourceMapConsumer, SourceMapGenerator } from 'source-map' import { minify } from 'terser'; import * as v8 from 'v8'; import { SourceMapSource } from 'webpack-sources'; +import { manglingDisabled } from './environment-options'; import { I18nOptions } from './i18n-options'; -import { manglingDisabled } from './mangle-options'; const cacache = require('cacache'); const deserialize = ((v8 as unknown) as { deserialize(buffer: Buffer): unknown }).deserialize;