Skip to content

Commit

Permalink
feat(@angular-devkit/build-angular): enable disk cache by default and…
Browse files Browse the repository at this point in the history
… provide configurable options

Persistent disk build cache is now enabled by default. A number of options have been added to allow fine tuning of the cache.

The options can be configuration in `cli.cache` section in the `angular.json` as shown below.

- `enabled`: Configure whether disk caching is enabled. Defaults to `true`
- `environment`: Configure in which environment disk cache is enabled. Valid values `ci`, `local` or `all`. Defaults to: `local`
- `path`: cache base path. Defaults to `.angular/cache`

DEPRECATED: `NG_BUILD_CACHE` environment variable option will be removed in the next major version. Configure `cli.cache` in the workspace configuration instead.

BREAKING CHANGE:  `NG_PERSISTENT_BUILD_CACHE` environment variable option no longer  have effect. Configure `cli.cache` in the workspace configuration instead.

```json
{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "cli": {
    "cache": {
      "enabled": true,
      "path": ".custom-cache-path",
      "environment": "all"
    }
  }
  ...
}
```
  • Loading branch information
alan-agius4 authored and filipesilva committed Oct 6, 2021
1 parent 09e0395 commit 5904afd
Show file tree
Hide file tree
Showing 20 changed files with 281 additions and 128 deletions.
2 changes: 0 additions & 2 deletions package.json
Expand Up @@ -100,7 +100,6 @@
"@types/copy-webpack-plugin": "^8.0.0",
"@types/debug": "^4.1.2",
"@types/express": "^4.16.0",
"@types/find-cache-dir": "^3.0.0",
"@types/glob": "^7.1.1",
"@types/http-proxy": "^1.17.4",
"@types/inquirer": "^8.0.0",
Expand Down Expand Up @@ -149,7 +148,6 @@
"eslint-plugin-import": "2.24.2",
"express": "4.17.1",
"fast-json-stable-stringify": "2.1.0",
"find-cache-dir": "3.3.2",
"font-awesome": "^4.7.0",
"gh-got": "^9.0.0",
"git-raw-commits": "^2.0.0",
Expand Down
6 changes: 5 additions & 1 deletion packages/angular/cli/commands/config-impl.ts
Expand Up @@ -21,10 +21,14 @@ const validCliPaths = new Map<
['cli.warnings.versionMismatch', undefined],
['cli.defaultCollection', undefined],
['cli.packageManager', undefined],

['cli.analytics', undefined],

['cli.analyticsSharing.tracking', undefined],
['cli.analyticsSharing.uuid', (v) => (v ? `${v}` : uuidV4())],

['cli.cache.enabled', undefined],
['cli.cache.environment', undefined],
['cli.cache.path', undefined],
]);

/**
Expand Down
19 changes: 19 additions & 0 deletions packages/angular/cli/lib/config/workspace-schema.json
Expand Up @@ -76,6 +76,25 @@
"type": "string"
}
}
},
"cache": {
"description": "Control disk cache.",
"type": "object",
"properties": {
"environment": {
"description": "Configure in which environment disk cache is enabled.",
"type": "string",
"enum": ["local", "ci", "all"]
},
"enabled": {
"description": "Configure whether disk caching is enabled.",
"type": "boolean"
},
"path": {
"description": "Cache base path.",
"type": "string"
}
}
}
},
"additionalProperties": false
Expand Down
2 changes: 0 additions & 2 deletions packages/angular_devkit/build_angular/BUILD.bazel
Expand Up @@ -119,7 +119,6 @@ ts_library(
"@npm//@types/cacache",
"@npm//@types/caniuse-lite",
"@npm//@types/copy-webpack-plugin",
"@npm//@types/find-cache-dir",
"@npm//@types/glob",
"@npm//@types/inquirer",
"@npm//@types/karma",
Expand All @@ -145,7 +144,6 @@ ts_library(
"@npm//css-loader",
"@npm//esbuild",
"@npm//esbuild-wasm",
"@npm//find-cache-dir",
"@npm//glob",
"@npm//https-proxy-agent",
"@npm//inquirer",
Expand Down
1 change: 0 additions & 1 deletion packages/angular_devkit/build_angular/package.json
Expand Up @@ -33,7 +33,6 @@
"critters": "0.0.10",
"css-loader": "6.3.0",
"esbuild-wasm": "0.13.4",
"find-cache-dir": "3.3.2",
"glob": "7.2.0",
"https-proxy-agent": "5.0.0",
"inquirer": "8.2.0",
Expand Down
Expand Up @@ -33,6 +33,7 @@ import {
IndexHtmlGenerator,
IndexHtmlTransform,
} from '../../utils/index-file/index-html-generator';
import { normalizeCacheOptions } from '../../utils/normalize-cache';
import { ensureOutputPaths } from '../../utils/output-paths';
import { generateEntryPoints } from '../../utils/package-chunk-sort';
import { augmentAppWithServiceWorker } from '../../utils/service-worker';
Expand Down Expand Up @@ -168,11 +169,14 @@ export function buildWebpackBrowser(

checkInternetExplorerSupport(buildBrowserFeatures.supportedBrowsers, context.logger);

return initialize(options, context, transforms.webpackConfiguration);
return {
...(await initialize(options, context, transforms.webpackConfiguration)),
cacheOptions: normalizeCacheOptions(projectMetadata, context.workspaceRoot),
};
}),
switchMap(
// eslint-disable-next-line max-lines-per-function
({ config, projectRoot, projectSourceRoot, i18n, target }) => {
({ config, projectRoot, projectSourceRoot, i18n, target, cacheOptions }) => {
const normalizedOptimization = normalizeOptimization(options.optimization);

return runWebpack(config, context, {
Expand Down Expand Up @@ -293,6 +297,7 @@ export function buildWebpackBrowser(
});

const indexHtmlGenerator = new IndexHtmlGenerator({
cache: cacheOptions,
indexPath: path.join(context.workspaceRoot, getIndexInputFile(options.index)),
entrypoints,
deployUrl: options.deployUrl,
Expand Down
Expand Up @@ -21,11 +21,11 @@ import webpack from 'webpack';
import webpackDevServer from 'webpack-dev-server';
import { ExecutionTransformer } from '../../transforms';
import { normalizeOptimization } from '../../utils';
import { findCachePath } from '../../utils/cache-path';
import { checkPort } from '../../utils/check-port';
import { colors } from '../../utils/color';
import { I18nOptions } from '../../utils/i18n-options';
import { IndexHtmlTransform } from '../../utils/index-file/index-html-generator';
import { NormalizedCachedOptions, normalizeCacheOptions } from '../../utils/normalize-cache';
import { generateEntryPoints } from '../../utils/package-chunk-sort';
import { assertCompatibleAngularVersion } from '../../utils/version';
import {
Expand Down Expand Up @@ -86,8 +86,12 @@ export function serveWebpackBrowser(
browserOptions: json.JsonObject & BrowserBuilderSchema;
webpackConfig: webpack.Configuration;
projectRoot: string;
locale: string | undefined;
}> {
const projectName = context.target?.project;
if (!projectName) {
throw new Error('The builder requires a target.');
}

options.port = await checkPort(options.port ?? 4200, options.host || 'localhost');

if (options.hmr) {
Expand Down Expand Up @@ -130,6 +134,9 @@ export function serveWebpackBrowser(
logger.warn(`Warning: 'outputHashing' option is disabled when using the dev-server.`);
}

const metadata = await context.getProjectMetadata(projectName);
const cacheOptions = normalizeCacheOptions(metadata, context.workspaceRoot);

const browserName = await context.getBuilderNameForTarget(browserTarget);
const browserOptions = (await context.validateOptions(
{
Expand Down Expand Up @@ -193,51 +200,51 @@ export function serveWebpackBrowser(
);
}

await setupLocalize(locale, i18n, browserOptions, webpackConfig);
await setupLocalize(locale, i18n, browserOptions, webpackConfig, cacheOptions);
}

if (transforms.webpackConfiguration) {
webpackConfig = await transforms.webpackConfiguration(webpackConfig);
}

if (browserOptions.index) {
const { scripts = [], styles = [], baseHref } = browserOptions;
const entrypoints = generateEntryPoints({
scripts,
styles,
// The below is needed as otherwise HMR for CSS will break.
// styles.js and runtime.js needs to be loaded as a non-module scripts as otherwise `document.currentScript` will be null.
// https://github.com/webpack-contrib/mini-css-extract-plugin/blob/90445dd1d81da0c10b9b0e8a17b417d0651816b8/src/hmr/hotModuleReplacement.js#L39
isHMREnabled: !!webpackConfig.devServer?.hot,
});

webpackConfig.plugins ??= [];
webpackConfig.plugins.push(
new IndexHtmlWebpackPlugin({
indexPath: path.resolve(workspaceRoot, getIndexInputFile(browserOptions.index)),
outputPath: getIndexOutputFile(browserOptions.index),
baseHref,
entrypoints,
deployUrl: browserOptions.deployUrl,
sri: browserOptions.subresourceIntegrity,
cache: cacheOptions,
postTransform: transforms.indexHtml,
optimization: normalizeOptimization(browserOptions.optimization),
crossOrigin: browserOptions.crossOrigin,
lang: locale,
}),
);
}

return {
browserOptions,
webpackConfig,
projectRoot,
locale,
};
}

return from(setup()).pipe(
switchMap(({ browserOptions, webpackConfig, locale }) => {
if (browserOptions.index) {
const { scripts = [], styles = [], baseHref } = browserOptions;
const entrypoints = generateEntryPoints({
scripts,
styles,
// The below is needed as otherwise HMR for CSS will break.
// styles.js and runtime.js needs to be loaded as a non-module scripts as otherwise `document.currentScript` will be null.
// https://github.com/webpack-contrib/mini-css-extract-plugin/blob/90445dd1d81da0c10b9b0e8a17b417d0651816b8/src/hmr/hotModuleReplacement.js#L39
isHMREnabled: !!webpackConfig.devServer?.hot,
});

webpackConfig.plugins ??= [];
webpackConfig.plugins.push(
new IndexHtmlWebpackPlugin({
indexPath: path.resolve(workspaceRoot, getIndexInputFile(browserOptions.index)),
outputPath: getIndexOutputFile(browserOptions.index),
baseHref,
entrypoints,
deployUrl: browserOptions.deployUrl,
sri: browserOptions.subresourceIntegrity,
postTransform: transforms.indexHtml,
optimization: normalizeOptimization(browserOptions.optimization),
crossOrigin: browserOptions.crossOrigin,
lang: locale,
}),
);
}

switchMap(({ browserOptions, webpackConfig }) => {
return runWebpackDevServer(webpackConfig, context, {
logging: transforms.logging || createWebpackLoggingCallback(browserOptions, logger),
webpackFactory: require('webpack') as typeof webpack,
Expand Down Expand Up @@ -286,6 +293,7 @@ async function setupLocalize(
i18n: I18nOptions,
browserOptions: BrowserBuilderSchema,
webpackConfig: webpack.Configuration,
cacheOptions: NormalizedCachedOptions,
) {
const localeDescription = i18n.locales[locale];

Expand Down Expand Up @@ -327,7 +335,9 @@ async function setupLocalize(
{
loader: require.resolve('../../babel/webpack-loader'),
options: {
cacheDirectory: findCachePath('babel-dev-server-i18n'),
cacheDirectory:
(cacheOptions.enabled && path.join(cacheOptions.path, 'babel-dev-server-i18n')) ||
false,
cacheIdentifier: JSON.stringify({
locale,
translationIntegrity: localeDescription?.files.map((file) => file.integrity),
Expand Down
Expand Up @@ -7,35 +7,52 @@
*/

import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
import { resolve } from 'path';
import { join, resolve } from 'path';
import { Observable, from, of } from 'rxjs';
import { catchError, mapTo, switchMap } from 'rxjs/operators';
import { normalizeCacheOptions } from '../../utils/normalize-cache';
import { Schema as NgPackagrBuilderOptions } from './schema';

async function initialize(
options: NgPackagrBuilderOptions,
root: string,
): Promise<import('ng-packagr').NgPackagr> {
const packager = (await import('ng-packagr')).ngPackagr();

packager.forProject(resolve(root, options.project));

if (options.tsConfig) {
packager.withTsConfig(resolve(root, options.tsConfig));
}

return packager;
}

/**
* @experimental Direct usage of this function is considered experimental.
*/
export function execute(
options: NgPackagrBuilderOptions,
context: BuilderContext,
): Observable<BuilderOutput> {
return from(initialize(options, context.workspaceRoot)).pipe(
switchMap((packager) => (options.watch ? packager.watch() : packager.build())),
return from(
(async () => {
const root = context.workspaceRoot;
const packager = (await import('ng-packagr')).ngPackagr();

packager.forProject(resolve(root, options.project));

if (options.tsConfig) {
packager.withTsConfig(resolve(root, options.tsConfig));
}

const projectName = context.target?.project;
if (!projectName) {
throw new Error('The builder requires a target.');
}

const metadata = await context.getProjectMetadata(projectName);
const { enabled: cacheEnabled, path: cacheDirectory } = normalizeCacheOptions(
metadata,
context.workspaceRoot,
);

const ngPackagrOptions = {
cacheEnabled,
cacheDirectory: join(cacheDirectory, 'ng-packagr'),
};

return { packager, ngPackagrOptions };
})(),
).pipe(
switchMap(({ packager, ngPackagrOptions }) =>
options.watch ? packager.watch(ngPackagrOptions) : packager.build(ngPackagrOptions),
),
mapTo({ success: true }),
catchError((err) => of({ success: false, error: err.message })),
);
Expand Down
Expand Up @@ -20,6 +20,7 @@ import {
SourceMapClass,
} from '../builders/browser/schema';
import { Schema as DevServerSchema } from '../builders/dev-server/schema';
import { NormalizedCachedOptions } from './normalize-cache';
import { NormalizedFileReplacement } from './normalize-file-replacements';
import { NormalizedOptimizationOptions } from './normalize-optimization';

Expand Down Expand Up @@ -66,8 +67,8 @@ export interface BuildOptions {
platform?: 'browser' | 'server';
fileReplacements: NormalizedFileReplacement[];
inlineStyleLanguage?: InlineStyleLanguage;

allowedCommonJsDependencies?: string[];
cache: NormalizedCachedOptions;
}

export interface WebpackTestOptions extends BuildOptions {
Expand Down
20 changes: 0 additions & 20 deletions packages/angular_devkit/build_angular/src/utils/cache-path.ts

This file was deleted.

0 comments on commit 5904afd

Please sign in to comment.