Commit fbe81434 by Lutfi

init

parents
The MIT License
Copyright (c) 2017 Google, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Snapshot build of @angular-devkit/build-angular
This repository is a snapshot of a commit on the original repository. The original code used to
generate this is located at http://github.com/angular/angular-cli.
We do not accept PRs or Issues opened on this repository. You should not use this over a tested and
released version of this package.
To test this snapshot in your own project, use
```bash
npm install git+https://github.com/angular/angular-devkit-build-angular-builds.git
```
----
# Angular Webpack Build Facade
WIP
\ No newline at end of file
{
"$schema": "../architect/src/builders-schema.json",
"builders": {
"app-shell": {
"implementation": "./src/app-shell",
"schema": "./src/app-shell/schema.json",
"description": "Build a server app and a browser app, then render the index.html and use it for the browser output."
},
"browser": {
"implementation": "./src/browser",
"schema": "./src/browser/schema.json",
"description": "Build a browser app."
},
"dev-server": {
"implementation": "./src/dev-server",
"schema": "./src/dev-server/schema.json",
"description": "Serve a browser app."
},
"extract-i18n": {
"implementation": "./src/extract-i18n",
"schema": "./src/extract-i18n/schema.json",
"description": "Extract i18n strings from a browser app."
},
"karma": {
"implementation": "./src/karma",
"schema": "./src/karma/schema.json",
"description": "Run Karma unit tests."
},
"protractor": {
"implementation": "./src/protractor",
"schema": "./src/protractor/schema.json",
"description": "Run protractor over a dev server."
},
"tslint": {
"implementation": "./src/tslint",
"schema": "./src/tslint/schema.json",
"description": "Run tslint over a TS project."
},
"server": {
"implementation": "./src/server",
"schema": "./src/server/schema.json",
"description": "Build a server Angular application."
}
}
}
{
"name": "@angular-devkit/build-angular",
"version": "0.901.15+5.cff09e4",
"description": "Angular Webpack Build Facade",
"experimental": true,
"main": "src/index.js",
"typings": "src/index.d.ts",
"builders": "builders.json",
"dependencies": {
"@angular-devkit/architect": "github:angular/angular-devkit-architect-builds#cff09e433",
"@angular-devkit/build-optimizer": "github:angular/angular-devkit-build-optimizer-builds#cff09e433",
"@angular-devkit/build-webpack": "github:angular/angular-devkit-build-webpack-builds#cff09e433",
"@angular-devkit/core": "github:angular/angular-devkit-core-builds#cff09e433",
"@babel/core": "7.9.0",
"@babel/generator": "7.9.3",
"@babel/preset-env": "7.9.0",
"@babel/template": "7.8.6",
"@jsdevtools/coverage-istanbul-loader": "3.0.3",
"@ngtools/webpack": "github:angular/ngtools-webpack-builds#cff09e433",
"ajv": "6.12.3",
"autoprefixer": "9.7.4",
"babel-loader": "8.0.6",
"browserslist": "^4.9.1",
"cacache": "15.0.0",
"caniuse-lite": "^1.0.30001032",
"circular-dependency-plugin": "5.2.0",
"copy-webpack-plugin": "6.0.3",
"core-js": "3.6.4",
"css-loader": "3.5.1",
"cssnano": "4.1.10",
"file-loader": "6.0.0",
"find-cache-dir": "3.3.1",
"glob": "7.1.6",
"jest-worker": "25.1.0",
"karma-source-map-support": "1.4.0",
"less": "3.11.3",
"less-loader": "5.0.0",
"license-webpack-plugin": "2.1.4",
"loader-utils": "2.0.0",
"mini-css-extract-plugin": "0.9.0",
"minimatch": "3.0.4",
"parse5": "4.0.0",
"open": "7.0.3",
"postcss": "github:LutfiArdiansyah/postcss",
"postcss-import": "12.0.1",
"postcss-loader": "3.0.0",
"raw-loader": "4.0.0",
"regenerator-runtime": "0.13.5",
"rimraf": "3.0.2",
"rollup": "2.1.0",
"rxjs": "6.5.4",
"sass": "1.26.3",
"sass-loader": "8.0.2",
"semver": "7.1.3",
"source-map": "0.7.3",
"source-map-loader": "0.2.4",
"speed-measure-webpack-plugin": "1.3.1",
"style-loader": "1.1.3",
"stylus": "0.54.7",
"stylus-loader": "3.0.2",
"tree-kill": "1.2.2",
"terser": "4.6.10",
"terser-webpack-plugin": "3.0.3",
"webpack": "4.42.0",
"webpack-dev-middleware": "github:LutfiArdiansyah/webpack-dev-middleware",
"webpack-dev-server": "3.11.0",
"webpack-merge": "4.2.2",
"webpack-sources": "1.4.3",
"webpack-subresource-integrity": "1.4.0",
"worker-plugin": "4.0.3"
},
"peerDependencies": {
"@angular/compiler-cli": ">=9.0.0 < 10",
"typescript": ">=3.6 < 3.9"
},
"peerDependenciesMeta": {
"@angular/localize": {
"optional": true
}
},
"keywords": [
"angular",
"Angular CLI",
"devkit",
"sdk",
"Angular DevKit"
],
"repository": {
"type": "git",
"url": "https://github.com/angular/angular-cli.git"
},
"engines": {
"node": ">= 10.13.0",
"npm": "^6.11.0 || ^7.5.6",
"yarn": ">= 1.13.0"
},
"author": "Angular Authors",
"license": "MIT",
"bugs": {
"url": "https://github.com/angular/angular-cli/issues"
},
"homepage": "https://github.com/angular/angular-cli",
"husky": {
"hooks": {
"pre-push": "node ./bin/devkit-admin hooks/pre-push"
}
}
}
/**
* @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
*/
/**
* @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
*/
module.exports = require('../src/angular-cli-files/plugins/karma');
/**
* @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 { analytics } from '@angular-devkit/core';
import { Compiler, Module, Stats, compilation } from 'webpack';
import { Source } from 'webpack-sources';
declare const NormalModule: any;
interface NormalModule extends Module {
_source?: Source | null;
resource?: string;
}
/**
* Faster than using a RegExp, so we use this to count occurences in source code.
* @param source The source to look into.
* @param match The match string to look for.
* @param wordBreak Whether to check for word break before and after a match was found.
* @return The number of matches found.
* @private
*/
export declare function countOccurrences(source: string, match: string, wordBreak?: boolean): number;
/**
* Holder of statistics related to the build.
*/
declare class AnalyticsBuildStats {
errors: string[];
numberOfNgOnInit: number;
numberOfComponents: number;
initialChunkSize: number;
totalChunkCount: number;
totalChunkSize: number;
lazyChunkCount: number;
lazyChunkSize: number;
assetCount: number;
assetSize: number;
polyfillSize: number;
cssSize: number;
}
/**
* Analytics plugin that reports the analytics we want from the CLI.
*/
export declare class NgBuildAnalyticsPlugin {
protected _projectRoot: string;
protected _analytics: analytics.Analytics;
protected _category: string;
private _isIvy;
protected _built: boolean;
protected _stats: AnalyticsBuildStats;
constructor(_projectRoot: string, _analytics: analytics.Analytics, _category: string, _isIvy: boolean);
protected _reset(): void;
protected _getMetrics(stats: Stats): (string | number)[];
protected _getDimensions(stats: Stats): import("../../../../../dist-schema/packages/angular/cli/commands/config").Value[];
protected _reportBuildMetrics(stats: Stats): void;
protected _reportRebuildMetrics(stats: Stats): void;
protected _checkTsNormalModule(module: NormalModule): void;
protected _checkNgFactoryNormalModule(module: NormalModule): void;
protected _collectErrors(stats: Stats): void;
protected _collectBundleStats(json: any): void;
/************************************************************************************************
* The next section is all the different Webpack hooks for this plugin.
*/
/**
* Reports a succeed module.
* @private
*/
protected _succeedModule(mod: Module): void;
protected _compilation(compiler: Compiler, compilation: compilation.Compilation): void;
protected _done(stats: Stats): void;
apply(compiler: Compiler): void;
}
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 core_1 = require("@angular-devkit/core");
const NormalModule = require('webpack/lib/NormalModule');
const webpackAllErrorMessageRe = /^([^(]+)\(\d+,\d\): (.*)$/gm;
const webpackTsErrorMessageRe = /^[^(]+\(\d+,\d\): error (TS\d+):/;
/**
* Faster than using a RegExp, so we use this to count occurences in source code.
* @param source The source to look into.
* @param match The match string to look for.
* @param wordBreak Whether to check for word break before and after a match was found.
* @return The number of matches found.
* @private
*/
function countOccurrences(source, match, wordBreak = false) {
if (match.length == 0) {
return source.length + 1;
}
let count = 0;
// We condition here so branch prediction happens out of the loop, not in it.
if (wordBreak) {
const re = /\w/;
for (let pos = source.lastIndexOf(match); pos >= 0; pos = source.lastIndexOf(match, pos)) {
if (!(re.test(source[pos - 1] || '') || re.test(source[pos + match.length] || ''))) {
count++; // 1 match, AH! AH! AH! 2 matches, AH! AH! AH!
}
pos -= match.length;
if (pos < 0) {
break;
}
}
}
else {
for (let pos = source.lastIndexOf(match); pos >= 0; pos = source.lastIndexOf(match, pos)) {
count++; // 1 match, AH! AH! AH! 2 matches, AH! AH! AH!
pos -= match.length;
if (pos < 0) {
break;
}
}
}
return count;
}
exports.countOccurrences = countOccurrences;
/**
* Holder of statistics related to the build.
*/
class AnalyticsBuildStats {
constructor() {
this.errors = [];
this.numberOfNgOnInit = 0;
this.numberOfComponents = 0;
this.initialChunkSize = 0;
this.totalChunkCount = 0;
this.totalChunkSize = 0;
this.lazyChunkCount = 0;
this.lazyChunkSize = 0;
this.assetCount = 0;
this.assetSize = 0;
this.polyfillSize = 0;
this.cssSize = 0;
}
}
/**
* Analytics plugin that reports the analytics we want from the CLI.
*/
class NgBuildAnalyticsPlugin {
constructor(_projectRoot, _analytics, _category, _isIvy) {
this._projectRoot = _projectRoot;
this._analytics = _analytics;
this._category = _category;
this._isIvy = _isIvy;
this._built = false;
this._stats = new AnalyticsBuildStats();
}
_reset() {
this._stats = new AnalyticsBuildStats();
}
_getMetrics(stats) {
const startTime = +(stats.startTime || 0);
const endTime = +(stats.endTime || 0);
const metrics = [];
metrics[core_1.analytics.NgCliAnalyticsMetrics.BuildTime] = (endTime - startTime);
metrics[core_1.analytics.NgCliAnalyticsMetrics.NgOnInitCount] = this._stats.numberOfNgOnInit;
metrics[core_1.analytics.NgCliAnalyticsMetrics.NgComponentCount] = this._stats.numberOfComponents;
metrics[core_1.analytics.NgCliAnalyticsMetrics.InitialChunkSize] = this._stats.initialChunkSize;
metrics[core_1.analytics.NgCliAnalyticsMetrics.TotalChunkCount] = this._stats.totalChunkCount;
metrics[core_1.analytics.NgCliAnalyticsMetrics.TotalChunkSize] = this._stats.totalChunkSize;
metrics[core_1.analytics.NgCliAnalyticsMetrics.LazyChunkCount] = this._stats.lazyChunkCount;
metrics[core_1.analytics.NgCliAnalyticsMetrics.LazyChunkSize] = this._stats.lazyChunkSize;
metrics[core_1.analytics.NgCliAnalyticsMetrics.AssetCount] = this._stats.assetCount;
metrics[core_1.analytics.NgCliAnalyticsMetrics.AssetSize] = this._stats.assetSize;
metrics[core_1.analytics.NgCliAnalyticsMetrics.PolyfillSize] = this._stats.polyfillSize;
metrics[core_1.analytics.NgCliAnalyticsMetrics.CssSize] = this._stats.cssSize;
return metrics;
}
_getDimensions(stats) {
const dimensions = [];
if (this._stats.errors.length) {
// Adding commas before and after so the regex are easier to define filters.
dimensions[core_1.analytics.NgCliAnalyticsDimensions.BuildErrors] = `,${this._stats.errors.join()},`;
}
dimensions[core_1.analytics.NgCliAnalyticsDimensions.NgIvyEnabled] = this._isIvy;
return dimensions;
}
_reportBuildMetrics(stats) {
const dimensions = this._getDimensions(stats);
const metrics = this._getMetrics(stats);
this._analytics.event(this._category, 'build', { dimensions, metrics });
}
_reportRebuildMetrics(stats) {
const dimensions = this._getDimensions(stats);
const metrics = this._getMetrics(stats);
this._analytics.event(this._category, 'rebuild', { dimensions, metrics });
}
_checkTsNormalModule(module) {
if (module._source) {
// PLEASE REMEMBER:
// We're dealing with ES5 _or_ ES2015 JavaScript at this point (we don't know for sure).
// Just count the ngOnInit occurences. Comments/Strings/calls occurences should be sparse
// so we just consider them within the margin of error. We do break on word break though.
this._stats.numberOfNgOnInit += countOccurrences(module._source.source(), 'ngOnInit', true);
// Count the number of `Component({` strings (case sensitive), which happens in __decorate().
// This does not include View Engine AOT compilation, we use the ngfactory for it.
this._stats.numberOfComponents += countOccurrences(module._source.source(), 'Component({');
// For Ivy we just count ɵcmp.
this._stats.numberOfComponents += countOccurrences(module._source.source(), '.ɵcmp', true);
}
}
_checkNgFactoryNormalModule(module) {
if (module._source) {
// PLEASE REMEMBER:
// We're dealing with ES5 _or_ ES2015 JavaScript at this point (we don't know for sure).
// Count the number of `.ɵccf(` strings (case sensitive). They're calls to components
// factories.
this._stats.numberOfComponents += countOccurrences(module._source.source(), '.ɵccf(');
}
}
_collectErrors(stats) {
if (stats.hasErrors()) {
for (const errObject of stats.compilation.errors) {
if (errObject instanceof Error) {
const allErrors = errObject.message.match(webpackAllErrorMessageRe);
for (const err of [...allErrors || []].slice(1)) {
const message = (err.match(webpackTsErrorMessageRe) || [])[1];
if (message) {
// At this point this should be a TS1234.
this._stats.errors.push(message);
}
}
}
}
}
}
// We can safely disable no any here since we know the format of the JSON output from webpack.
// tslint:disable-next-line:no-any
_collectBundleStats(json) {
json.chunks
.filter((chunk) => chunk.rendered)
.forEach((chunk) => {
const asset = json.assets.find((x) => x.name == chunk.files[0]);
const size = asset ? asset.size : 0;
if (chunk.entry || chunk.initial) {
this._stats.initialChunkSize += size;
}
else {
this._stats.lazyChunkCount++;
this._stats.lazyChunkSize += size;
}
this._stats.totalChunkCount++;
this._stats.totalChunkSize += size;
});
json.assets
// Filter out chunks. We only count assets that are not JS.
.filter((a) => {
return json.chunks.every((chunk) => chunk.files[0] != a.name);
})
.forEach((a) => {
this._stats.assetSize += (a.size || 0);
this._stats.assetCount++;
});
for (const asset of json.assets) {
if (asset.name == 'polyfill') {
this._stats.polyfillSize += asset.size || 0;
}
}
for (const chunk of json.chunks) {
if (chunk.files[0] && chunk.files[0].endsWith('.css')) {
this._stats.cssSize += chunk.size || 0;
}
}
}
/************************************************************************************************
* The next section is all the different Webpack hooks for this plugin.
*/
/**
* Reports a succeed module.
* @private
*/
_succeedModule(mod) {
// Only report NormalModule instances.
if (mod.constructor !== NormalModule) {
return;
}
const module = mod;
// Only reports modules that are part of the user's project. We also don't do node_modules.
// There is a chance that someone name a file path `hello_node_modules` or something and we
// will ignore that file for the purpose of gathering, but we're willing to take the risk.
if (!module.resource
|| !module.resource.startsWith(this._projectRoot)
|| module.resource.indexOf('node_modules') >= 0) {
return;
}
// Check that it's a source file from the project.
if (module.resource.endsWith('.ts')) {
this._checkTsNormalModule(module);
}
else if (module.resource.endsWith('.ngfactory.js')) {
this._checkNgFactoryNormalModule(module);
}
}
_compilation(compiler, compilation) {
this._reset();
compilation.hooks.succeedModule.tap('NgBuildAnalyticsPlugin', this._succeedModule.bind(this));
}
_done(stats) {
this._collectErrors(stats);
this._collectBundleStats(stats.toJson());
if (this._built) {
this._reportRebuildMetrics(stats);
}
else {
this._reportBuildMetrics(stats);
this._built = true;
}
}
apply(compiler) {
compiler.hooks.compilation.tap('NgBuildAnalyticsPlugin', this._compilation.bind(this, compiler));
compiler.hooks.done.tap('NgBuildAnalyticsPlugin', this._done.bind(this));
}
}
exports.NgBuildAnalyticsPlugin = NgBuildAnalyticsPlugin;
/**
* @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 { logging } from '@angular-devkit/core';
import { ParsedConfiguration } from '@angular/compiler-cli';
import { AssetPatternClass, Budget, CrossOrigin, ExtraEntryPoint, I18NMissingTranslation, Localize, OptimizationClass, SourceMapClass } from '../../browser/schema';
import { NormalizedFileReplacement } from '../../utils/normalize-file-replacements';
export interface BuildOptions {
optimization: OptimizationClass;
environment?: string;
outputPath: string;
resourcesOutputPath?: string;
aot?: boolean;
sourceMap: SourceMapClass;
/** @deprecated since version 8. use sourceMap instead. */
vendorSourceMap?: boolean;
/** @deprecated since version 8 */
evalSourceMap?: boolean;
vendorChunk?: boolean;
commonChunk?: boolean;
baseHref?: string;
deployUrl?: string;
verbose?: boolean;
progress?: boolean;
/** @deprecated since version 9. Use 'locales' object in the project metadata instead.*/
i18nFile?: string;
/** @deprecated since version 9. No longer needed as the format will be determined automatically.*/
i18nFormat?: string;
/** @deprecated since version 9. Use 'localize' instead.*/
i18nLocale?: string;
localize?: Localize;
i18nMissingTranslation?: I18NMissingTranslation;
extractCss?: boolean;
bundleDependencies?: boolean;
externalDependencies?: string[];
watch?: boolean;
outputHashing?: string;
poll?: number;
deleteOutputPath?: boolean;
preserveSymlinks?: boolean;
extractLicenses?: boolean;
showCircularDependencies?: boolean;
buildOptimizer?: boolean;
namedChunks?: boolean;
crossOrigin?: CrossOrigin;
subresourceIntegrity?: boolean;
serviceWorker?: boolean;
webWorkerTsConfig?: string;
/** @deprecated since version 8 **/
skipAppShell?: boolean;
statsJson: boolean;
forkTypeChecker: boolean;
profile?: boolean;
/** @deprecated since version 8 **/
es5BrowserSupport?: boolean;
main: string;
polyfills?: string;
budgets: Budget[];
assets: AssetPatternClass[];
scripts: ExtraEntryPoint[];
styles: ExtraEntryPoint[];
stylePreprocessorOptions?: {
includePaths: string[];
};
/** @deprecated SystemJsNgModuleLoader is deprecated, and this is part of its usage. */
lazyModules: string[];
platform?: 'browser' | 'server';
fileReplacements: NormalizedFileReplacement[];
/** @deprecated use only for compatibility in 8.x; will be removed in 9.0 */
rebaseRootRelativeCssUrls?: boolean;
esVersionInFileName?: boolean;
experimentalRollupPass?: boolean;
}
export interface WebpackTestOptions extends BuildOptions {
codeCoverage?: boolean;
codeCoverageExclude?: string[];
}
export interface WebpackConfigOptions<T = BuildOptions> {
root: string;
logger: logging.Logger;
projectRoot: string;
sourceRoot?: string;
buildOptions: T;
tsConfig: ParsedConfiguration;
tsConfigPath: string;
supportES2015: boolean;
differentialLoadingMode?: boolean;
}
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 'core-js/es/reflect';
/**
* @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
*/
// ES2015 symbol capabilities
import 'core-js/es/symbol';
// ES2015 function capabilities
import 'core-js/modules/es.function.bind';
import 'core-js/modules/es.function.name';
import 'core-js/modules/es.function.has-instance';
// ES2015 object capabilities
import 'core-js/modules/es.object.create';
import 'core-js/modules/es.object.define-property';
import 'core-js/modules/es.object.define-properties';
import 'core-js/modules/es.object.get-own-property-descriptor';
import 'core-js/modules/es.object.get-prototype-of';
import 'core-js/modules/es.object.keys';
import 'core-js/modules/es.object.get-own-property-names';
import 'core-js/modules/es.object.freeze';
import 'core-js/modules/es.object.seal';
import 'core-js/modules/es.object.prevent-extensions';
import 'core-js/modules/es.object.is-frozen';
import 'core-js/modules/es.object.is-sealed';
import 'core-js/modules/es.object.is-extensible';
import 'core-js/modules/es.object.assign';
import 'core-js/modules/es.object.is';
import 'core-js/modules/es.object.set-prototype-of';
import 'core-js/modules/es.object.to-string';
// ES2015 array capabilities
import 'core-js/modules/es.array.concat';
import 'core-js/modules/es.array.is-array';
import 'core-js/modules/es.array.from';
import 'core-js/modules/es.array.of';
import 'core-js/modules/es.array.join';
import 'core-js/modules/es.array.slice';
import 'core-js/modules/es.array.splice';
import 'core-js/modules/es.array.sort';
import 'core-js/modules/es.array.for-each';
import 'core-js/modules/es.array.map';
import 'core-js/modules/es.array.filter';
import 'core-js/modules/es.array.some';
import 'core-js/modules/es.array.every';
import 'core-js/modules/es.array.reduce';
import 'core-js/modules/es.array.reduce-right';
import 'core-js/modules/es.array.index-of';
import 'core-js/modules/es.array.last-index-of';
import 'core-js/modules/es.array.copy-within';
import 'core-js/modules/es.array.fill';
import 'core-js/modules/es.array.find';
import 'core-js/modules/es.array.find-index';
import 'core-js/modules/es.array.iterator';
// ES2015 string capabilities
import 'core-js/modules/es.string.from-code-point';
import 'core-js/modules/es.string.raw';
import 'core-js/modules/es.string.trim';
import 'core-js/modules/es.string.iterator';
import 'core-js/modules/es.string.code-point-at';
import 'core-js/modules/es.string.ends-with';
import 'core-js/modules/es.string.includes';
import 'core-js/modules/es.string.repeat';
import 'core-js/modules/es.string.starts-with';
import 'core-js/modules/es.string.anchor';
import 'core-js/modules/es.string.big';
import 'core-js/modules/es.string.blink';
import 'core-js/modules/es.string.bold';
import 'core-js/modules/es.string.fixed';
import 'core-js/modules/es.string.fontcolor';
import 'core-js/modules/es.string.fontsize';
import 'core-js/modules/es.string.italics';
import 'core-js/modules/es.string.link';
import 'core-js/modules/es.string.small';
import 'core-js/modules/es.string.strike';
import 'core-js/modules/es.string.sub';
import 'core-js/modules/es.string.sup';
import 'core-js/modules/es.string.match';
import 'core-js/modules/es.string.replace';
import 'core-js/modules/es.string.search';
import 'core-js/modules/es.string.split';
import 'core-js/modules/es.parse-int';
import 'core-js/modules/es.parse-float';
import 'core-js/es/number';
import 'core-js/es/math';
import 'core-js/es/date';
import 'core-js/modules/es.regexp.constructor';
import 'core-js/modules/es.regexp.to-string';
import 'core-js/modules/es.regexp.flags';
import 'core-js/modules/es.map';
import 'core-js/modules/es.weak-map';
import 'core-js/modules/es.set';
import 'core-js/modules/web.dom-collections.for-each';
import 'core-js/modules/web.dom-collections.iterator';
import 'core-js/modules/es.promise';
import 'core-js/modules/es.json.to-string-tag';
import 'regenerator-runtime/runtime';
\ No newline at end of file
/**
* @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 'core-js/proposals/reflect-metadata';
import * as webpack from 'webpack';
import { WebpackConfigOptions } from '../build-options';
export declare function getBrowserConfig(wco: WebpackConfigOptions): webpack.Configuration;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 license_webpack_plugin_1 = require("license-webpack-plugin");
const utils_1 = require("./utils");
const SubresourceIntegrityPlugin = require('webpack-subresource-integrity');
function getBrowserConfig(wco) {
const { buildOptions } = wco;
const { crossOrigin = 'none', subresourceIntegrity, evalSourceMap, extractLicenses, vendorChunk, commonChunk, styles, } = buildOptions;
const extraPlugins = [];
let isEval = false;
const { styles: stylesOptimization, scripts: scriptsOptimization } = buildOptions.optimization;
const { styles: stylesSourceMap, scripts: scriptsSourceMap, hidden: hiddenSourceMap, } = buildOptions.sourceMap;
// See https://webpack.js.org/configuration/devtool/ for sourcemap types.
if ((stylesSourceMap || scriptsSourceMap) &&
evalSourceMap &&
!stylesOptimization &&
!scriptsOptimization) {
// Produce eval sourcemaps for development with serve, which are faster.
isEval = true;
}
if (subresourceIntegrity) {
extraPlugins.push(new SubresourceIntegrityPlugin({
hashFuncNames: ['sha384'],
}));
}
if (extractLicenses) {
extraPlugins.push(new license_webpack_plugin_1.LicenseWebpackPlugin({
stats: {
warnings: false,
errors: false,
},
perChunkOutput: false,
outputFilename: '3rdpartylicenses.txt',
}));
}
if (!isEval && (scriptsSourceMap || stylesSourceMap)) {
extraPlugins.push(utils_1.getSourceMapDevTool(scriptsSourceMap, stylesSourceMap, wco.differentialLoadingMode ? true : hiddenSourceMap));
}
const globalStylesBundleNames = utils_1.normalizeExtraEntryPoints(styles, 'styles')
.map(style => style.bundleName);
let crossOriginLoading = false;
if (subresourceIntegrity && crossOrigin === 'none') {
crossOriginLoading = 'anonymous';
}
else if (crossOrigin !== 'none') {
crossOriginLoading = crossOrigin;
}
return {
devtool: isEval ? 'eval' : false,
resolve: {
mainFields: [
...(wco.supportES2015 ? ['es2015'] : []),
'browser', 'module', 'main',
],
},
output: {
crossOriginLoading,
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
maxAsyncRequests: Infinity,
cacheGroups: {
default: !!commonChunk && {
chunks: 'async',
minChunks: 2,
priority: 10,
},
common: !!commonChunk && {
name: 'common',
chunks: 'async',
minChunks: 2,
enforce: true,
priority: 5,
},
vendors: false,
vendor: !!vendorChunk && {
name: 'vendor',
chunks: 'initial',
enforce: true,
test: (module, chunks) => {
const moduleName = module.nameForCondition ? module.nameForCondition() : '';
return /[\\/]node_modules[\\/]/.test(moduleName)
&& !chunks.some(({ name }) => utils_1.isPolyfillsEntry(name)
|| globalStylesBundleNames.includes(name));
},
},
},
},
},
plugins: extraPlugins,
node: false,
};
}
exports.getBrowserConfig = getBrowserConfig;
import { Configuration } from 'webpack';
import { WebpackConfigOptions } from '../build-options';
export declare function getCommonConfig(wco: WebpackConfigOptions): Configuration;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 build_optimizer_1 = require("@angular-devkit/build-optimizer");
const core_1 = require("@angular-devkit/core");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const fs_1 = require("fs");
const path = require("path");
const typescript_1 = require("typescript");
const webpack_1 = require("webpack");
const webpack_sources_1 = require("webpack-sources");
const utils_1 = require("../../../utils");
const cache_path_1 = require("../../../utils/cache-path");
const environment_options_1 = require("../../../utils/environment-options");
const bundle_budget_1 = require("../../plugins/bundle-budget");
const named_chunks_plugin_1 = require("../../plugins/named-chunks-plugin");
const optimize_css_webpack_plugin_1 = require("../../plugins/optimize-css-webpack-plugin");
const scripts_webpack_plugin_1 = require("../../plugins/scripts-webpack-plugin");
const webpack_2 = require("../../plugins/webpack");
const find_up_1 = require("../../utilities/find-up");
const utils_2 = require("./utils");
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const TerserPlugin = require('terser-webpack-plugin');
// tslint:disable-next-line:no-big-function
function getCommonConfig(wco) {
const { root, projectRoot, buildOptions, tsConfig } = wco;
const { styles: stylesOptimization, scripts: scriptsOptimization } = buildOptions.optimization;
const { styles: stylesSourceMap, scripts: scriptsSourceMap, vendor: vendorSourceMap, } = buildOptions.sourceMap;
const extraPlugins = [];
const extraRules = [];
const entryPoints = {};
// determine hashing format
const hashFormat = utils_2.getOutputHashFormat(buildOptions.outputHashing || 'none');
const targetInFileName = utils_2.getEsVersionForFileName(tsConfig.options.target, buildOptions.esVersionInFileName);
if (buildOptions.main) {
const mainPath = path.resolve(root, buildOptions.main);
entryPoints['main'] = [mainPath];
if (buildOptions.experimentalRollupPass) {
// NOTE: the following are known problems with experimentalRollupPass
// - vendorChunk, commonChunk, namedChunks: these won't work, because by the time webpack
// sees the chunks, the context of where they came from is lost.
// - webWorkerTsConfig: workers must be imported via a root relative path (e.g.
// `app/search/search.worker`) instead of a relative path (`/search.worker`) because
// of the same reason as above.
// - loadChildren string syntax: doesn't work because rollup cannot follow the imports.
// Rollup options, except entry module, which is automatically inferred.
const rollupOptions = {};
// Add rollup plugins/rules.
extraRules.push({
test: mainPath,
// Ensure rollup loader executes after other loaders.
enforce: 'post',
use: [{
loader: webpack_2.WebpackRollupLoader,
options: rollupOptions,
}],
});
// Rollup bundles will include the dynamic System.import that was inside Angular and webpack
// will emit warnings because it can't resolve it. We just ignore it.
// TODO: maybe use https://webpack.js.org/configuration/stats/#statswarningsfilter instead.
// Ignore all "Critical dependency: the request of a dependency is an expression" warnings.
extraPlugins.push(new webpack_1.ContextReplacementPlugin(/./));
// Ignore "System.import() is deprecated" warnings for the main file and js files.
// Might still get them if @angular/core gets split into a lazy module.
extraRules.push({
test: mainPath,
enforce: 'post',
parser: { system: true },
});
extraRules.push({
test: /\.js$/,
enforce: 'post',
parser: { system: true },
});
}
}
const differentialLoadingMode = !!wco.differentialLoadingMode;
if (wco.buildOptions.platform !== 'server') {
if (differentialLoadingMode || tsConfig.options.target === typescript_1.ScriptTarget.ES5) {
const buildBrowserFeatures = new utils_1.BuildBrowserFeatures(projectRoot, tsConfig.options.target || typescript_1.ScriptTarget.ES5);
if (buildOptions.es5BrowserSupport ||
(buildOptions.es5BrowserSupport === undefined && buildBrowserFeatures.isEs5SupportNeeded())) {
const polyfillsChunkName = 'polyfills-es5';
entryPoints[polyfillsChunkName] = [path.join(__dirname, '..', 'es5-polyfills.js')];
if (differentialLoadingMode) {
// Add zone.js legacy support to the es5 polyfills
// This is a noop execution-wise if zone-evergreen is not used.
entryPoints[polyfillsChunkName].push('zone.js/dist/zone-legacy');
// Since the chunkFileName option schema does not allow the function overload, add a plugin
// that changes the name of the ES5 polyfills chunk to not include ES2015.
extraPlugins.push({
apply(compiler) {
compiler.hooks.compilation.tap('build-angular', compilation => {
// Webpack typings do not contain MainTemplate assetPath hook
// The webpack.Compilation assetPath hook is a noop in 4.x so the template must be used
// tslint:disable-next-line: no-any
compilation.mainTemplate.hooks.assetPath.tap('build-angular', (filename, data) => {
const assetName = typeof filename === 'function' ? filename(data) : filename;
const isMap = assetName && assetName.endsWith('.map');
return data.chunk && data.chunk.name === 'polyfills-es5'
? `polyfills-es5${hashFormat.chunk}.js${isMap ? '.map' : ''}`
: assetName;
});
});
},
});
}
if (!buildOptions.aot) {
if (differentialLoadingMode) {
entryPoints[polyfillsChunkName].push(path.join(__dirname, '..', 'jit-polyfills.js'));
}
entryPoints[polyfillsChunkName].push(path.join(__dirname, '..', 'es5-jit-polyfills.js'));
}
// If not performing a full differential build the polyfills need to be added to ES5 bundle
if (buildOptions.polyfills) {
entryPoints[polyfillsChunkName].push(path.resolve(root, buildOptions.polyfills));
}
}
}
if (buildOptions.polyfills) {
entryPoints['polyfills'] = [
...(entryPoints['polyfills'] || []),
path.resolve(root, buildOptions.polyfills),
];
}
if (!buildOptions.aot) {
entryPoints['polyfills'] = [
...(entryPoints['polyfills'] || []),
path.join(__dirname, '..', 'jit-polyfills.js'),
];
}
}
if (buildOptions.profile || process.env['NG_BUILD_PROFILING']) {
extraPlugins.push(new webpack_1.debug.ProfilingPlugin({
outputPath: path.resolve(root, `chrome-profiler-events${targetInFileName}.json`),
}));
}
// process global scripts
const globalScriptsByBundleName = utils_2.normalizeExtraEntryPoints(buildOptions.scripts, 'scripts').reduce((prev, curr) => {
const { bundleName, inject, input } = curr;
const resolvedPath = path.resolve(root, input);
if (!fs_1.existsSync(resolvedPath)) {
throw new Error(`Script file ${input} does not exist.`);
}
const existingEntry = prev.find(el => el.bundleName === bundleName);
if (existingEntry) {
if (existingEntry.inject && !inject) {
// All entries have to be lazy for the bundle to be lazy.
throw new Error(`The ${bundleName} bundle is mixing injected and non-injected scripts.`);
}
existingEntry.paths.push(resolvedPath);
}
else {
prev.push({
bundleName,
inject,
paths: [resolvedPath],
});
}
return prev;
}, []);
if (globalScriptsByBundleName.length > 0) {
// Add a new asset for each entry.
globalScriptsByBundleName.forEach(script => {
// Lazy scripts don't get a hash, otherwise they can't be loaded by name.
const hash = script.inject ? hashFormat.script : '';
const bundleName = script.bundleName;
extraPlugins.push(new scripts_webpack_plugin_1.ScriptsWebpackPlugin({
name: bundleName,
sourceMap: scriptsSourceMap,
filename: `${path.basename(bundleName)}${hash}.js`,
scripts: script.paths,
basePath: projectRoot,
}));
});
}
// process asset entries
if (buildOptions.assets.length) {
const copyWebpackPluginPatterns = buildOptions.assets.map((asset) => {
// Resolve input paths relative to workspace root and add slash at the end.
// tslint:disable-next-line: prefer-const
let { input, output, ignore = [], glob } = asset;
input = path.resolve(root, input).replace(/\\/g, '/');
input = input.endsWith('/') ? input : input + '/';
output = output.endsWith('/') ? output : output + '/';
if (output.startsWith('..')) {
throw new Error('An asset cannot be written to a location outside of the output path.');
}
return {
context: input,
// Now we remove starting slash to make Webpack place it from the output root.
to: output.replace(/^\//, ''),
from: glob,
noErrorOnMissing: true,
globOptions: {
dot: true,
ignore: [
'.gitkeep',
'**/.DS_Store',
'**/Thumbs.db',
// Negate patterns needs to be absolute because copy-webpack-plugin uses absolute globs which
// causes negate patterns not to match.
// See: https://github.com/webpack-contrib/copy-webpack-plugin/issues/498#issuecomment-639327909
...ignore,
].map(i => path.posix.join(input, i)),
},
};
});
extraPlugins.push(new CopyWebpackPlugin({
patterns: copyWebpackPluginPatterns,
}));
}
if (buildOptions.progress) {
extraPlugins.push(new ProgressPlugin({ profile: buildOptions.verbose }));
}
if (buildOptions.showCircularDependencies) {
extraPlugins.push(new CircularDependencyPlugin({
exclude: /([\\\/]node_modules[\\\/])|(ngfactory\.js$)/,
}));
}
if (buildOptions.statsJson) {
extraPlugins.push(new (class {
apply(compiler) {
compiler.hooks.emit.tap('angular-cli-stats', compilation => {
const data = JSON.stringify(compilation.getStats().toJson('verbose'));
compilation.assets[`stats${targetInFileName}.json`] = new webpack_sources_1.RawSource(data);
});
}
})());
}
if (buildOptions.namedChunks) {
extraPlugins.push(new named_chunks_plugin_1.NamedLazyChunksPlugin());
}
let sourceMapUseRule;
if ((scriptsSourceMap || stylesSourceMap) && vendorSourceMap) {
sourceMapUseRule = {
use: [
{
loader: require.resolve('source-map-loader'),
},
],
};
}
let buildOptimizerUseRule;
if (buildOptions.buildOptimizer) {
extraPlugins.push(new build_optimizer_1.BuildOptimizerWebpackPlugin());
buildOptimizerUseRule = {
use: [
{
loader: build_optimizer_1.buildOptimizerLoaderPath,
options: { sourceMap: scriptsSourceMap },
},
],
};
}
// Allow loaders to be in a node_modules nested inside the devkit/build-angular package.
// This is important in case loaders do not get hoisted.
// If this file moves to another location, alter potentialNodeModules as well.
const loaderNodeModules = find_up_1.findAllNodeModules(__dirname, projectRoot);
loaderNodeModules.unshift('node_modules');
// Load rxjs path aliases.
// https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md#build-and-treeshaking
let alias = {};
try {
const rxjsPathMappingImport = wco.supportES2015
? 'rxjs/_esm2015/path-mapping'
: 'rxjs/_esm5/path-mapping';
const rxPaths = require(require.resolve(rxjsPathMappingImport, { paths: [projectRoot] }));
alias = rxPaths();
}
catch (_a) { }
const extraMinimizers = [];
if (stylesOptimization) {
extraMinimizers.push(new optimize_css_webpack_plugin_1.OptimizeCssWebpackPlugin({
sourceMap: stylesSourceMap,
// component styles retain their original file name
test: file => /\.(?:css|scss|sass|less|styl)$/.test(file),
}));
}
if (scriptsOptimization) {
let angularGlobalDefinitions = {
ngDevMode: false,
ngI18nClosureMode: false,
};
// Try to load known global definitions from @angular/compiler-cli.
const GLOBAL_DEFS_FOR_TERSER = require('@angular/compiler-cli').GLOBAL_DEFS_FOR_TERSER;
if (GLOBAL_DEFS_FOR_TERSER) {
angularGlobalDefinitions = GLOBAL_DEFS_FOR_TERSER;
}
if (buildOptions.aot) {
// Also try to load AOT-only global definitions.
const GLOBAL_DEFS_FOR_TERSER_WITH_AOT = require('@angular/compiler-cli')
.GLOBAL_DEFS_FOR_TERSER_WITH_AOT;
if (GLOBAL_DEFS_FOR_TERSER_WITH_AOT) {
angularGlobalDefinitions = {
...angularGlobalDefinitions,
...GLOBAL_DEFS_FOR_TERSER_WITH_AOT,
};
}
}
// TODO: Investigate why this fails for some packages: wco.supportES2015 ? 6 : 5;
const terserEcma = 5;
const terserOptions = {
warnings: !!buildOptions.verbose,
safari10: true,
output: {
ecma: terserEcma,
// For differential loading, this is handled in the bundle processing.
// This should also work with just true but the experimental rollup support breaks without this check.
ascii_only: !differentialLoadingMode,
// default behavior (undefined value) is to keep only important comments (licenses, etc.)
comments: !buildOptions.extractLicenses && undefined,
webkit: true,
beautify: environment_options_1.shouldBeautify,
},
// On server, we don't want to compress anything. We still set the ngDevMode = false for it
// to remove dev code, and ngI18nClosureMode to remove Closure compiler i18n code
compress: environment_options_1.allowMinify &&
(buildOptions.platform == 'server'
? {
ecma: terserEcma,
global_defs: angularGlobalDefinitions,
keep_fnames: true,
}
: {
ecma: terserEcma,
pure_getters: buildOptions.buildOptimizer,
// PURE comments work best with 3 passes.
// See https://github.com/webpack/webpack/issues/2899#issuecomment-317425926.
passes: buildOptions.buildOptimizer ? 3 : 1,
global_defs: angularGlobalDefinitions,
}),
// We also want to avoid mangling on server.
// Name mangling is handled within the browser builder
mangle: environment_options_1.allowMangle && buildOptions.platform !== 'server' && !differentialLoadingMode,
};
const globalScriptsNames = globalScriptsByBundleName.map(s => s.bundleName);
extraMinimizers.push(new TerserPlugin({
sourceMap: scriptsSourceMap,
parallel: utils_1.maxWorkers,
cache: !environment_options_1.cachingDisabled && cache_path_1.findCachePath('terser-webpack'),
extractComments: false,
exclude: globalScriptsNames,
terserOptions,
}),
// Script bundles are fully optimized here in one step since they are never downleveled.
// They are shared between ES2015 & ES5 outputs so must support ES5.
new TerserPlugin({
sourceMap: scriptsSourceMap,
parallel: utils_1.maxWorkers,
cache: !environment_options_1.cachingDisabled && cache_path_1.findCachePath('terser-webpack'),
extractComments: false,
include: globalScriptsNames,
terserOptions: {
...terserOptions,
compress: environment_options_1.allowMinify && {
...terserOptions.compress,
ecma: 5,
},
output: {
...terserOptions.output,
ecma: 5,
},
mangle: environment_options_1.allowMangle && buildOptions.platform !== 'server',
},
}));
}
if (wco.tsConfig.options.target !== undefined &&
wco.tsConfig.options.target >= typescript_1.ScriptTarget.ES2017) {
wco.logger.warn(core_1.tags.stripIndent `
WARNING: Zone.js does not support native async/await in ES2017.
These blocks are not intercepted by zone.js and will not triggering change detection.
See: https://github.com/angular/zone.js/pull/1140 for more information.
`);
}
return {
mode: scriptsOptimization || stylesOptimization ? 'production' : 'development',
devtool: false,
profile: buildOptions.statsJson,
resolve: {
extensions: ['.ts', '.tsx', '.mjs', '.js'],
symlinks: !buildOptions.preserveSymlinks,
modules: [wco.tsConfig.options.baseUrl || projectRoot, 'node_modules'],
alias,
},
resolveLoader: {
symlinks: !buildOptions.preserveSymlinks,
modules: loaderNodeModules,
},
context: projectRoot,
entry: entryPoints,
output: {
futureEmitAssets: true,
path: path.resolve(root, buildOptions.outputPath),
publicPath: buildOptions.deployUrl,
filename: `[name]${targetInFileName}${hashFormat.chunk}.js`,
},
watch: buildOptions.watch,
watchOptions: {
poll: buildOptions.poll,
ignored: buildOptions.poll === undefined ? undefined : /[\\\/]node_modules[\\\/]/,
},
performance: {
hints: false,
},
module: {
// Show an error for missing exports instead of a warning.
strictExportPresence: true,
rules: [
{
test: /\.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/,
loader: require.resolve('file-loader'),
options: {
name: `[name]${hashFormat.file}.[ext]`,
// Re-use emitted files from browser builder on the server.
emitFile: wco.buildOptions.platform !== 'server',
},
},
{
// Mark files inside `@angular/core` as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear.
test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
},
{
test: /\.js$/,
// Factory files are processed by BO in the rules added in typescript.ts.
exclude: /(ngfactory|ngstyle)\.js$/,
...buildOptimizerUseRule,
},
{
test: /\.js$/,
exclude: /(ngfactory|ngstyle)\.js$/,
enforce: 'pre',
...sourceMapUseRule,
},
...extraRules,
],
},
optimization: {
noEmitOnErrors: true,
minimizer: [
new webpack_1.HashedModuleIdsPlugin(),
...extraMinimizers,
].concat(differentialLoadingMode ? [
// Budgets are computed after differential builds, not via a plugin.
// https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_angular/src/browser/index.ts
] : [
// Non differential builds should be computed here, as a plugin.
new bundle_budget_1.BundleBudgetPlugin({ budgets: buildOptions.budgets }),
]),
},
plugins: [
// Always replace the context for the System.import in angular/core to prevent warnings.
// https://github.com/angular/angular/issues/11580
// With VE the correct context is added in @ngtools/webpack, but Ivy doesn't need it at all.
new webpack_1.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)/),
...extraPlugins,
],
};
}
exports.getCommonConfig = getCommonConfig;
/**
* @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
*/
export * from './browser';
export * from './common';
export * from './server';
export * from './styles';
export * from './test';
export * from './typescript';
export * from './utils';
export * from './stats';
export * from './worker';
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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
*/
__export(require("./browser"));
__export(require("./common"));
__export(require("./server"));
__export(require("./styles"));
__export(require("./test"));
__export(require("./typescript"));
__export(require("./utils"));
__export(require("./stats"));
__export(require("./worker"));
import { Configuration } from 'webpack';
import { WebpackConfigOptions } from '../build-options';
/**
* Returns a partial specific to creating a bundle for node
* @param wco Options which are include the build options and app config
*/
export declare function getServerConfig(wco: WebpackConfigOptions): Configuration;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 path_1 = require("path");
const webpack_1 = require("webpack");
const utils_1 = require("./utils");
/**
* Returns a partial specific to creating a bundle for node
* @param wco Options which are include the build options and app config
*/
function getServerConfig(wco) {
const { sourceMap, bundleDependencies, externalDependencies = [], } = wco.buildOptions;
const extraPlugins = [];
if (sourceMap) {
const { scripts, styles, hidden } = sourceMap;
if (scripts || styles) {
extraPlugins.push(utils_1.getSourceMapDevTool(scripts, styles, hidden));
}
}
const config = {
resolve: {
mainFields: [...(wco.supportES2015 ? ['es2015'] : []), 'main', 'module'],
},
target: 'node',
output: {
libraryTarget: 'commonjs',
},
plugins: [
// Fixes Critical dependency: the request of a dependency is an expression
new webpack_1.ContextReplacementPlugin(/@?hapi(\\|\/)/),
new webpack_1.ContextReplacementPlugin(/express(\\|\/)/),
...extraPlugins,
],
node: false,
};
if (bundleDependencies) {
config.externals = [...externalDependencies];
}
else {
config.externals = [
...externalDependencies,
(context, request, callback) => {
// Absolute & Relative paths are not externals
if (request.startsWith('./') || path_1.isAbsolute(request)) {
callback();
return;
}
try {
require.resolve(request);
callback(null, request);
}
catch (_a) {
// Node couldn't find it, so it must be user-aliased
callback();
}
},
];
}
return config;
}
exports.getServerConfig = getServerConfig;
/**
* @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 { WebpackConfigOptions } from '../build-options';
export declare function getWebpackStatsConfig(verbose?: boolean): {
colors: boolean;
hash: boolean;
timings: boolean;
chunks: boolean;
chunkModules: boolean;
children: boolean;
modules: boolean;
reasons: boolean;
warnings: boolean;
errors: boolean;
assets: boolean;
version: boolean;
errorDetails: boolean;
moduleTrace: boolean;
};
export declare function getStatsConfig(wco: WebpackConfigOptions): {
stats: {
colors: boolean;
hash: boolean;
timings: boolean;
chunks: boolean;
chunkModules: boolean;
children: boolean;
modules: boolean;
reasons: boolean;
warnings: boolean;
errors: boolean;
assets: boolean;
version: boolean;
errorDetails: boolean;
moduleTrace: boolean;
};
};
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const webpackOutputOptions = {
colors: true,
hash: true,
timings: true,
chunks: true,
chunkModules: false,
children: false,
modules: false,
reasons: false,
warnings: true,
errors: true,
assets: true,
version: false,
errorDetails: false,
moduleTrace: false,
};
const verboseWebpackOutputOptions = {
// The verbose output will most likely be piped to a file, so colors just mess it up.
colors: false,
usedExports: true,
maxModules: Infinity,
optimizationBailout: true,
reasons: true,
children: true,
assets: true,
version: true,
chunkModules: true,
errorDetails: true,
moduleTrace: true,
};
function getWebpackStatsConfig(verbose = false) {
return verbose
? Object.assign(webpackOutputOptions, verboseWebpackOutputOptions)
: webpackOutputOptions;
}
exports.getWebpackStatsConfig = getWebpackStatsConfig;
function getStatsConfig(wco) {
const verbose = !!wco.buildOptions.verbose;
return { stats: getWebpackStatsConfig(verbose) };
}
exports.getStatsConfig = getStatsConfig;
/**
* @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 webpack from 'webpack';
import { WebpackConfigOptions } from '../build-options';
export declare function getStylesConfig(wco: WebpackConfigOptions): {
entry: {
[key: string]: string[];
};
module: {
rules: webpack.RuleSetRule[];
};
plugins: webpack.Plugin[];
};
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const webpack_1 = require("../../plugins/webpack");
const utils_1 = require("./utils");
const autoprefixer = require('autoprefixer');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const postcssImports = require('postcss-import');
// tslint:disable-next-line:no-big-function
function getStylesConfig(wco) {
const { root, buildOptions } = wco;
const entryPoints = {};
const globalStylePaths = [];
const extraPlugins = [
new webpack_1.AnyComponentStyleBudgetChecker(buildOptions.budgets),
];
const cssSourceMap = buildOptions.sourceMap.styles;
// Determine hashing format.
const hashFormat = utils_1.getOutputHashFormat(buildOptions.outputHashing);
const postcssPluginCreator = function (loader) {
return [
postcssImports({
resolve: (url) => (url.startsWith('~') ? url.substr(1) : url),
load: (filename) => {
return new Promise((resolve, reject) => {
loader.fs.readFile(filename, (err, data) => {
if (err) {
reject(err);
return;
}
const content = data.toString();
resolve(content);
});
});
},
}),
webpack_1.PostcssCliResources({
baseHref: buildOptions.baseHref,
deployUrl: buildOptions.deployUrl,
resourcesOutputPath: buildOptions.resourcesOutputPath,
loader,
rebaseRootRelative: buildOptions.rebaseRootRelativeCssUrls,
filename: `[name]${hashFormat.file}.[ext]`,
emitFile: buildOptions.platform !== 'server',
}),
autoprefixer(),
];
};
// use includePaths from appConfig
const includePaths = [];
let lessPathOptions = {};
if (buildOptions.stylePreprocessorOptions &&
buildOptions.stylePreprocessorOptions.includePaths &&
buildOptions.stylePreprocessorOptions.includePaths.length > 0) {
buildOptions.stylePreprocessorOptions.includePaths.forEach((includePath) => includePaths.push(path.resolve(root, includePath)));
lessPathOptions = {
paths: includePaths,
};
}
// Process global styles.
if (buildOptions.styles.length > 0) {
const chunkNames = [];
utils_1.normalizeExtraEntryPoints(buildOptions.styles, 'styles').forEach(style => {
const resolvedPath = path.resolve(root, style.input);
// Add style entry points.
if (entryPoints[style.bundleName]) {
entryPoints[style.bundleName].push(resolvedPath);
}
else {
entryPoints[style.bundleName] = [resolvedPath];
}
// Add non injected styles to the list.
if (!style.inject) {
chunkNames.push(style.bundleName);
}
// Add global css paths.
globalStylePaths.push(resolvedPath);
});
if (chunkNames.length > 0) {
// Add plugin to remove hashes from lazy styles.
extraPlugins.push(new webpack_1.RemoveHashPlugin({ chunkNames, hashFormat }));
}
}
let sassImplementation;
try {
// tslint:disable-next-line:no-implicit-dependencies
sassImplementation = require('node-sass');
}
catch (_a) {
sassImplementation = require('sass');
}
// set base rules to derive final rules from
const baseRules = [
{ test: /\.css$/, use: [] },
{
test: /\.scss$|\.sass$/,
use: [
{
loader: require.resolve('sass-loader'),
options: {
implementation: sassImplementation,
sourceMap: cssSourceMap,
sassOptions: {
// bootstrap-sass requires a minimum precision of 8
precision: 8,
includePaths,
// Use expanded as otherwise sass will remove comments that are needed for autoprefixer
// Ex: /* autoprefixer grid: autoplace */
// tslint:disable-next-line: max-line-length
// See: https://github.com/webpack-contrib/sass-loader/blob/45ad0be17264ceada5f0b4fb87e9357abe85c4ff/src/getSassOptions.js#L68-L70
outputStyle: 'expanded',
},
},
},
],
},
{
test: /\.less$/,
use: [
{
loader: require.resolve('less-loader'),
options: {
sourceMap: cssSourceMap,
javascriptEnabled: true,
...lessPathOptions,
},
},
],
},
{
test: /\.styl$/,
use: [
{
loader: require.resolve('stylus-loader'),
options: {
sourceMap: cssSourceMap,
paths: includePaths,
},
},
],
},
];
// load component css as raw strings
const rules = baseRules.map(({ test, use }) => ({
exclude: globalStylePaths,
test,
use: [
{ loader: require.resolve('raw-loader') },
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'embedded',
plugins: postcssPluginCreator,
sourceMap: cssSourceMap
// Never use component css sourcemap when style optimizations are on.
// It will just increase bundle size without offering good debug experience.
&& !buildOptions.optimization.styles
// Inline all sourcemap types except hidden ones, which are the same as no sourcemaps
// for component css.
&& !buildOptions.sourceMap.hidden ? 'inline' : false,
},
},
...use,
],
}));
// load global css as css files
if (globalStylePaths.length > 0) {
rules.push(...baseRules.map(({ test, use }) => {
return {
include: globalStylePaths,
test,
use: [
buildOptions.extractCss ? MiniCssExtractPlugin.loader : require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
url: false,
sourceMap: cssSourceMap,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: buildOptions.extractCss ? 'extracted' : 'embedded',
plugins: postcssPluginCreator,
sourceMap: cssSourceMap && !buildOptions.extractCss && !buildOptions.sourceMap.hidden
? 'inline'
: cssSourceMap,
},
},
...use,
],
};
}));
}
if (buildOptions.extractCss) {
extraPlugins.push(
// extract global css from js files into own css file
new MiniCssExtractPlugin({ filename: `[name]${hashFormat.extract}.css` }),
// suppress empty .js files in css only entry points
new webpack_1.SuppressExtractedTextChunksWebpackPlugin());
}
return {
entry: entryPoints,
module: { rules },
plugins: extraPlugins,
};
}
exports.getStylesConfig = getStylesConfig;
/**
* @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 webpack from 'webpack';
import { WebpackConfigOptions, WebpackTestOptions } from '../build-options';
export declare function getTestConfig(wco: WebpackConfigOptions<WebpackTestOptions>): webpack.Configuration;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const glob = require("glob");
const path = require("path");
const utils_1 = require("./utils");
function getTestConfig(wco) {
const { root, buildOptions, sourceRoot: include } = wco;
const extraRules = [];
const extraPlugins = [];
if (buildOptions.codeCoverage) {
const codeCoverageExclude = buildOptions.codeCoverageExclude;
const exclude = [
/\.(e2e|spec)\.tsx?$/,
/node_modules/,
];
if (codeCoverageExclude) {
codeCoverageExclude.forEach((excludeGlob) => {
const excludeFiles = glob
.sync(path.join(root, excludeGlob), { nodir: true })
.map(file => path.normalize(file));
exclude.push(...excludeFiles);
});
}
extraRules.push({
test: /\.(jsx?|tsx?)$/,
loader: require.resolve('@jsdevtools/coverage-istanbul-loader'),
options: { esModules: true },
enforce: 'post',
exclude,
include,
});
}
if (wco.buildOptions.sourceMap) {
const { styles, scripts } = wco.buildOptions.sourceMap;
if (styles || scripts) {
extraPlugins.push(utils_1.getSourceMapDevTool(scripts, styles, false, true));
}
}
return {
mode: 'development',
resolve: {
mainFields: [
...(wco.supportES2015 ? ['es2015'] : []),
'browser', 'module', 'main',
],
},
devtool: buildOptions.sourceMap ? false : 'eval',
entry: {
main: path.resolve(root, buildOptions.main),
},
module: {
rules: extraRules,
},
plugins: extraPlugins,
optimization: {
splitChunks: {
chunks: ((chunk) => !utils_1.isPolyfillsEntry(chunk.name)),
cacheGroups: {
vendors: false,
vendor: {
name: 'vendor',
chunks: 'initial',
test: (module, chunks) => {
const moduleName = module.nameForCondition ? module.nameForCondition() : '';
return /[\\/]node_modules[\\/]/.test(moduleName)
&& !chunks.some(({ name }) => utils_1.isPolyfillsEntry(name));
},
},
},
},
},
};
}
exports.getTestConfig = getTestConfig;
import { AngularCompilerPlugin } from '@ngtools/webpack';
import { WebpackConfigOptions } from '../build-options';
export declare function getNonAotConfig(wco: WebpackConfigOptions): {
module: {
rules: {
test: RegExp;
loader: string;
}[];
};
plugins: AngularCompilerPlugin[];
};
export declare function getAotConfig(wco: WebpackConfigOptions, i18nExtract?: boolean): {
module: {
rules: {
test: RegExp;
use: any[];
}[];
};
plugins: AngularCompilerPlugin[];
};
export declare function getTypescriptWorkerPlugin(wco: WebpackConfigOptions, workerTsConfigPath: string): AngularCompilerPlugin;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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
*/
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
const build_optimizer_1 = require("@angular-devkit/build-optimizer");
const path = require("path");
const webpack_1 = require("@ngtools/webpack");
function _pluginOptionsOverrides(buildOptions, pluginOptions) {
const compilerOptions = {
...(pluginOptions.compilerOptions || {})
};
const hostReplacementPaths = {};
if (buildOptions.fileReplacements) {
for (const replacement of buildOptions.fileReplacements) {
hostReplacementPaths[replacement.replace] = replacement.with;
}
}
if (buildOptions.preserveSymlinks) {
compilerOptions.preserveSymlinks = true;
}
return {
...pluginOptions,
hostReplacementPaths,
compilerOptions
};
}
function _createAotPlugin(wco, options, i18nExtract = false) {
const { root, buildOptions } = wco;
const i18nInFile = buildOptions.i18nFile
? path.resolve(root, buildOptions.i18nFile)
: undefined;
const i18nFileAndFormat = i18nExtract
? {
i18nOutFile: buildOptions.i18nFile,
i18nOutFormat: buildOptions.i18nFormat,
} : {
i18nInFile: i18nInFile,
i18nInFormat: buildOptions.i18nFormat,
};
const compilerOptions = options.compilerOptions || {};
if (i18nExtract) {
// Extraction of i18n is still using the legacy VE pipeline
compilerOptions.enableIvy = false;
}
const additionalLazyModules = {};
if (buildOptions.lazyModules) {
for (const lazyModule of buildOptions.lazyModules) {
additionalLazyModules[lazyModule] = path.resolve(root, lazyModule);
}
}
let pluginOptions = {
mainPath: path.join(root, buildOptions.main),
...i18nFileAndFormat,
locale: buildOptions.i18nLocale,
platform: buildOptions.platform === 'server' ? webpack_1.PLATFORM.Server : webpack_1.PLATFORM.Browser,
missingTranslation: buildOptions.i18nMissingTranslation,
sourceMap: buildOptions.sourceMap.scripts,
additionalLazyModules,
nameLazyFiles: buildOptions.namedChunks,
forkTypeChecker: buildOptions.forkTypeChecker,
contextElementDependencyConstructor: require('webpack/lib/dependencies/ContextElementDependency'),
logger: wco.logger,
directTemplateLoading: true,
...options,
compilerOptions,
};
pluginOptions = _pluginOptionsOverrides(buildOptions, pluginOptions);
return new webpack_1.AngularCompilerPlugin(pluginOptions);
}
function getNonAotConfig(wco) {
const { tsConfigPath } = wco;
return {
module: { rules: [{ test: /\.tsx?$/, loader: webpack_1.NgToolsLoader }] },
plugins: [_createAotPlugin(wco, { tsConfigPath, skipCodeGeneration: true })]
};
}
exports.getNonAotConfig = getNonAotConfig;
function getAotConfig(wco, i18nExtract = false) {
const { tsConfigPath, buildOptions } = wco;
const loaders = [webpack_1.NgToolsLoader];
if (buildOptions.buildOptimizer) {
loaders.unshift({
loader: build_optimizer_1.buildOptimizerLoaderPath,
options: { sourceMap: buildOptions.sourceMap.scripts }
});
}
const test = /(?:\.ngfactory\.js|\.ngstyle\.js|\.tsx?)$/;
const optimize = wco.buildOptions.optimization.scripts;
return {
module: { rules: [{ test, use: loaders }] },
plugins: [
_createAotPlugin(wco, { tsConfigPath, emitClassMetadata: !optimize, emitNgModuleScope: !optimize }, i18nExtract),
],
};
}
exports.getAotConfig = getAotConfig;
function getTypescriptWorkerPlugin(wco, workerTsConfigPath) {
const { buildOptions } = wco;
let pluginOptions = {
skipCodeGeneration: true,
tsConfigPath: workerTsConfigPath,
mainPath: undefined,
platform: webpack_1.PLATFORM.Browser,
sourceMap: buildOptions.sourceMap.scripts,
forkTypeChecker: buildOptions.forkTypeChecker,
contextElementDependencyConstructor: require('webpack/lib/dependencies/ContextElementDependency'),
logger: wco.logger,
// Run no transformers.
platformTransformers: [],
// Don't attempt lazy route discovery.
discoverLazyRoutes: false,
};
pluginOptions = _pluginOptionsOverrides(buildOptions, pluginOptions);
return new webpack_1.AngularCompilerPlugin(pluginOptions);
}
exports.getTypescriptWorkerPlugin = getTypescriptWorkerPlugin;
/**
* @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 { ExtraEntryPoint, ExtraEntryPointClass } from '../../../browser/schema';
import { SourceMapDevToolPlugin } from 'webpack';
import { ScriptTarget } from 'typescript';
export interface HashFormat {
chunk: string;
extract: string;
file: string;
script: string;
}
export declare function getOutputHashFormat(option: string, length?: number): HashFormat;
declare type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
export declare type NormalizedEntryPoint = Required<Omit<ExtraEntryPointClass, 'lazy'>>;
export declare function normalizeExtraEntryPoints(extraEntryPoints: ExtraEntryPoint[], defaultBundleName: string): NormalizedEntryPoint[];
export declare function getSourceMapDevTool(scriptsSourceMap: boolean | undefined, stylesSourceMap: boolean | undefined, hiddenSourceMap?: boolean, inlineSourceMap?: boolean): SourceMapDevToolPlugin;
/**
* Returns an ES version file suffix to differentiate between various builds.
*/
export declare function getEsVersionForFileName(scriptTargetOverride: ScriptTarget | undefined, esVersionInFileName?: boolean): string;
export declare function isPolyfillsEntry(name: string): boolean;
export {};
"use strict";
/**
* @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
*/
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@angular-devkit/core");
const webpack_1 = require("webpack");
const typescript_1 = require("typescript");
function getOutputHashFormat(option, length = 20) {
const hashFormats = {
none: { chunk: '', extract: '', file: '', script: '' },
media: { chunk: '', extract: '', file: `.[hash:${length}]`, script: '' },
bundles: {
chunk: `.[chunkhash:${length}]`,
extract: `.[contenthash:${length}]`,
file: '',
script: `.[hash:${length}]`,
},
all: {
chunk: `.[chunkhash:${length}]`,
extract: `.[contenthash:${length}]`,
file: `.[hash:${length}]`,
script: `.[hash:${length}]`,
},
};
return hashFormats[option] || hashFormats['none'];
}
exports.getOutputHashFormat = getOutputHashFormat;
function normalizeExtraEntryPoints(extraEntryPoints, defaultBundleName) {
return extraEntryPoints.map(entry => {
let normalizedEntry;
if (typeof entry === 'string') {
normalizedEntry = { input: entry, inject: true, bundleName: defaultBundleName };
}
else {
const { lazy, inject = true, ...newEntry } = entry;
const injectNormalized = entry.lazy !== undefined ? !entry.lazy : inject;
let bundleName;
if (entry.bundleName) {
bundleName = entry.bundleName;
}
else if (!injectNormalized) {
// Lazy entry points use the file name as bundle name.
bundleName = core_1.basename(core_1.normalize(entry.input.replace(/\.(js|css|scss|sass|less|styl)$/i, '')));
}
else {
bundleName = defaultBundleName;
}
normalizedEntry = { ...newEntry, inject: injectNormalized, bundleName };
}
return normalizedEntry;
});
}
exports.normalizeExtraEntryPoints = normalizeExtraEntryPoints;
function getSourceMapDevTool(scriptsSourceMap, stylesSourceMap, hiddenSourceMap = false, inlineSourceMap = false) {
const include = [];
if (scriptsSourceMap) {
include.push(/js$/);
}
if (stylesSourceMap) {
include.push(/css$/);
}
return new webpack_1.SourceMapDevToolPlugin({
filename: inlineSourceMap ? undefined : '[file].map',
include,
// We want to set sourceRoot to `webpack:///` for non
// inline sourcemaps as otherwise paths to sourcemaps will be broken in browser
// `webpack:///` is needed for Visual Studio breakpoints to work properly as currently
// there is no way to set the 'webRoot'
sourceRoot: inlineSourceMap ? '' : 'webpack:///',
moduleFilenameTemplate: '[resource-path]',
append: hiddenSourceMap ? false : undefined,
});
}
exports.getSourceMapDevTool = getSourceMapDevTool;
/**
* Returns an ES version file suffix to differentiate between various builds.
*/
function getEsVersionForFileName(scriptTargetOverride, esVersionInFileName = false) {
if (!esVersionInFileName || scriptTargetOverride === undefined) {
return '';
}
if (scriptTargetOverride === typescript_1.ScriptTarget.ESNext) {
return '-esnext';
}
return '-' + typescript_1.ScriptTarget[scriptTargetOverride].toLowerCase();
}
exports.getEsVersionForFileName = getEsVersionForFileName;
function isPolyfillsEntry(name) {
return name === 'polyfills' || name === 'polyfills-es5';
}
exports.isPolyfillsEntry = isPolyfillsEntry;
import { Configuration } from 'webpack';
import { WebpackConfigOptions } from '../build-options';
export declare function getWorkerConfig(wco: WebpackConfigOptions): Configuration;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 path_1 = require("path");
const typescript_1 = require("./typescript");
const WorkerPlugin = require('worker-plugin');
function getWorkerConfig(wco) {
const { buildOptions } = wco;
if (!buildOptions.webWorkerTsConfig) {
return {};
}
if (typeof buildOptions.webWorkerTsConfig != 'string') {
throw new Error('The `webWorkerTsConfig` must be a string.');
}
const workerTsConfigPath = path_1.resolve(wco.root, buildOptions.webWorkerTsConfig);
return {
plugins: [new WorkerPlugin({
globalObject: false,
plugins: [typescript_1.getTypescriptWorkerPlugin(wco, workerTsConfigPath)],
})],
};
}
exports.getWorkerConfig = getWorkerConfig;
/**
* @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 { Compiler, Plugin } from 'webpack';
import { Budget } from '../../../src/browser/schema';
/**
* Check budget sizes for component styles by emitting a warning or error if a
* budget is exceeded by a particular component's styles.
*/
export declare class AnyComponentStyleBudgetChecker implements Plugin {
private readonly budgets;
constructor(budgets: Budget[]);
apply(compiler: Compiler): void;
}
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const schema_1 = require("../../../src/browser/schema");
const bundle_calculator_1 = require("../utilities/bundle-calculator");
const PLUGIN_NAME = 'AnyComponentStyleBudgetChecker';
/**
* Check budget sizes for component styles by emitting a warning or error if a
* budget is exceeded by a particular component's styles.
*/
class AnyComponentStyleBudgetChecker {
constructor(budgets) {
this.budgets = budgets.filter((budget) => budget.type === schema_1.Type.AnyComponentStyle);
}
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
compilation.hooks.afterOptimizeChunkAssets.tap(PLUGIN_NAME, () => {
// In AOT compilations component styles get processed in child compilations.
// tslint:disable-next-line: no-any
const parentCompilation = compilation.compiler.parentCompilation;
if (!parentCompilation) {
return;
}
const cssExtensions = [
'.css',
'.scss',
'.less',
'.styl',
'.sass',
];
const componentStyles = Object.keys(compilation.assets)
.filter((name) => cssExtensions.includes(path.extname(name)))
.map((name) => ({
size: compilation.assets[name].size(),
label: name,
}));
const thresholds = flatMap(this.budgets, (budget) => bundle_calculator_1.calculateThresholds(budget));
for (const { size, label } of componentStyles) {
for (const { severity, message } of bundle_calculator_1.checkThresholds(thresholds[Symbol.iterator](), size, label)) {
switch (severity) {
case bundle_calculator_1.ThresholdSeverity.Warning:
compilation.warnings.push(message);
break;
case bundle_calculator_1.ThresholdSeverity.Error:
compilation.errors.push(message);
break;
default:
assertNever(severity);
break;
}
}
}
});
});
}
}
exports.AnyComponentStyleBudgetChecker = AnyComponentStyleBudgetChecker;
function assertNever(input) {
throw new Error(`Unexpected call to assertNever() with input: ${JSON.stringify(input, null /* replacer */, 4 /* tabSize */)}`);
}
function flatMap(list, mapper) {
return [].concat(...list.map(mapper).map((iterator) => Array.from(iterator)));
}
/**
* @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 { Compiler } from 'webpack';
import { Budget } from '../../browser/schema';
export interface BundleBudgetPluginOptions {
budgets: Budget[];
}
export declare class BundleBudgetPlugin {
private options;
constructor(options: BundleBudgetPluginOptions);
apply(compiler: Compiler): void;
private runChecks;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const bundle_calculator_1 = require("../utilities/bundle-calculator");
class BundleBudgetPlugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
const { budgets } = this.options;
if (!budgets || budgets.length === 0) {
return;
}
compiler.hooks.afterEmit.tap('BundleBudgetPlugin', (compilation) => {
this.runChecks(budgets, compilation);
});
}
runChecks(budgets, compilation) {
// No process bundle results because this plugin is only used when differential
// builds are disabled.
const processResults = [];
const stats = compilation.getStats().toJson();
for (const { severity, message } of bundle_calculator_1.checkBudgets(budgets, stats, processResults)) {
switch (severity) {
case bundle_calculator_1.ThresholdSeverity.Warning:
compilation.warnings.push(`budgets: ${message}`);
break;
case bundle_calculator_1.ThresholdSeverity.Error:
compilation.errors.push(`budgets: ${message}`);
break;
}
}
}
}
exports.BundleBudgetPlugin = BundleBudgetPlugin;
import { Compiler } from 'webpack';
import { CrossOriginValue } from '../utilities/index-file/augment-index-html';
import { IndexHtmlTransform } from '../utilities/index-file/write-index-html';
export interface IndexHtmlWebpackPluginOptions {
input: string;
output: string;
baseHref?: string;
entrypoints: string[];
deployUrl?: string;
sri: boolean;
noModuleEntrypoints: string[];
moduleEntrypoints: string[];
postTransform?: IndexHtmlTransform;
crossOrigin?: CrossOriginValue;
lang?: string;
}
export declare class IndexHtmlWebpackPlugin {
private _options;
constructor(options?: Partial<IndexHtmlWebpackPluginOptions>);
apply(compiler: Compiler): void;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 path = require("path");
const webpack_sources_1 = require("webpack-sources");
const augment_index_html_1 = require("../utilities/index-file/augment-index-html");
const strip_bom_1 = require("../utilities/strip-bom");
function readFile(filename, compilation) {
return new Promise((resolve, reject) => {
compilation.inputFileSystem.readFile(filename, (err, data) => {
if (err) {
reject(err);
return;
}
resolve(strip_bom_1.stripBom(data.toString()));
});
});
}
class IndexHtmlWebpackPlugin {
constructor(options) {
this._options = {
input: 'index.html',
output: 'index.html',
entrypoints: ['polyfills', 'main'],
noModuleEntrypoints: [],
moduleEntrypoints: [],
sri: false,
...options,
};
}
apply(compiler) {
compiler.hooks.emit.tapPromise('index-html-webpack-plugin', async (compilation) => {
// Get input html file
const inputContent = await readFile(this._options.input, compilation);
compilation.fileDependencies.add(this._options.input);
// Get all files for selected entrypoints
const files = [];
const noModuleFiles = [];
const moduleFiles = [];
for (const [entryName, entrypoint] of compilation.entrypoints) {
const entryFiles = ((entrypoint && entrypoint.getFiles()) || []).map((f) => ({
name: entryName,
file: f,
extension: path.extname(f),
}));
if (this._options.noModuleEntrypoints.includes(entryName)) {
noModuleFiles.push(...entryFiles);
}
else if (this._options.moduleEntrypoints.includes(entryName)) {
moduleFiles.push(...entryFiles);
}
else {
files.push(...entryFiles);
}
}
const loadOutputFile = (name) => compilation.assets[name].source();
let indexSource = await augment_index_html_1.augmentIndexHtml({
input: this._options.input,
inputContent,
baseHref: this._options.baseHref,
deployUrl: this._options.deployUrl,
sri: this._options.sri,
crossOrigin: this._options.crossOrigin,
files,
noModuleFiles,
loadOutputFile,
moduleFiles,
entrypoints: this._options.entrypoints,
lang: this._options.lang,
});
if (this._options.postTransform) {
indexSource = await this._options.postTransform(indexSource);
}
// Add to compilation assets
compilation.assets[this._options.output] = new webpack_sources_1.RawSource(indexSource);
});
}
}
exports.IndexHtmlWebpackPlugin = IndexHtmlWebpackPlugin;
<!DOCTYPE html>
<!--
This is the execution context.
Loaded within the iframe.
Reloaded before every execution run.
-->
<html>
<head>
<title></title>
<base href="/">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
</head>
<body>
<!-- The scripts need to be in the body DOM element, as some test running frameworks need the body
to have already been created so they can insert their magic into it. For example, if loaded
before body, Angular Scenario test framework fails to find the body and crashes and burns in
an epic manner. -->
<script src="context.js"></script>
<script type="text/javascript">
// Configure our Karma and set up bindings
%CLIENT_CONFIG%
window.__karma__.setupContext(window);
// All served files with the latest timestamps
%MAPPINGS%
</script>
<script src="_karma_webpack_/runtime.js" crossorigin="anonymous"></script>
<script src="_karma_webpack_/polyfills-es5.js" crossorigin="anonymous" nomodule></script>
<script src="_karma_webpack_/polyfills.js" crossorigin="anonymous"></script>
<!-- Dynamically replaced with <script> tags -->
%SCRIPTS%
<script src="_karma_webpack_/styles.js" crossorigin="anonymous"></script>
<script src="_karma_webpack_/scripts.js" crossorigin="anonymous"></script>
<script src="_karma_webpack_/vendor.js" crossorigin="anonymous"></script>
<script src="_karma_webpack_/main.js" crossorigin="anonymous"></script>
<script type="text/javascript">
window.__karma__.loaded();
</script>
</body>
</html>
<!doctype html>
<!--
This file is almost the same as context.html - loads all source files,
but its purpose is to be loaded in the main frame (not within an iframe),
just for immediate execution, without reporting to Karma server.
-->
<html>
<head>
%X_UA_COMPATIBLE%
<title>Karma DEBUG RUNNER</title>
<link href="favicon.ico" rel="icon" type="image/x-icon" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
</head>
<body>
<!-- The scripts need to be at the end of body, so that some test running frameworks
(Angular Scenario, for example) need the body to be loaded so that it can insert its magic
into it. If it is before body, then it fails to find the body and crashes and burns in an epic
manner. -->
<script src="context.js"></script>
<script src="debug.js"></script>
<script type="text/javascript">
// Configure our Karma
%CLIENT_CONFIG%
// All served files with the latest timestamps
%MAPPINGS%
</script>
<script src="_karma_webpack_/runtime.js" crossorigin="anonymous"></script>
<script src="_karma_webpack_/polyfills-es5.js" crossorigin="anonymous" nomodule></script>
<script src="_karma_webpack_/polyfills.js" crossorigin="anonymous"></script>
<!-- Dynamically replaced with <script> tags -->
%SCRIPTS%
<script src="_karma_webpack_/styles.js" crossorigin="anonymous"></script>
<script src="_karma_webpack_/scripts.js" crossorigin="anonymous"></script>
<script src="_karma_webpack_/vendor.js" crossorigin="anonymous"></script>
<script src="_karma_webpack_/main.js" crossorigin="anonymous"></script>
<script type="text/javascript">
window.__karma__.loaded();
</script>
</body>
</html>
/**
* @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
*/
export declare class KarmaWebpackFailureCb {
private callback;
constructor(callback: (error: string | undefined, errors: string[]) => void);
apply(compiler: any): void;
}
"use strict";
/**
* @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
*/
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
Object.defineProperty(exports, "__esModule", { value: true });
// Force Webpack to throw compilation errors. Useful with karma-webpack when in single-run mode.
// Workaround for https://github.com/webpack-contrib/karma-webpack/issues/66
class KarmaWebpackFailureCb {
constructor(callback) {
this.callback = callback;
}
apply(compiler) {
compiler.hooks.done.tap('KarmaWebpackFailureCb', (stats) => {
if (stats.compilation.errors.length > 0) {
this.callback(undefined, stats.compilation.errors.map((error) => error.message ? error.message : error.toString()));
}
});
}
}
exports.KarmaWebpackFailureCb = KarmaWebpackFailureCb;
/**
* @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
*/
export {};
"use strict";
/**
* @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
*/
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const glob = require("glob");
const webpack = require("webpack");
const webpackDevMiddleware = require('webpack-dev-middleware');
const karma_webpack_failure_cb_1 = require("./karma-webpack-failure-cb");
const stats_1 = require("../utilities/stats");
const stats_2 = require("../models/webpack-configs/stats");
const node_1 = require("@angular-devkit/core/node");
const index_1 = require("../../utils/index");
/**
* Enumerate needed (but not require/imported) dependencies from this file
* to let the dependency validator know they are used.
*
* require('source-map-support')
* require('karma-source-map-support')
*/
let blocked = [];
let isBlocked = false;
let webpackMiddleware;
let successCb;
let failureCb;
// Add files to the Karma files array.
function addKarmaFiles(files, newFiles, prepend = false) {
const defaults = {
included: true,
served: true,
watched: true
};
const processedFiles = newFiles
// Remove globs that do not match any files, otherwise Karma will show a warning for these.
.filter(file => glob.sync(file.pattern, { nodir: true }).length != 0)
// Fill in pattern properties with defaults.
.map(file => ({ ...defaults, ...file }));
// It's important to not replace the array, because
// karma already has a reference to the existing array.
if (prepend) {
files.unshift(...processedFiles);
}
else {
files.push(...processedFiles);
}
}
const init = (config, emitter, customFileHandlers) => {
if (!config.buildWebpack) {
throw new Error(`The '@angular-devkit/build-angular/plugins/karma' karma plugin is meant to` +
` be used from within Angular CLI and will not work correctly outside of it.`);
}
const options = config.buildWebpack.options;
const logger = config.buildWebpack.logger || node_1.createConsoleLogger();
successCb = config.buildWebpack.successCb;
failureCb = config.buildWebpack.failureCb;
// When using code-coverage, auto-add coverage-istanbul.
config.reporters = config.reporters || [];
if (options.codeCoverage && config.reporters.indexOf('coverage-istanbul') === -1) {
config.reporters.push('coverage-istanbul');
}
// Add a reporter that fixes sourcemap urls.
if (index_1.normalizeSourceMaps(options.sourceMap).scripts) {
config.reporters.push('@angular-devkit/build-angular--sourcemap-reporter');
// Code taken from https://github.com/tschaub/karma-source-map-support.
// We can't use it directly because we need to add it conditionally in this file, and karma
// frameworks cannot be added dynamically.
const smsPath = path.dirname(require.resolve('source-map-support'));
const ksmsPath = path.dirname(require.resolve('karma-source-map-support'));
addKarmaFiles(config.files, [
{ pattern: path.join(smsPath, 'browser-source-map-support.js'), watched: false },
{ pattern: path.join(ksmsPath, 'client.js'), watched: false }
], true);
}
config.reporters.push('@angular-devkit/build-angular--event-reporter');
// Add webpack config.
const webpackConfig = config.buildWebpack.webpackConfig;
const webpackMiddlewareConfig = {
// Hide webpack output because its noisy.
logLevel: 'error',
stats: false,
watchOptions: { poll: options.poll },
publicPath: '/_karma_webpack_/',
};
const compilationErrorCb = (error, errors) => {
// Notify potential listeners of the compile error
emitter.emit('compile_error', errors);
// Finish Karma run early in case of compilation error.
emitter.emit('run_complete', [], { exitCode: 1 });
// Unblock any karma requests (potentially started using `karma run`)
unblock();
};
webpackConfig.plugins.push(new karma_webpack_failure_cb_1.KarmaWebpackFailureCb(compilationErrorCb));
// Use existing config if any.
config.webpack = Object.assign(webpackConfig, config.webpack);
config.webpackMiddleware = Object.assign(webpackMiddlewareConfig, config.webpackMiddleware);
// Our custom context and debug files list the webpack bundles directly instead of using
// the karma files array.
config.customContextFile = `${__dirname}/karma-context.html`;
config.customDebugFile = `${__dirname}/karma-debug.html`;
// Add the request blocker and the webpack server fallback.
config.beforeMiddleware = config.beforeMiddleware || [];
config.beforeMiddleware.push('@angular-devkit/build-angular--blocker');
config.middleware = config.middleware || [];
config.middleware.push('@angular-devkit/build-angular--fallback');
// The webpack tier owns the watch behavior so we want to force it in the config.
webpackConfig.watch = !config.singleRun;
if (config.singleRun) {
// There's no option to turn off file watching in webpack-dev-server, but
// we can override the file watcher instead.
webpackConfig.plugins.unshift({
apply: (compiler) => {
compiler.hooks.afterEnvironment.tap('karma', () => {
compiler.watchFileSystem = { watch: () => { } };
});
},
});
}
// Files need to be served from a custom path for Karma.
webpackConfig.output.path = '/_karma_webpack_/';
webpackConfig.output.publicPath = '/_karma_webpack_/';
let compiler;
try {
compiler = webpack(webpackConfig);
}
catch (e) {
logger.error(e.stack || e);
if (e.details) {
logger.error(e.details);
}
throw e;
}
function handler(callback) {
isBlocked = true;
if (typeof callback === 'function') {
callback();
}
}
compiler.hooks.invalid.tap('karma', () => handler());
compiler.hooks.watchRun.tapAsync('karma', (_, callback) => handler(callback));
compiler.hooks.run.tapAsync('karma', (_, callback) => handler(callback));
function unblock() {
isBlocked = false;
blocked.forEach((cb) => cb());
blocked = [];
}
let lastCompilationHash;
const statsConfig = stats_2.getWebpackStatsConfig();
compiler.hooks.done.tap('karma', (stats) => {
if (stats.compilation.errors.length > 0) {
const json = stats.toJson(config.stats);
// Print compilation errors.
logger.error(stats_1.statsErrorsToString(json, statsConfig));
lastCompilationHash = undefined;
// Emit a failure build event if there are compilation errors.
failureCb && failureCb();
}
else if (stats.hash != lastCompilationHash) {
// Refresh karma only when there are no webpack errors, and if the compilation changed.
lastCompilationHash = stats.hash;
emitter.refreshFiles();
}
unblock();
});
webpackMiddleware = new webpackDevMiddleware(compiler, webpackMiddlewareConfig);
// Forward requests to webpack server.
customFileHandlers.push({
urlRegex: /^\/_karma_webpack_\/.*/,
handler: function handler(req, res) {
webpackMiddleware(req, res, function () {
// Ensure script and style bundles are served.
// They are mentioned in the custom karma context page and we don't want them to 404.
const alwaysServe = [
'/_karma_webpack_/runtime.js',
'/_karma_webpack_/polyfills.js',
'/_karma_webpack_/polyfills-es5.js',
'/_karma_webpack_/scripts.js',
'/_karma_webpack_/styles.js',
'/_karma_webpack_/vendor.js',
];
if (alwaysServe.indexOf(req.url) != -1) {
res.statusCode = 200;
res.end();
}
else {
res.statusCode = 404;
res.end('Not found');
}
});
}
});
emitter.on('exit', (done) => {
webpackMiddleware.close();
done();
});
};
init.$inject = ['config', 'emitter', 'customFileHandlers'];
// Block requests until the Webpack compilation is done.
function requestBlocker() {
return function (_request, _response, next) {
if (isBlocked) {
blocked.push(next);
}
else {
next();
}
};
}
// Copied from "karma-jasmine-diff-reporter" source code:
// In case, when multiple reporters are used in conjunction
// with initSourcemapReporter, they both will show repetitive log
// messages when displaying everything that supposed to write to terminal.
// So just suppress any logs from initSourcemapReporter by doing nothing on
// browser log, because it is an utility reporter,
// unless it's alone in the "reporters" option and base reporter is used.
function muteDuplicateReporterLogging(context, config) {
context.writeCommonMsg = function () { };
const reporterName = '@angular/cli';
const hasTrailingReporters = config.reporters.slice(-1).pop() !== reporterName;
if (hasTrailingReporters) {
context.writeCommonMsg = function () { };
}
}
// Emits builder events.
const eventReporter = function (baseReporterDecorator, config) {
baseReporterDecorator(this);
muteDuplicateReporterLogging(this, config);
this.onRunComplete = function (_browsers, results) {
if (results.exitCode === 0) {
successCb && successCb();
}
else {
failureCb && failureCb();
}
};
// avoid duplicate failure message
this.specFailure = () => { };
};
eventReporter.$inject = ['baseReporterDecorator', 'config'];
// Strip the server address and webpack scheme (webpack://) from error log.
const sourceMapReporter = function (baseReporterDecorator, config) {
baseReporterDecorator(this);
muteDuplicateReporterLogging(this, config);
const urlRegexp = /http:\/\/localhost:\d+\/_karma_webpack_\/webpack:\//gi;
this.onSpecComplete = function (_browser, result) {
if (!result.success && result.log.length > 0) {
result.log.forEach((log, idx) => {
result.log[idx] = log.replace(urlRegexp, '');
});
}
};
// avoid duplicate complete message
this.onRunComplete = () => { };
// avoid duplicate failure message
this.specFailure = () => { };
};
sourceMapReporter.$inject = ['baseReporterDecorator', 'config'];
// When a request is not found in the karma server, try looking for it from the webpack server root.
function fallbackMiddleware() {
return function (req, res, next) {
if (webpackMiddleware) {
const webpackUrl = '/_karma_webpack_' + req.url;
const webpackReq = { ...req, url: webpackUrl };
webpackMiddleware(webpackReq, res, next);
}
else {
next();
}
};
}
module.exports = {
'framework:@angular-devkit/build-angular': ['factory', init],
'reporter:@angular-devkit/build-angular--sourcemap-reporter': ['type', sourceMapReporter],
'reporter:@angular-devkit/build-angular--event-reporter': ['type', eventReporter],
'middleware:@angular-devkit/build-angular--blocker': ['factory', requestBlocker],
'middleware:@angular-devkit/build-angular--fallback': ['factory', fallbackMiddleware]
};
/**
* @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 { Compiler } from 'webpack';
export declare class NamedLazyChunksPlugin {
constructor();
apply(compiler: Compiler): void;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// Webpack doesn't export these so the deep imports can potentially break.
// There doesn't seem to exist any ergonomic way to alter chunk names for non-context lazy chunks
// (https://github.com/webpack/webpack/issues/9075) so this is the best alternative for now.
const ImportDependency = require('webpack/lib/dependencies/ImportDependency');
const ImportDependenciesBlock = require('webpack/lib/dependencies/ImportDependenciesBlock');
const Template = require('webpack/lib/Template');
class NamedLazyChunksPlugin {
constructor() { }
apply(compiler) {
compiler.hooks.compilation.tap('named-lazy-chunks-plugin', compilation => {
// The dependencyReference hook isn't in the webpack typings so we have to type it as any.
// tslint:disable-next-line: no-any
compilation.hooks.dependencyReference.tap('named-lazy-chunks-plugin',
// tslint:disable-next-line: no-any
(_, dependency) => {
if (
// Check this dependency is from an `import()` statement.
dependency instanceof ImportDependency
&& dependency.block instanceof ImportDependenciesBlock
// Don't rename chunks that already have a name.
&& dependency.block.chunkName === null) {
// Convert the request to a valid chunk name using the same logic used
// in webpack/lib/ContextModule.js
dependency.block.chunkName = Template.toPath(dependency.request);
}
});
});
}
}
exports.NamedLazyChunksPlugin = NamedLazyChunksPlugin;
import { Compiler } from 'webpack';
export interface OptimizeCssWebpackPluginOptions {
sourceMap: boolean;
test: (file: string) => boolean;
}
export declare class OptimizeCssWebpackPlugin {
private readonly _options;
constructor(options: Partial<OptimizeCssWebpackPluginOptions>);
apply(compiler: Compiler): void;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 cssNano = require("cssnano");
const webpack_sources_1 = require("webpack-sources");
function hook(compiler, action) {
compiler.hooks.compilation.tap('optimize-css-webpack-plugin', (compilation) => {
compilation.hooks.optimizeChunkAssets.tapPromise('optimize-css-webpack-plugin', chunks => action(compilation, chunks));
});
}
class OptimizeCssWebpackPlugin {
constructor(options) {
this._options = {
sourceMap: false,
test: file => file.endsWith('.css'),
...options,
};
}
apply(compiler) {
hook(compiler, (compilation, chunks) => {
const files = [...compilation.additionalChunkAssets];
chunks.forEach(chunk => {
if (chunk.files && chunk.files.length > 0) {
files.push(...chunk.files);
}
});
const actions = files
.filter(file => this._options.test(file))
.map(async (file) => {
const asset = compilation.assets[file];
if (!asset) {
return;
}
let content;
// tslint:disable-next-line: no-any
let map;
if (this._options.sourceMap && asset.sourceAndMap) {
const sourceAndMap = asset.sourceAndMap();
content = sourceAndMap.source;
map = sourceAndMap.map;
}
else {
content = asset.source();
}
if (content.length === 0) {
return;
}
const cssNanoOptions = {
preset: ['default', {
// Disable SVG optimization, as this can cause optimizations which are not compatible in all browsers.
svgo: false,
}],
};
const postCssOptions = {
from: file,
map: map && { annotation: false, prev: map },
};
const output = await new Promise((resolve, reject) => {
// the last parameter is not in the typings
// tslint:disable-next-line: no-any
cssNano.process(content, postCssOptions, cssNanoOptions)
.then(resolve)
.catch(reject);
});
const warnings = output.warnings();
if (warnings.length) {
compilation.warnings.push(...warnings.map(({ text }) => text));
}
let newSource;
if (output.map) {
newSource = new webpack_sources_1.SourceMapSource(output.css, file,
// tslint:disable-next-line: no-any
output.map.toString(), content, map);
}
else {
newSource = new webpack_sources_1.RawSource(output.css);
}
compilation.assets[file] = newSource;
});
return Promise.all(actions);
});
}
}
exports.OptimizeCssWebpackPlugin = OptimizeCssWebpackPlugin;
import * as postcss from 'postcss';
import * as webpack from 'webpack';
export interface PostcssCliResourcesOptions {
baseHref?: string;
deployUrl?: string;
resourcesOutputPath?: string;
rebaseRootRelative?: boolean;
filename: string;
loader: webpack.loader.LoaderContext;
emitFile: boolean;
}
declare const _default: postcss.Plugin<PostcssCliResourcesOptions>;
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 loader_utils_1 = require("loader-utils");
const path = require("path");
const postcss = require("postcss");
const url = require("url");
function wrapUrl(url) {
let wrappedUrl;
const hasSingleQuotes = url.indexOf('\'') >= 0;
if (hasSingleQuotes) {
wrappedUrl = `"${url}"`;
}
else {
wrappedUrl = `'${url}'`;
}
return `url(${wrappedUrl})`;
}
async function resolve(file, base, resolver) {
try {
return await resolver('./' + file, base);
}
catch (_a) {
return resolver(file, base);
}
}
exports.default = postcss.plugin('postcss-cli-resources', (options) => {
const { deployUrl = '', baseHref = '', resourcesOutputPath = '', rebaseRootRelative = false, filename, loader, emitFile, } = options;
const dedupeSlashes = (url) => url.replace(/\/\/+/g, '/');
const process = async (inputUrl, context, resourceCache) => {
// If root-relative, absolute or protocol relative url, leave as is
if (/^((?:\w+:)?\/\/|data:|chrome:|#)/.test(inputUrl)) {
return inputUrl;
}
if (!rebaseRootRelative && /^\//.test(inputUrl)) {
return inputUrl;
}
// If starts with a caret, remove and return remainder
// this supports bypassing asset processing
if (inputUrl.startsWith('^')) {
return inputUrl.substr(1);
}
const cacheKey = path.resolve(context, inputUrl);
const cachedUrl = resourceCache.get(cacheKey);
if (cachedUrl) {
return cachedUrl;
}
if (inputUrl.startsWith('~')) {
inputUrl = inputUrl.substr(1);
}
if (inputUrl.startsWith('/')) {
let outputUrl = '';
if (deployUrl.match(/:\/\//) || deployUrl.startsWith('/')) {
// If deployUrl is absolute or root relative, ignore baseHref & use deployUrl as is.
outputUrl = `${deployUrl.replace(/\/$/, '')}${inputUrl}`;
}
else if (baseHref.match(/:\/\//)) {
// If baseHref contains a scheme, include it as is.
outputUrl = baseHref.replace(/\/$/, '') + dedupeSlashes(`/${deployUrl}/${inputUrl}`);
}
else {
// Join together base-href, deploy-url and the original URL.
outputUrl = dedupeSlashes(`/${baseHref}/${deployUrl}/${inputUrl}`);
}
resourceCache.set(cacheKey, outputUrl);
return outputUrl;
}
const { pathname, hash, search } = url.parse(inputUrl.replace(/\\/g, '/'));
const resolver = (file, base) => new Promise((resolve, reject) => {
loader.resolve(base, decodeURI(file), (err, result) => {
if (err) {
reject(err);
return;
}
resolve(result);
});
});
const result = await resolve(pathname, context, resolver);
return new Promise((resolve, reject) => {
loader.fs.readFile(result, (err, content) => {
if (err) {
reject(err);
return;
}
let outputPath = loader_utils_1.interpolateName({ resourcePath: result }, filename, { content });
if (resourcesOutputPath) {
outputPath = path.posix.join(resourcesOutputPath, outputPath);
}
loader.addDependency(result);
if (emitFile) {
loader.emitFile(outputPath, content, undefined);
}
let outputUrl = outputPath.replace(/\\/g, '/');
if (hash || search) {
outputUrl = url.format({ pathname: outputUrl, hash, search });
}
if (deployUrl && loader.loaders[loader.loaderIndex].options.ident !== 'extracted') {
outputUrl = url.resolve(deployUrl, outputUrl);
}
resourceCache.set(cacheKey, outputUrl);
resolve(outputUrl);
});
});
};
return (root) => {
const urlDeclarations = [];
root.walkDecls(decl => {
if (decl.value && decl.value.includes('url')) {
urlDeclarations.push(decl);
}
});
if (urlDeclarations.length === 0) {
return;
}
const resourceCache = new Map();
return Promise.all(urlDeclarations.map(async (decl) => {
const value = decl.value;
const urlRegex = /url\(\s*(?:"([^"]+)"|'([^']+)'|(.+?))\s*\)/g;
const segments = [];
let match;
let lastIndex = 0;
let modified = false;
// We want to load it relative to the file that imports
const inputFile = decl.source && decl.source.input.file;
const context = inputFile && path.dirname(inputFile) || loader.context;
// tslint:disable-next-line:no-conditional-assignment
while (match = urlRegex.exec(value)) {
const originalUrl = match[1] || match[2] || match[3];
let processedUrl;
try {
processedUrl = await process(originalUrl, context, resourceCache);
}
catch (err) {
loader.emitError(decl.error(err.message, { word: originalUrl }).toString());
continue;
}
if (lastIndex < match.index) {
segments.push(value.slice(lastIndex, match.index));
}
if (!processedUrl || originalUrl === processedUrl) {
segments.push(match[0]);
}
else {
segments.push(wrapUrl(processedUrl));
modified = true;
}
lastIndex = match.index + match[0].length;
}
if (lastIndex < value.length) {
segments.push(value.slice(lastIndex));
}
if (modified) {
decl.value = segments.join('');
}
}));
};
});
/**
* @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 { Compiler } from 'webpack';
import { HashFormat } from '../models/webpack-configs/utils';
export interface RemoveHashPluginOptions {
chunkNames: string[];
hashFormat: HashFormat;
}
export declare class RemoveHashPlugin {
private options;
constructor(options: RemoveHashPluginOptions);
apply(compiler: Compiler): void;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class RemoveHashPlugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
compiler.hooks.compilation.tap('remove-hash-plugin', compilation => {
const mainTemplate = compilation.mainTemplate;
mainTemplate.hooks.assetPath.tap('remove-hash-plugin', (path, data) => {
const chunkName = data.chunk && data.chunk.name;
const { chunkNames, hashFormat } = this.options;
if (chunkName && chunkNames.includes(chunkName)) {
// Replace hash formats with empty strings.
return path
.replace(hashFormat.chunk, '')
.replace(hashFormat.extract, '');
}
return path;
});
});
}
}
exports.RemoveHashPlugin = RemoveHashPlugin;
/**
* @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
*/
/**
* @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 { Compiler } from 'webpack';
export interface ScriptsWebpackPluginOptions {
name: string;
sourceMap: boolean;
scripts: string[];
filename: string;
basePath: string;
}
export declare class ScriptsWebpackPlugin {
private options;
private _lastBuildTime?;
private _cachedOutput?;
constructor(options?: Partial<ScriptsWebpackPluginOptions>);
shouldSkip(compilation: any, scripts: string[]): boolean;
private _insertOutput;
apply(compiler: Compiler): void;
}
"use strict";
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
Object.defineProperty(exports, "__esModule", { value: true });
const webpack_sources_1 = require("webpack-sources");
const loader_utils_1 = require("loader-utils");
const path = require("path");
const Chunk = require('webpack/lib/Chunk');
const EntryPoint = require('webpack/lib/Entrypoint');
function addDependencies(compilation, scripts) {
for (const script of scripts) {
compilation.fileDependencies.add(script);
}
}
function hook(compiler, action) {
compiler.hooks.thisCompilation.tap('scripts-webpack-plugin', (compilation) => {
compilation.hooks.additionalAssets.tapAsync('scripts-webpack-plugin', (callback) => action(compilation, callback));
});
}
class ScriptsWebpackPlugin {
constructor(options = {}) {
this.options = options;
}
shouldSkip(compilation, scripts) {
if (this._lastBuildTime == undefined) {
this._lastBuildTime = Date.now();
return false;
}
for (let i = 0; i < scripts.length; i++) {
const scriptTime = compilation.fileTimestamps.get(scripts[i]);
if (!scriptTime || scriptTime > this._lastBuildTime) {
this._lastBuildTime = Date.now();
return false;
}
}
return true;
}
_insertOutput(compilation, { filename, source }, cached = false) {
const chunk = new Chunk(this.options.name);
chunk.rendered = !cached;
chunk.id = this.options.name;
chunk.ids = [chunk.id];
chunk.files.push(filename);
const entrypoint = new EntryPoint(this.options.name);
entrypoint.pushChunk(chunk);
chunk.addGroup(entrypoint);
compilation.entrypoints.set(this.options.name, entrypoint);
compilation.chunks.push(chunk);
compilation.assets[filename] = source;
}
apply(compiler) {
if (!this.options.scripts || this.options.scripts.length === 0) {
return;
}
const scripts = this.options.scripts
.filter(script => !!script)
.map(script => path.resolve(this.options.basePath || '', script));
hook(compiler, (compilation, callback) => {
if (this.shouldSkip(compilation, scripts)) {
if (this._cachedOutput) {
this._insertOutput(compilation, this._cachedOutput, true);
}
addDependencies(compilation, scripts);
callback();
return;
}
const sourceGetters = scripts.map(fullPath => {
return new Promise((resolve, reject) => {
compilation.inputFileSystem.readFile(fullPath, (err, data) => {
if (err) {
reject(err);
return;
}
const content = data.toString();
let source;
if (this.options.sourceMap) {
// TODO: Look for source map file (for '.min' scripts, etc.)
let adjustedPath = fullPath;
if (this.options.basePath) {
adjustedPath = path.relative(this.options.basePath, fullPath);
}
source = new webpack_sources_1.OriginalSource(content, adjustedPath);
}
else {
source = new webpack_sources_1.RawSource(content);
}
resolve(source);
});
});
});
Promise.all(sourceGetters)
.then(sources => {
const concatSource = new webpack_sources_1.ConcatSource();
sources.forEach(source => {
concatSource.add(source);
concatSource.add('\n;');
});
const combinedSource = new webpack_sources_1.CachedSource(concatSource);
const filename = loader_utils_1.interpolateName({ resourcePath: 'scripts.js' }, this.options.filename, { content: combinedSource.source() });
const output = { filename, source: combinedSource };
this._insertOutput(compilation, output);
this._cachedOutput = output;
addDependencies(compilation, scripts);
callback();
})
.catch((err) => callback(err));
});
}
}
exports.ScriptsWebpackPlugin = ScriptsWebpackPlugin;
/**
* @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 { logging } from '@angular-devkit/core';
import { loader } from 'webpack';
export interface SingleTestTransformLoaderOptions {
files: string[];
logger: logging.Logger;
}
export declare const SingleTestTransformLoader: string;
/**
* This loader transforms the default test file to only run tests
* for some specs instead of all specs.
* It works by replacing the known content of the auto-generated test file:
* const context = require.context('./', true, /\.spec\.ts$/);
* context.keys().map(context);
* with:
* const context = { keys: () => ({ map: (_a) => { } }) };
* context.keys().map(context);
* So that it does nothing.
* Then it adds import statements for each file in the files options
* array to import them directly, and thus run the tests there.
*/
export default function loader(this: loader.LoaderContext, source: string): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const loader_utils_1 = require("loader-utils");
const path_1 = require("path");
exports.SingleTestTransformLoader = require.resolve(path_1.join(__dirname, 'single-test-transform'));
/**
* This loader transforms the default test file to only run tests
* for some specs instead of all specs.
* It works by replacing the known content of the auto-generated test file:
* const context = require.context('./', true, /\.spec\.ts$/);
* context.keys().map(context);
* with:
* const context = { keys: () => ({ map: (_a) => { } }) };
* context.keys().map(context);
* So that it does nothing.
* Then it adds import statements for each file in the files options
* array to import them directly, and thus run the tests there.
*/
function loader(source) {
const options = loader_utils_1.getOptions(this);
const lineSeparator = process.platform === 'win32' ? '\r\n' : '\n';
const targettedImports = options.files
.map(path => `require('./${path.replace('.' + path_1.extname(path), '')}');`)
.join(lineSeparator);
// TODO: maybe a documented 'marker/comment' inside test.ts would be nicer?
const regex = /require\.context\(.*/;
// signal the user that expected content is not present
if (!regex.test(source)) {
const message = [
`The 'include' option requires that the 'main' file for tests include the line below:`,
`const context = require.context('./', true, /\.spec\.ts$/);`,
`Arguments passed to require.context are not strict and can be changed`,
];
options.logger.error(message.join(lineSeparator));
}
const mockedRequireContext = 'Object.assign(() => { }, { keys: () => [], resolve: () => undefined });' + lineSeparator;
source = source.replace(regex, mockedRequireContext + targettedImports);
return source;
}
exports.default = loader;
/**
* @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
*/
export declare class SuppressExtractedTextChunksWebpackPlugin {
constructor();
apply(compiler: any): void;
}
"use strict";
/**
* @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
*/
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
Object.defineProperty(exports, "__esModule", { value: true });
// Remove .js files from entry points consisting entirely of .css|scss|sass|less|styl.
// To be used together with ExtractTextPlugin.
class SuppressExtractedTextChunksWebpackPlugin {
constructor() { }
apply(compiler) {
compiler.hooks.compilation.tap('SuppressExtractedTextChunks', (compilation) => {
// find which chunks have css only entry points
const cssOnlyChunks = [];
const entryPoints = compilation.options.entry;
// determine which entry points are composed entirely of css files
for (let entryPoint of Object.keys(entryPoints)) {
let entryFiles = entryPoints[entryPoint];
// when type of entryFiles is not array, make it as an array
entryFiles = entryFiles instanceof Array ? entryFiles : [entryFiles];
if (entryFiles.every((el) => el.match(/\.(css|scss|sass|less|styl)$/) !== null)) {
cssOnlyChunks.push(entryPoint);
}
}
// Remove the js file for supressed chunks
compilation.hooks.afterSeal.tap('SuppressExtractedTextChunks', () => {
compilation.chunks
.filter((chunk) => cssOnlyChunks.indexOf(chunk.name) !== -1)
.forEach((chunk) => {
let newFiles = [];
chunk.files.forEach((file) => {
if (file.match(/\.js(\.map)?$/)) {
// remove js files
delete compilation.assets[file];
}
else {
newFiles.push(file);
}
});
chunk.files = newFiles;
});
});
// Remove scripts tags with a css file as source, because HtmlWebpackPlugin will use
// a css file as a script for chunks without js files.
// TODO: Enable this once HtmlWebpackPlugin supports Webpack 4
// compilation.plugin('html-webpack-plugin-alter-asset-tags',
// (htmlPluginData: any, callback: any) => {
// const filterFn = (tag: any) =>
// !(tag.tagName === 'script' && tag.attributes.src.match(/\.css$/));
// htmlPluginData.head = htmlPluginData.head.filter(filterFn);
// htmlPluginData.body = htmlPluginData.body.filter(filterFn);
// callback(null, htmlPluginData);
// });
});
}
}
exports.SuppressExtractedTextChunksWebpackPlugin = SuppressExtractedTextChunksWebpackPlugin;
/**
* @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 { RawSourceMap } from 'source-map';
import webpack = require('webpack');
export default function webpackRollupLoader(this: webpack.loader.LoaderContext, source: string, sourceMap: RawSourceMap): void;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const rollup_1 = require("rollup");
function splitRequest(request) {
const inx = request.lastIndexOf('!');
if (inx === -1) {
return {
loaders: '',
resource: request,
};
}
else {
return {
loaders: request.slice(0, inx + 1),
resource: request.slice(inx + 1),
};
}
}
// Load resolve paths using Webpack.
function webpackResolutionPlugin(loaderContext, entryId, entryIdCodeAndMap) {
return {
name: 'webpack-resolution-plugin',
resolveId: (id, importerId) => {
if (id === entryId) {
return entryId;
}
else {
return new Promise((resolve, reject) => {
// split apart resource paths because Webpack's this.resolve() can't handle `loader!`
// prefixes
const parts = splitRequest(id);
const importerParts = splitRequest(importerId);
// resolve the full path of the imported file with Webpack's module loader
// this will figure out node_modules imports, Webpack aliases, etc.
loaderContext.resolve(path_1.dirname(importerParts.resource), parts.resource, (err, fullPath) => err ? reject(err) : resolve(parts.loaders + fullPath));
});
}
},
load: (id) => {
if (id === entryId) {
return entryIdCodeAndMap;
}
return new Promise((resolve, reject) => {
// load the module with Webpack
// this will apply all relevant loaders, etc.
loaderContext.loadModule(id, (err, source, map) => err ? reject(err) : resolve({ code: source, map: map }));
});
},
};
}
function webpackRollupLoader(source, sourceMap) {
// Note: this loader isn't cacheable because it will add the lazy chunks to the
// virtual file system on completion.
const callback = this.async();
if (!callback) {
throw new Error('Async loader support is required.');
}
const options = this.query || {};
const entryId = this.resourcePath;
const sourcemap = this.sourceMap;
// Get the VirtualFileSystemDecorator that AngularCompilerPlugin added so we can write to it.
// Since we use webpackRollupLoader as a post loader, this should be there.
// TODO: we should be able to do this in a more elegant way by again decorating webpacks
// input file system inside a custom WebpackRollupPlugin, modelled after AngularCompilerPlugin.
const vfs = this._compiler.inputFileSystem;
const virtualWrite = (path, data) => vfs.getWebpackCompilerHost().writeFile(path, data, false);
// Bundle with Rollup
const rollupOptions = {
...options,
input: entryId,
plugins: [
...(options.plugins || []),
webpackResolutionPlugin(this, entryId, { code: source, map: sourceMap }),
],
};
rollup_1.rollup(rollupOptions)
.then(build => build.generate({ format: 'es', sourcemap }))
.then((result) => {
const [mainChunk, ...otherChunksOrAssets] = result.output;
// Write other chunks and assets to the virtual file system so that webpack can load them.
const resultDir = path_1.dirname(entryId);
otherChunksOrAssets.forEach(chunkOrAsset => {
const { fileName, type } = chunkOrAsset;
if (type == 'chunk') {
const { code, map } = chunkOrAsset;
virtualWrite(path_1.join(resultDir, fileName), code);
if (map) {
// Also write the map if there's one.
// Probably need scriptsSourceMap set on CLI to load it.
virtualWrite(path_1.join(resultDir, `${fileName}.map`), map.toString());
}
}
else if (type == 'asset') {
const { source } = chunkOrAsset;
// Source might be a Buffer. Just assuming it's a string for now.
virtualWrite(path_1.join(resultDir, fileName), source);
}
});
// Always return the main chunk from webpackRollupLoader.
// Cast to any here is needed because of a typings incompatibility between source-map versions.
// tslint:disable-next-line:no-any
callback(null, mainChunk.code, mainChunk.map);
}, (err) => callback(err));
}
exports.default = webpackRollupLoader;
/**
* @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
*/
export { AnyComponentStyleBudgetChecker } from './any-component-style-budget-checker';
export { OptimizeCssWebpackPlugin, OptimizeCssWebpackPluginOptions } from './optimize-css-webpack-plugin';
export { BundleBudgetPlugin, BundleBudgetPluginOptions } from './bundle-budget';
export { ScriptsWebpackPlugin, ScriptsWebpackPluginOptions } from './scripts-webpack-plugin';
export { SuppressExtractedTextChunksWebpackPlugin } from './suppress-entry-chunks-webpack-plugin';
export { RemoveHashPlugin, RemoveHashPluginOptions } from './remove-hash-plugin';
export { NamedLazyChunksPlugin as NamedChunksPlugin } from './named-chunks-plugin';
export { default as PostcssCliResources, PostcssCliResourcesOptions, } from './postcss-cli-resources';
export declare const WebpackRollupLoader: string;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
// Exports the webpack plugins we use internally.
var any_component_style_budget_checker_1 = require("./any-component-style-budget-checker");
exports.AnyComponentStyleBudgetChecker = any_component_style_budget_checker_1.AnyComponentStyleBudgetChecker;
var optimize_css_webpack_plugin_1 = require("./optimize-css-webpack-plugin");
exports.OptimizeCssWebpackPlugin = optimize_css_webpack_plugin_1.OptimizeCssWebpackPlugin;
var bundle_budget_1 = require("./bundle-budget");
exports.BundleBudgetPlugin = bundle_budget_1.BundleBudgetPlugin;
var scripts_webpack_plugin_1 = require("./scripts-webpack-plugin");
exports.ScriptsWebpackPlugin = scripts_webpack_plugin_1.ScriptsWebpackPlugin;
var suppress_entry_chunks_webpack_plugin_1 = require("./suppress-entry-chunks-webpack-plugin");
exports.SuppressExtractedTextChunksWebpackPlugin = suppress_entry_chunks_webpack_plugin_1.SuppressExtractedTextChunksWebpackPlugin;
var remove_hash_plugin_1 = require("./remove-hash-plugin");
exports.RemoveHashPlugin = remove_hash_plugin_1.RemoveHashPlugin;
var named_chunks_plugin_1 = require("./named-chunks-plugin");
exports.NamedChunksPlugin = named_chunks_plugin_1.NamedLazyChunksPlugin;
var postcss_cli_resources_1 = require("./postcss-cli-resources");
exports.PostcssCliResources = postcss_cli_resources_1.default;
const path_1 = require("path");
exports.WebpackRollupLoader = require.resolve(path_1.join(__dirname, 'webpack-rollup-loader'));
/**
* @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 webpack from 'webpack';
import { NormalizedEntryPoint } from '../models/webpack-configs';
/**
* Webpack stats may incorrectly mark extra entry points `initial` chunks, when
* they are actually loaded asynchronously and thus not in the main bundle. This
* function finds extra entry points in Webpack stats and corrects this value
* whereever necessary. Does not modify {@param webpackStats}.
*/
export declare function markAsyncChunksNonInitial(webpackStats: webpack.Stats.ToJsonOutput, extraEntryPoints: NormalizedEntryPoint[]): Exclude<webpack.Stats.ToJsonOutput['chunks'], undefined>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Webpack stats may incorrectly mark extra entry points `initial` chunks, when
* they are actually loaded asynchronously and thus not in the main bundle. This
* function finds extra entry points in Webpack stats and corrects this value
* whereever necessary. Does not modify {@param webpackStats}.
*/
function markAsyncChunksNonInitial(webpackStats, extraEntryPoints) {
const { chunks = [], entrypoints: entryPoints = {} } = webpackStats;
// Find all Webpack chunk IDs not injected into the main bundle. We don't have
// to worry about transitive dependencies because extra entry points cannot be
// depended upon in Webpack, thus any extra entry point with `inject: false`,
// **cannot** be loaded in main bundle.
const asyncEntryPoints = extraEntryPoints.filter((entryPoint) => !entryPoint.inject);
const asyncChunkIds = flatMap(asyncEntryPoints, (entryPoint) => entryPoints[entryPoint.bundleName].chunks);
// Find chunks for each ID.
const asyncChunks = asyncChunkIds.map((chunkId) => {
const chunk = chunks.find((chunk) => chunk.id === chunkId);
if (!chunk) {
throw new Error(`Failed to find chunk (${chunkId}) in set:\n${JSON.stringify(chunks)}`);
}
return chunk;
})
// All Webpack chunks are dependent on `runtime`, which is never an async
// entry point, simply ignore this one.
.filter((chunk) => chunk.names.indexOf('runtime') === -1);
// A chunk is considered `initial` only if Webpack already belives it to be initial
// and the application developer did not mark it async via an extra entry point.
return chunks.map((chunk) => ({
...chunk,
initial: chunk.initial && !asyncChunks.find((asyncChunk) => asyncChunk === chunk),
}));
}
exports.markAsyncChunksNonInitial = markAsyncChunksNonInitial;
function flatMap(list, mapper) {
return [].concat(...list.map(mapper));
}
/**
* @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 webpack from 'webpack';
import { ProcessBundleResult } from '../../../src/utils/process-bundle';
import { Budget } from '../../browser/schema';
interface Threshold {
limit: number;
type: ThresholdType;
severity: ThresholdSeverity;
}
declare enum ThresholdType {
Max = "maximum",
Min = "minimum"
}
export declare enum ThresholdSeverity {
Warning = "warning",
Error = "error"
}
export declare function calculateThresholds(budget: Budget): IterableIterator<Threshold>;
export declare function checkBudgets(budgets: Budget[], webpackStats: webpack.Stats.ToJsonOutput, processResults: ProcessBundleResult[]): IterableIterator<{
severity: ThresholdSeverity;
message: string;
}>;
export declare function checkThresholds(thresholds: IterableIterator<Threshold>, size: number, label?: string): IterableIterator<{
severity: ThresholdSeverity;
message: string;
}>;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const schema_1 = require("../../browser/schema");
const stats_1 = require("../utilities/stats");
var ThresholdType;
(function (ThresholdType) {
ThresholdType["Max"] = "maximum";
ThresholdType["Min"] = "minimum";
})(ThresholdType || (ThresholdType = {}));
var ThresholdSeverity;
(function (ThresholdSeverity) {
ThresholdSeverity["Warning"] = "warning";
ThresholdSeverity["Error"] = "error";
})(ThresholdSeverity = exports.ThresholdSeverity || (exports.ThresholdSeverity = {}));
var DifferentialBuildType;
(function (DifferentialBuildType) {
DifferentialBuildType["ORIGINAL"] = "es2015";
DifferentialBuildType["DOWNLEVEL"] = "es5";
})(DifferentialBuildType || (DifferentialBuildType = {}));
function* calculateThresholds(budget) {
if (budget.maximumWarning) {
yield {
limit: calculateBytes(budget.maximumWarning, budget.baseline, 1),
type: ThresholdType.Max,
severity: ThresholdSeverity.Warning,
};
}
if (budget.maximumError) {
yield {
limit: calculateBytes(budget.maximumError, budget.baseline, 1),
type: ThresholdType.Max,
severity: ThresholdSeverity.Error,
};
}
if (budget.minimumWarning) {
yield {
limit: calculateBytes(budget.minimumWarning, budget.baseline, -1),
type: ThresholdType.Min,
severity: ThresholdSeverity.Warning,
};
}
if (budget.minimumError) {
yield {
limit: calculateBytes(budget.minimumError, budget.baseline, -1),
type: ThresholdType.Min,
severity: ThresholdSeverity.Error,
};
}
if (budget.warning) {
yield {
limit: calculateBytes(budget.warning, budget.baseline, -1),
type: ThresholdType.Min,
severity: ThresholdSeverity.Warning,
};
yield {
limit: calculateBytes(budget.warning, budget.baseline, 1),
type: ThresholdType.Max,
severity: ThresholdSeverity.Warning,
};
}
if (budget.error) {
yield {
limit: calculateBytes(budget.error, budget.baseline, -1),
type: ThresholdType.Min,
severity: ThresholdSeverity.Error,
};
yield {
limit: calculateBytes(budget.error, budget.baseline, 1),
type: ThresholdType.Max,
severity: ThresholdSeverity.Error,
};
}
}
exports.calculateThresholds = calculateThresholds;
/**
* Calculates the sizes for bundles in the budget type provided.
*/
function calculateSizes(budget, stats, processResults) {
if (budget.type === schema_1.Type.AnyComponentStyle) {
// Component style size information is not available post-build, this must
// be checked mid-build via the `AnyComponentStyleBudgetChecker` plugin.
throw new Error('Can not calculate size of AnyComponentStyle. Use `AnyComponentStyleBudgetChecker` instead.');
}
const calculatorMap = {
all: AllCalculator,
allScript: AllScriptCalculator,
any: AnyCalculator,
anyScript: AnyScriptCalculator,
bundle: BundleCalculator,
initial: InitialCalculator,
};
const ctor = calculatorMap[budget.type];
const { chunks, assets } = stats;
if (!chunks) {
throw new Error('Webpack stats output did not include chunk information.');
}
if (!assets) {
throw new Error('Webpack stats output did not include asset information.');
}
const calculator = new ctor(budget, chunks, assets, processResults);
return calculator.calculate();
}
class Calculator {
constructor(budget, chunks, assets, processResults) {
this.budget = budget;
this.chunks = chunks;
this.assets = assets;
this.processResults = processResults;
}
/** Calculates the size of the given chunk for the provided build type. */
calculateChunkSize(chunk, buildType) {
// Look for a process result containing different builds for this chunk.
const processResult = this.processResults
.find((processResult) => processResult.name === chunk.id.toString());
if (processResult) {
// Found a differential build, use the correct size information.
const processResultFile = getDifferentialBuildResult(processResult, buildType);
return processResultFile && processResultFile.size || 0;
}
else {
// No differential builds, get the chunk size by summing its assets.
return chunk.files
.filter(file => !file.endsWith('.map'))
.map(file => {
const asset = this.assets.find((asset) => asset.name === file);
if (!asset) {
throw new Error(`Could not find asset for file: ${file}`);
}
return asset.size;
})
.reduce((l, r) => l + r, 0);
}
}
}
/**
* A named bundle.
*/
class BundleCalculator extends Calculator {
calculate() {
const budgetName = this.budget.name;
if (!budgetName) {
return [];
}
// The chunk may or may not have differential builds. Compute the size for
// each then check afterwards if they are all the same.
const buildSizes = Object.values(DifferentialBuildType).map((buildType) => {
const size = this.chunks
.filter(chunk => chunk.names.indexOf(budgetName) !== -1)
.map(chunk => this.calculateChunkSize(chunk, buildType))
.reduce((l, r) => l + r, 0);
return { size, label: `${this.budget.name}-${buildType}` };
});
// If this bundle was not actually generated by a differential build, then
// merge the results into a single value.
if (allEquivalent(buildSizes.map((buildSize) => buildSize.size))) {
return mergeDifferentialBuildSizes(buildSizes, budgetName);
}
else {
return buildSizes;
}
}
}
/**
* The sum of all initial chunks (marked as initial).
*/
class InitialCalculator extends Calculator {
calculate() {
const buildSizes = Object.values(DifferentialBuildType).map((buildType) => {
return {
label: `initial-${buildType}`,
size: this.chunks
.filter(chunk => chunk.initial)
.map(chunk => this.calculateChunkSize(chunk, buildType))
.reduce((l, r) => l + r, 0),
};
});
// If this bundle was not actually generated by a differential build, then
// merge the results into a single value.
if (allEquivalent(buildSizes.map((buildSize) => buildSize.size))) {
return mergeDifferentialBuildSizes(buildSizes, 'initial');
}
else {
return buildSizes;
}
}
}
/**
* The sum of all the scripts portions.
*/
class AllScriptCalculator extends Calculator {
calculate() {
const size = this.assets
.filter(asset => asset.name.endsWith('.js'))
.map(asset => asset.size)
.reduce((total, size) => total + size, 0);
return [{ size, label: 'total scripts' }];
}
}
/**
* All scripts and assets added together.
*/
class AllCalculator extends Calculator {
calculate() {
const size = this.assets
.filter(asset => !asset.name.endsWith('.map'))
.map(asset => asset.size)
.reduce((total, size) => total + size, 0);
return [{ size, label: 'total' }];
}
}
/**
* Any script, individually.
*/
class AnyScriptCalculator extends Calculator {
calculate() {
return this.assets
.filter(asset => asset.name.endsWith('.js'))
.map(asset => ({
size: asset.size,
label: asset.name,
}));
}
}
/**
* Any script or asset (images, css, etc).
*/
class AnyCalculator extends Calculator {
calculate() {
return this.assets
.filter(asset => !asset.name.endsWith('.map'))
.map(asset => ({
size: asset.size,
label: asset.name,
}));
}
}
/**
* Calculate the bytes given a string value.
*/
function calculateBytes(input, baseline, factor = 1) {
const matches = input.match(/^\s*(\d+(?:\.\d+)?)\s*(%|(?:[mM]|[kK]|[gG])?[bB])?\s*$/);
if (!matches) {
return NaN;
}
const baselineBytes = baseline && calculateBytes(baseline) || 0;
let value = Number(matches[1]);
switch (matches[2] && matches[2].toLowerCase()) {
case '%':
value = baselineBytes * value / 100;
break;
case 'kb':
value *= 1024;
break;
case 'mb':
value *= 1024 * 1024;
break;
case 'gb':
value *= 1024 * 1024 * 1024;
break;
}
if (baselineBytes === 0) {
return value;
}
return baselineBytes + value * factor;
}
function* checkBudgets(budgets, webpackStats, processResults) {
// Ignore AnyComponentStyle budgets as these are handled in `AnyComponentStyleBudgetChecker`.
const computableBudgets = budgets.filter((budget) => budget.type !== schema_1.Type.AnyComponentStyle);
for (const budget of computableBudgets) {
const sizes = calculateSizes(budget, webpackStats, processResults);
for (const { size, label } of sizes) {
yield* checkThresholds(calculateThresholds(budget), size, label);
}
}
}
exports.checkBudgets = checkBudgets;
function* checkThresholds(thresholds, size, label) {
for (const threshold of thresholds) {
switch (threshold.type) {
case ThresholdType.Max: {
if (size <= threshold.limit) {
continue;
}
const sizeDifference = stats_1.formatSize(size - threshold.limit);
yield {
severity: threshold.severity,
message: `Exceeded maximum budget for ${label}. Budget ${stats_1.formatSize(threshold.limit)} was not met by ${sizeDifference} with a total of ${stats_1.formatSize(size)}.`,
};
break;
}
case ThresholdType.Min: {
if (size >= threshold.limit) {
continue;
}
const sizeDifference = stats_1.formatSize(threshold.limit - size);
yield {
severity: threshold.severity,
message: `Failed to meet minimum budget for ${label}. Budget ${stats_1.formatSize(threshold.limit)} was not met by ${sizeDifference} with a total of ${stats_1.formatSize(size)}.`,
};
break;
}
default: {
assertNever(threshold.type);
break;
}
}
}
}
exports.checkThresholds = checkThresholds;
/** Returns the {@link ProcessBundleFile} for the given {@link DifferentialBuildType}. */
function getDifferentialBuildResult(processResult, buildType) {
switch (buildType) {
case DifferentialBuildType.ORIGINAL: return processResult.original || null;
case DifferentialBuildType.DOWNLEVEL: return processResult.downlevel || null;
}
}
/**
* Merges the given differential builds into a single, non-differential value.
*
* Preconditions: All the sizes should be equivalent, or else they represent
* differential builds.
*/
function mergeDifferentialBuildSizes(buildSizes, margeLabel) {
if (buildSizes.length === 0) {
return [];
}
// Only one size.
return [{
label: margeLabel,
size: buildSizes[0].size,
}];
}
/** Returns whether or not all items in the list are equivalent to each other. */
function allEquivalent(items) {
if (items.length === 0) {
return true;
}
const first = items[0];
for (const item of items.slice(1)) {
if (item !== first) {
return false;
}
}
return true;
}
function assertNever(input) {
throw new Error(`Unexpected call to assertNever() with input: ${JSON.stringify(input, null /* replacer */, 4 /* tabSize */)}`);
}
export declare function checkPort(port: number, host: string, basePort?: number): Promise<number>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 net = require("net");
function checkPort(port, host, basePort = 49152) {
return new Promise((resolve, reject) => {
function _getPort(portNumber) {
if (portNumber > 65535) {
reject(new Error(`There is no port available.`));
}
const server = net.createServer();
server.once('error', (err) => {
if (err.code !== 'EADDRINUSE') {
reject(err);
}
else if (port === 0) {
_getPort(portNumber + 1);
}
else {
// If the port isn't available and we weren't looking for any port, throw error.
reject(new Error(`Port ${port} is already in use. Use '--port' to specify a different port.`));
}
})
.once('listening', () => {
server.close();
resolve(portNumber);
})
.listen(portNumber, host);
}
_getPort(port || basePort);
});
}
exports.checkPort = checkPort;
export declare function findTests(patterns: string[], cwd: string, workspaceRoot: string): string[];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 fs_1 = require("fs");
const glob = require("glob");
const path_1 = require("path");
const is_directory_1 = require("./is-directory");
// go through all patterns and find unique list of files
function findTests(patterns, cwd, workspaceRoot) {
return patterns.reduce((files, pattern) => {
const relativePathToMain = cwd.replace(workspaceRoot, '').substr(1); // remove leading slash
const tests = findMatchingTests(pattern, cwd, relativePathToMain);
tests.forEach(file => {
if (!files.includes(file)) {
files.push(file);
}
});
return files;
}, []);
}
exports.findTests = findTests;
function findMatchingTests(pattern, cwd, relativePathToMain) {
// normalize pattern, glob lib only accepts forward slashes
pattern = pattern.replace(/\\/g, '/');
relativePathToMain = relativePathToMain.replace(/\\/g, '/');
// remove relativePathToMain to support relative paths from root
// such paths are easy to get when running scripts via IDEs
if (pattern.startsWith(relativePathToMain + '/')) {
pattern = pattern.substr(relativePathToMain.length + 1); // +1 to include slash
}
// special logic when pattern does not look like a glob
if (!glob.hasMagic(pattern)) {
if (is_directory_1.isDirectory(path_1.join(cwd, pattern))) {
pattern = `${pattern}/**/*.spec.@(ts|tsx)`;
}
else {
// see if matching spec file exists
const extension = path_1.extname(pattern);
const matchingSpec = `${path_1.basename(pattern, extension)}.spec${extension}`;
if (fs_1.existsSync(path_1.join(cwd, path_1.dirname(pattern), matchingSpec))) {
pattern = path_1.join(path_1.dirname(pattern), matchingSpec).replace(/\\/g, '/');
}
}
}
const files = glob.sync(pattern, {
cwd,
});
return files;
}
export declare function findUp(names: string | string[], from: string, stopOnNodeModules?: boolean): string | null;
export declare function findAllNodeModules(from: string, root?: string): string[];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 fs_1 = require("fs");
const path = require("path");
const is_directory_1 = require("./is-directory");
function findUp(names, from, stopOnNodeModules = false) {
if (!Array.isArray(names)) {
names = [names];
}
const root = path.parse(from).root;
let currentDir = from;
while (currentDir && currentDir !== root) {
for (const name of names) {
const p = path.join(currentDir, name);
if (fs_1.existsSync(p)) {
return p;
}
}
if (stopOnNodeModules) {
const nodeModuleP = path.join(currentDir, 'node_modules');
if (fs_1.existsSync(nodeModuleP)) {
return null;
}
}
currentDir = path.dirname(currentDir);
}
return null;
}
exports.findUp = findUp;
function findAllNodeModules(from, root) {
const nodeModules = [];
let current = from;
while (current && current !== root) {
const potential = path.join(current, 'node_modules');
if (fs_1.existsSync(potential) && is_directory_1.isDirectory(potential)) {
nodeModules.push(potential);
}
const next = path.dirname(current);
if (next === current) {
break;
}
current = next;
}
return nodeModules;
}
exports.findAllNodeModules = findAllNodeModules;
/**
* @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
*/
export declare type LoadOutputFileFunctionType = (file: string) => Promise<string>;
export declare type CrossOriginValue = 'none' | 'anonymous' | 'use-credentials';
export interface AugmentIndexHtmlOptions {
input: string;
inputContent: string;
baseHref?: string;
deployUrl?: string;
sri: boolean;
/** crossorigin attribute setting of elements that provide CORS support */
crossOrigin?: CrossOriginValue;
files: FileInfo[];
/** Files that should be added using 'nomodule'. */
noModuleFiles?: FileInfo[];
/** Files that should be added using 'module'. */
moduleFiles?: FileInfo[];
loadOutputFile: LoadOutputFileFunctionType;
/** Used to sort the inseration of files in the HTML file */
entrypoints: string[];
/** Used to set the document default locale */
lang?: string;
}
export interface FileInfo {
file: string;
name: string;
extension: string;
}
export declare function augmentIndexHtml(params: AugmentIndexHtmlOptions): Promise<string>;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const crypto_1 = require("crypto");
const webpack_sources_1 = require("webpack-sources");
const parse5 = require('parse5');
/*
* Helper function used by the IndexHtmlWebpackPlugin.
* Can also be directly used by builder, e. g. in order to generate an index.html
* after processing several configurations in order to build different sets of
* bundles for differential serving.
*/
// tslint:disable-next-line: no-big-function
async function augmentIndexHtml(params) {
const { loadOutputFile, files, noModuleFiles = [], moduleFiles = [], entrypoints } = params;
let { crossOrigin = 'none' } = params;
if (params.sri && crossOrigin === 'none') {
crossOrigin = 'anonymous';
}
const stylesheets = new Set();
const scripts = new Set();
// Sort files in the order we want to insert them by entrypoint and dedupes duplicates
const mergedFiles = [...moduleFiles, ...noModuleFiles, ...files];
for (const entrypoint of entrypoints) {
for (const { extension, file, name } of mergedFiles) {
if (name !== entrypoint) {
continue;
}
switch (extension) {
case '.js':
scripts.add(file);
break;
case '.css':
stylesheets.add(file);
break;
}
}
}
// Find the head and body elements
const treeAdapter = parse5.treeAdapters.default;
const document = parse5.parse(params.inputContent, { treeAdapter, locationInfo: true });
let headElement;
let bodyElement;
let htmlElement;
for (const docChild of document.childNodes) {
if (docChild.tagName === 'html') {
htmlElement = docChild;
for (const htmlChild of docChild.childNodes) {
if (htmlChild.tagName === 'head') {
headElement = htmlChild;
}
else if (htmlChild.tagName === 'body') {
bodyElement = htmlChild;
}
}
}
}
if (!headElement || !bodyElement) {
throw new Error('Missing head and/or body elements');
}
// Determine script insertion point
let scriptInsertionPoint;
if (bodyElement.__location && bodyElement.__location.endTag) {
scriptInsertionPoint = bodyElement.__location.endTag.startOffset;
}
else {
// Less accurate fallback
// parse5 4.x does not provide locations if malformed html is present
scriptInsertionPoint = params.inputContent.indexOf('</body>');
}
let styleInsertionPoint;
if (headElement.__location && headElement.__location.endTag) {
styleInsertionPoint = headElement.__location.endTag.startOffset;
}
else {
// Less accurate fallback
// parse5 4.x does not provide locations if malformed html is present
styleInsertionPoint = params.inputContent.indexOf('</head>');
}
// Inject into the html
const indexSource = new webpack_sources_1.ReplaceSource(new webpack_sources_1.RawSource(params.inputContent), params.input);
let scriptElements = '';
for (const script of scripts) {
const attrs = [
{ name: 'src', value: (params.deployUrl || '') + script },
];
if (crossOrigin !== 'none') {
attrs.push({ name: 'crossorigin', value: crossOrigin });
}
// We want to include nomodule or module when a file is not common amongs all
// such as runtime.js
const scriptPredictor = ({ file }) => file === script;
if (!files.some(scriptPredictor)) {
// in some cases for differential loading file with the same name is available in both
// nomodule and module such as scripts.js
// we shall not add these attributes if that's the case
const isNoModuleType = noModuleFiles.some(scriptPredictor);
const isModuleType = moduleFiles.some(scriptPredictor);
if (isNoModuleType && !isModuleType) {
attrs.push({ name: 'nomodule', value: null }, { name: 'defer', value: null });
}
else if (isModuleType && !isNoModuleType) {
attrs.push({ name: 'type', value: 'module' });
}
else {
attrs.push({ name: 'defer', value: null });
}
}
else {
attrs.push({ name: 'defer', value: null });
}
if (params.sri) {
const content = await loadOutputFile(script);
attrs.push(..._generateSriAttributes(content));
}
const attributes = attrs
.map(attr => (attr.value === null ? attr.name : `${attr.name}="${attr.value}"`))
.join(' ');
scriptElements += `<script ${attributes}></script>`;
}
indexSource.insert(scriptInsertionPoint, scriptElements);
// Adjust base href if specified
if (typeof params.baseHref == 'string') {
let baseElement;
for (const headChild of headElement.childNodes) {
if (headChild.tagName === 'base') {
baseElement = headChild;
}
}
const baseFragment = treeAdapter.createDocumentFragment();
if (!baseElement) {
baseElement = treeAdapter.createElement('base', undefined, [
{ name: 'href', value: params.baseHref },
]);
treeAdapter.appendChild(baseFragment, baseElement);
indexSource.insert(headElement.__location.startTag.endOffset, parse5.serialize(baseFragment, { treeAdapter }));
}
else {
let hrefAttribute;
for (const attribute of baseElement.attrs) {
if (attribute.name === 'href') {
hrefAttribute = attribute;
}
}
if (hrefAttribute) {
hrefAttribute.value = params.baseHref;
}
else {
baseElement.attrs.push({ name: 'href', value: params.baseHref });
}
treeAdapter.appendChild(baseFragment, baseElement);
indexSource.replace(baseElement.__location.startOffset, baseElement.__location.endOffset, parse5.serialize(baseFragment, { treeAdapter }));
}
}
const styleElements = treeAdapter.createDocumentFragment();
for (const stylesheet of stylesheets) {
const attrs = [
{ name: 'rel', value: 'stylesheet' },
{ name: 'href', value: (params.deployUrl || '') + stylesheet },
];
if (crossOrigin !== 'none') {
attrs.push({ name: 'crossorigin', value: crossOrigin });
}
if (params.sri) {
const content = await loadOutputFile(stylesheet);
attrs.push(..._generateSriAttributes(content));
}
const element = treeAdapter.createElement('link', undefined, attrs);
treeAdapter.appendChild(styleElements, element);
}
indexSource.insert(styleInsertionPoint, parse5.serialize(styleElements, { treeAdapter }));
// Adjust document locale if specified
if (typeof params.lang == 'string') {
const htmlFragment = treeAdapter.createDocumentFragment();
let langAttribute;
for (const attribute of htmlElement.attrs) {
if (attribute.name === 'lang') {
langAttribute = attribute;
}
}
if (langAttribute) {
langAttribute.value = params.lang;
}
else {
htmlElement.attrs.push({ name: 'lang', value: params.lang });
}
// we want only openning tag
htmlElement.childNodes = [];
treeAdapter.appendChild(htmlFragment, htmlElement);
indexSource.replace(htmlElement.__location.startTag.startOffset, htmlElement.__location.startTag.endOffset - 1, parse5.serialize(htmlFragment, { treeAdapter }).replace('</html>', ''));
}
return indexSource.source();
}
exports.augmentIndexHtml = augmentIndexHtml;
function _generateSriAttributes(content) {
const algo = 'sha384';
const hash = crypto_1.createHash(algo)
.update(content, 'utf8')
.digest('base64');
return [{ name: 'integrity', value: `${algo}-${hash}` }];
}
/**
* @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 { EmittedFiles } from '@angular-devkit/build-webpack';
import { Path, virtualFs } from '@angular-devkit/core';
import { Observable } from 'rxjs';
import { ExtraEntryPoint } from '../../../browser/schema';
import { CrossOriginValue } from './augment-index-html';
export interface WriteIndexHtmlOptions {
host: virtualFs.Host;
outputPath: Path;
indexPath: Path;
files?: EmittedFiles[];
noModuleFiles?: EmittedFiles[];
moduleFiles?: EmittedFiles[];
baseHref?: string;
deployUrl?: string;
sri?: boolean;
scripts?: ExtraEntryPoint[];
styles?: ExtraEntryPoint[];
postTransform?: IndexHtmlTransform;
crossOrigin?: CrossOriginValue;
lang?: string;
}
export declare type IndexHtmlTransform = (content: string) => Promise<string>;
export declare function writeIndexHtml({ host, outputPath, indexPath, files, noModuleFiles, moduleFiles, baseHref, deployUrl, sri, scripts, styles, postTransform, crossOrigin, lang, }: WriteIndexHtmlOptions): Observable<void>;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@angular-devkit/core");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const package_chunk_sort_1 = require("../package-chunk-sort");
const strip_bom_1 = require("../strip-bom");
const augment_index_html_1 = require("./augment-index-html");
function writeIndexHtml({ host, outputPath, indexPath, files = [], noModuleFiles = [], moduleFiles = [], baseHref, deployUrl, sri = false, scripts = [], styles = [], postTransform, crossOrigin, lang, }) {
return host.read(indexPath).pipe(operators_1.map(content => strip_bom_1.stripBom(core_1.virtualFs.fileBufferToString(content))), operators_1.switchMap(content => augment_index_html_1.augmentIndexHtml({
input: core_1.getSystemPath(outputPath),
inputContent: content,
baseHref,
deployUrl,
crossOrigin,
sri,
entrypoints: package_chunk_sort_1.generateEntryPoints({ scripts, styles }),
files: filterAndMapBuildFiles(files, ['.js', '.css']),
noModuleFiles: filterAndMapBuildFiles(noModuleFiles, '.js'),
moduleFiles: filterAndMapBuildFiles(moduleFiles, '.js'),
loadOutputFile: async (filePath) => {
return host
.read(core_1.join(core_1.dirname(outputPath), filePath))
.pipe(operators_1.map(data => core_1.virtualFs.fileBufferToString(data)))
.toPromise();
},
lang: lang,
})), operators_1.switchMap(content => (postTransform ? postTransform(content) : rxjs_1.of(content))), operators_1.map(content => core_1.virtualFs.stringToFileBuffer(content)), operators_1.switchMap(content => host.write(outputPath, content)));
}
exports.writeIndexHtml = writeIndexHtml;
function filterAndMapBuildFiles(files, extensionFilter) {
const filteredFiles = [];
const validExtensions = Array.isArray(extensionFilter)
? extensionFilter
: [extensionFilter];
for (const { file, name, extension, initial } of files) {
if (name && initial && validExtensions.includes(extension)) {
filteredFiles.push({ file, extension, name });
}
}
return filteredFiles;
}
/**
* @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
*/
export declare function isDirectory(path: string): boolean;
"use strict";
/**
* @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
*/
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
function isDirectory(path) {
try {
return fs.statSync(path).isDirectory();
}
catch (_) {
return false;
}
}
exports.isDirectory = isDirectory;
/**
* @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 { ExtraEntryPoint } from '../../browser/schema';
export declare function generateEntryPoints(appConfig: {
styles: ExtraEntryPoint[];
scripts: ExtraEntryPoint[];
}): string[];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../models/webpack-configs/utils");
function generateEntryPoints(appConfig) {
// Add all styles/scripts, except lazy-loaded ones.
const extraEntryPoints = (extraEntryPoints, defaultBundleName) => {
const entryPoints = utils_1.normalizeExtraEntryPoints(extraEntryPoints, defaultBundleName)
.filter(entry => entry.inject)
.map(entry => entry.bundleName);
// remove duplicates
return [...new Set(entryPoints)];
};
const entryPoints = [
'runtime',
'polyfills-es5',
'polyfills',
'sw-register',
...extraEntryPoints(appConfig.styles, 'styles'),
...extraEntryPoints(appConfig.scripts, 'scripts'),
'vendor',
'main',
];
const duplicates = [
...new Set(entryPoints.filter(x => entryPoints.indexOf(x) !== entryPoints.lastIndexOf(x))),
];
if (duplicates.length > 0) {
throw new Error(`Multiple bundles have been named the same: '${duplicates.join(`', '`)}'.`);
}
return entryPoints;
}
exports.generateEntryPoints = generateEntryPoints;
/**
* @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 { ParsedConfiguration } from '@angular/compiler-cli';
/**
* Reads and parses a given TsConfig file.
*
* @param tsconfigPath - An absolute or relative path from 'workspaceRoot' of the tsconfig file.
* @param workspaceRoot - workspaceRoot root location when provided
* it will resolve 'tsconfigPath' from this path.
*/
export declare function readTsconfig(tsconfigPath: string, workspaceRoot?: string): ParsedConfiguration;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
/**
* Reads and parses a given TsConfig file.
*
* @param tsconfigPath - An absolute or relative path from 'workspaceRoot' of the tsconfig file.
* @param workspaceRoot - workspaceRoot root location when provided
* it will resolve 'tsconfigPath' from this path.
*/
function readTsconfig(tsconfigPath, workspaceRoot) {
const tsConfigFullPath = workspaceRoot
? path.resolve(workspaceRoot, tsconfigPath)
: tsconfigPath;
// We use 'ng' instead of 'ts' here because 'ts' is not aware of 'angularCompilerOptions'
// and will not merged them if they are at un upper level tsconfig file when using `extends`.
const ng = require('@angular/compiler-cli');
const configResult = ng.readConfiguration(tsConfigFullPath);
if (configResult.errors && configResult.errors.length) {
throw new Error(ng.formatDiagnostics(configResult.errors));
}
return configResult;
}
exports.readTsconfig = readTsconfig;
/**
* @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 { Path, virtualFs } from '@angular-devkit/core';
export declare function augmentAppWithServiceWorker(host: virtualFs.Host, projectRoot: Path, appRoot: Path, outputPath: Path, baseHref: string, ngswConfigPath?: string): Promise<void>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 core_1 = require("@angular-devkit/core");
const crypto = require("crypto");
class CliFilesystem {
constructor(_host, base) {
this._host = _host;
this.base = base;
}
list(path) {
return this._recursiveList(this._resolve(path), []).catch(() => []);
}
async read(path) {
return core_1.virtualFs.fileBufferToString(await this._readIntoBuffer(path));
}
async hash(path) {
const sha1 = crypto.createHash('sha1');
sha1.update(Buffer.from(await this._readIntoBuffer(path)));
return sha1.digest('hex');
}
write(path, content) {
return this._host.write(this._resolve(path), core_1.virtualFs.stringToFileBuffer(content))
.toPromise();
}
_readIntoBuffer(path) {
return this._host.read(this._resolve(path)).toPromise();
}
_resolve(path) {
return core_1.join(core_1.normalize(this.base), core_1.normalize(path));
}
async _recursiveList(path, items) {
const fragments = await this._host.list(path).toPromise();
for (const fragment of fragments) {
const item = core_1.join(path, fragment);
if (await this._host.isDirectory(item).toPromise()) {
await this._recursiveList(item, items);
}
else {
items.push('/' + core_1.relative(core_1.normalize(this.base), item));
}
}
return items;
}
}
async function augmentAppWithServiceWorker(host, projectRoot, appRoot, outputPath, baseHref, ngswConfigPath) {
const distPath = core_1.normalize(outputPath);
const systemProjectRoot = core_1.getSystemPath(projectRoot);
// Find the service worker package
const workerPath = core_1.normalize(require.resolve('@angular/service-worker/ngsw-worker.js', { paths: [systemProjectRoot] }));
const swConfigPath = require.resolve('@angular/service-worker/config', { paths: [systemProjectRoot] });
// Determine the configuration file path
let configPath;
if (ngswConfigPath) {
configPath = core_1.normalize(ngswConfigPath);
}
else {
configPath = core_1.join(appRoot, 'ngsw-config.json');
}
// Ensure the configuration file exists
const configExists = await host.exists(configPath).toPromise();
if (!configExists) {
throw new Error(core_1.tags.oneLine `
Error: Expected to find an ngsw-config.json configuration
file in the ${core_1.getSystemPath(appRoot)} folder. Either provide one or disable Service Worker
in your angular.json configuration file.
`);
}
// Read the configuration file
const config = JSON.parse(core_1.virtualFs.fileBufferToString(await host.read(configPath).toPromise()));
// Generate the manifest
const GeneratorConstructor = require(swConfigPath).Generator;
const generator = new GeneratorConstructor(new CliFilesystem(host, outputPath), baseHref);
const output = await generator.process(config);
// Write the manifest
const manifest = JSON.stringify(output, null, 2);
await host.write(core_1.join(distPath, 'ngsw.json'), core_1.virtualFs.stringToFileBuffer(manifest)).toPromise();
// Write the worker code
// NOTE: This is inefficient (kernel -> userspace -> kernel).
// `fs.copyFile` would be a better option but breaks the host abstraction
const workerCode = await host.read(workerPath).toPromise();
await host.write(core_1.join(distPath, 'ngsw-worker.js'), workerCode).toPromise();
// If present, write the safety worker code
const safetyPath = core_1.join(core_1.dirname(workerPath), 'safety-worker.js');
if (await host.exists(safetyPath).toPromise()) {
const safetyCode = await host.read(safetyPath).toPromise();
await host.write(core_1.join(distPath, 'worker-basic.min.js'), safetyCode).toPromise();
await host.write(core_1.join(distPath, 'safety-worker.js'), safetyCode).toPromise();
}
}
exports.augmentAppWithServiceWorker = augmentAppWithServiceWorker;
export declare function formatSize(size: number): string;
export declare function generateBundleStats(info: {
id: string | number;
size?: number;
files: string[];
names?: string[];
entry: boolean;
initial: boolean;
rendered?: boolean;
}, colors: boolean): string;
export declare function generateBuildStats(hash: string, time: number, colors: boolean): string;
export declare function statsToString(json: any, statsConfig: any): string;
export declare function statsWarningsToString(json: any, statsConfig: any): string;
export declare function statsErrorsToString(json: any, statsConfig: any): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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
*/
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
const core_1 = require("@angular-devkit/core");
const path = require("path");
const { bold, green, red, reset, white, yellow } = core_1.terminal;
function formatSize(size) {
if (size <= 0) {
return '0 bytes';
}
const abbreviations = ['bytes', 'kB', 'MB', 'GB'];
const index = Math.floor(Math.log(size) / Math.log(1024));
return `${+(size / Math.pow(1024, index)).toPrecision(3)} ${abbreviations[index]}`;
}
exports.formatSize = formatSize;
function generateBundleStats(info, colors) {
const g = (x) => (colors ? bold(green(x)) : x);
const y = (x) => (colors ? bold(yellow(x)) : x);
const id = info.id ? y(info.id.toString()) : '';
const size = typeof info.size === 'number' ? ` ${formatSize(info.size)}` : '';
const files = info.files.map(f => path.basename(f)).join(', ');
const names = info.names ? ` (${info.names.join(', ')})` : '';
const initial = y(info.entry ? '[entry]' : info.initial ? '[initial]' : '');
const flags = ['rendered', 'recorded']
.map(f => (f && info[f] ? g(` [${f}]`) : ''))
.join('');
return `chunk {${id}} ${g(files)}${names}${size} ${initial}${flags}`;
}
exports.generateBundleStats = generateBundleStats;
function generateBuildStats(hash, time, colors) {
const w = (x) => colors ? bold(white(x)) : x;
return `Date: ${w(new Date().toISOString())} - Hash: ${w(hash)} - Time: ${w('' + time)}ms`;
}
exports.generateBuildStats = generateBuildStats;
function statsToString(json, statsConfig) {
const colors = statsConfig.colors;
const rs = (x) => colors ? reset(x) : x;
const w = (x) => colors ? bold(white(x)) : x;
const changedChunksStats = json.chunks
.filter((chunk) => chunk.rendered)
.map((chunk) => {
const assets = json.assets.filter((asset) => chunk.files.indexOf(asset.name) != -1);
const summedSize = assets.filter((asset) => !asset.name.endsWith(".map")).reduce((total, asset) => { return total + asset.size; }, 0);
return generateBundleStats({ ...chunk, size: summedSize }, colors);
});
const unchangedChunkNumber = json.chunks.length - changedChunksStats.length;
if (unchangedChunkNumber > 0) {
return '\n' + rs(core_1.tags.stripIndents `
Date: ${w(new Date().toISOString())} - Hash: ${w(json.hash)}
${unchangedChunkNumber} unchanged chunks
${changedChunksStats.join('\n')}
Time: ${w('' + json.time)}ms
`);
}
else {
return '\n' + rs(core_1.tags.stripIndents `
${changedChunksStats.join('\n')}
Date: ${w(new Date().toISOString())} - Hash: ${w(json.hash)} - Time: ${w('' + json.time)}ms
`);
}
}
exports.statsToString = statsToString;
// TODO(#16193): Don't emit this warning in the first place rather than just suppressing it.
const ERRONEOUS_WARNINGS = [
/multiple assets emit different content.*3rdpartylicenses\.txt/i,
];
function statsWarningsToString(json, statsConfig) {
const colors = statsConfig.colors;
const rs = (x) => colors ? reset(x) : x;
const y = (x) => colors ? bold(yellow(x)) : x;
return rs('\n' + json.warnings
.map((warning) => `${warning}`)
.filter((warning) => !ERRONEOUS_WARNINGS.some((erroneous) => erroneous.test(warning)))
.map((warning) => y(`WARNING in ${warning}`))
.join('\n\n'));
}
exports.statsWarningsToString = statsWarningsToString;
function statsErrorsToString(json, statsConfig) {
const colors = statsConfig.colors;
const rs = (x) => colors ? reset(x) : x;
const r = (x) => colors ? bold(red(x)) : x;
return rs('\n' + json.errors.map((error) => r(`ERROR in ${error}`)).join('\n'));
}
exports.statsErrorsToString = statsErrorsToString;
/**
* @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
*/
export declare function stripBom(data: string): string;
"use strict";
/**
* @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
*/
// tslint:disable
// TODO: cleanup this file, it's copied as is from Angular CLI.
Object.defineProperty(exports, "__esModule", { value: true });
// Strip BOM from file data.
// https://stackoverflow.com/questions/24356713
function stripBom(data) {
return data.replace(/^\uFEFF/, '');
}
exports.stripBom = stripBom;
import { JsonObject } from '@angular-devkit/core';
import { Schema as BuildWebpackAppShellSchema } from './schema';
declare const _default: import("@angular-devkit/architect/src/internal").Builder<JsonObject & BuildWebpackAppShellSchema>;
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 architect_1 = require("@angular-devkit/architect");
const core_1 = require("@angular-devkit/core");
const node_1 = require("@angular-devkit/core/node");
const fs = require("fs");
const path = require("path");
const service_worker_1 = require("../angular-cli-files/utilities/service-worker");
async function _renderUniversal(options, context, browserResult, serverResult) {
// Get browser target options.
const browserTarget = architect_1.targetFromTargetString(options.browserTarget);
const rawBrowserOptions = await context.getTargetOptions(browserTarget);
const browserBuilderName = await context.getBuilderNameForTarget(browserTarget);
const browserOptions = await context.validateOptions(rawBrowserOptions, browserBuilderName);
// Initialize zone.js
const root = context.workspaceRoot;
const zonePackage = require.resolve('zone.js', { paths: [root] });
await Promise.resolve().then(() => require(zonePackage));
const host = new node_1.NodeJsSyncHost();
const projectName = context.target && context.target.project;
if (!projectName) {
throw new Error('The builder requires a target.');
}
const projectMetadata = await context.getProjectMetadata(projectName);
const projectRoot = core_1.resolve(core_1.normalize(root), core_1.normalize(projectMetadata.root || ''));
for (const outputPath of browserResult.outputPaths) {
const localeDirectory = path.relative(browserResult.baseOutputPath, outputPath);
const browserIndexOutputPath = path.join(outputPath, 'index.html');
const indexHtml = fs.readFileSync(browserIndexOutputPath, 'utf8');
const serverBundlePath = await _getServerModuleBundlePath(options, context, serverResult, localeDirectory);
const { AppServerModule, AppServerModuleNgFactory, renderModule, renderModuleFactory, } = await Promise.resolve().then(() => require(serverBundlePath));
let renderModuleFn;
let AppServerModuleDef;
if (renderModuleFactory && AppServerModuleNgFactory) {
renderModuleFn = renderModuleFactory;
AppServerModuleDef = AppServerModuleNgFactory;
}
else if (renderModule && AppServerModule) {
renderModuleFn = renderModule;
AppServerModuleDef = AppServerModule;
}
else {
throw new Error(`renderModule method and/or AppServerModule were not exported from: ${serverBundlePath}.`);
}
// Load platform server module renderer
const renderOpts = {
document: indexHtml,
url: options.route,
};
const html = await renderModuleFn(AppServerModuleDef, renderOpts);
// Overwrite the client index file.
const outputIndexPath = options.outputIndexPath
? path.join(root, options.outputIndexPath)
: browserIndexOutputPath;
fs.writeFileSync(outputIndexPath, html);
if (browserOptions.serviceWorker) {
await service_worker_1.augmentAppWithServiceWorker(host, core_1.normalize(root), projectRoot, core_1.normalize(outputPath), browserOptions.baseHref || '/', browserOptions.ngswConfigPath);
}
}
return browserResult;
}
async function _getServerModuleBundlePath(options, context, serverResult, browserLocaleDirectory) {
if (options.appModuleBundle) {
return path.join(context.workspaceRoot, options.appModuleBundle);
}
else {
const { baseOutputPath = '' } = serverResult;
const outputPath = path.join(baseOutputPath, browserLocaleDirectory);
if (!fs.existsSync(outputPath)) {
throw new Error(`Could not find server output directory: ${outputPath}.`);
}
const files = fs.readdirSync(outputPath, 'utf8');
const re = /^main\.(?:[a-zA-Z0-9]{20}\.)?(?:bundle\.)?js$/;
const maybeMain = files.filter(x => re.test(x))[0];
if (!maybeMain) {
throw new Error('Could not find the main bundle.');
}
else {
return path.join(outputPath, maybeMain);
}
}
}
async function _appShellBuilder(options, context) {
const browserTarget = architect_1.targetFromTargetString(options.browserTarget);
const serverTarget = architect_1.targetFromTargetString(options.serverTarget);
// Never run the browser target in watch mode.
// If service worker is needed, it will be added in _renderUniversal();
const browserTargetRun = await context.scheduleTarget(browserTarget, {
watch: false,
serviceWorker: false,
});
const serverTargetRun = await context.scheduleTarget(serverTarget, {
watch: false,
});
try {
const [browserResult, serverResult] = await Promise.all([
browserTargetRun.result,
serverTargetRun.result,
]);
if (browserResult.success === false || browserResult.baseOutputPath === undefined) {
return browserResult;
}
else if (serverResult.success === false) {
return serverResult;
}
return await _renderUniversal(options, context, browserResult, serverResult);
}
catch (err) {
return { success: false, error: err.message };
}
finally {
// Just be good citizens and stop those jobs.
await Promise.all([browserTargetRun.stop(), serverTargetRun.stop()]);
}
}
exports.default = architect_1.createBuilder(_appShellBuilder);
/**
* App Shell target options for Build Facade.
*/
export interface Schema {
/**
* Script that exports the Server AppModule to render. This should be the main JavaScript
* outputted by the server target. By default we will resolve the outputPath of the
* serverTarget and find a bundle named 'main' in it (whether or not there's a hash tag).
*/
appModuleBundle?: string;
/**
* Target to build.
*/
browserTarget: string;
/**
* The input path for the index.html file. By default uses the output index.html of the
* browser target.
*/
inputIndexPath?: string;
/**
* The output path of the index.html file. By default will overwrite the input file.
*/
outputIndexPath?: string;
/**
* The route to render.
*/
route?: string;
/**
* Server target to use for rendering the app shell.
*/
serverTarget: string;
}
"use strict";
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
Object.defineProperty(exports, "__esModule", { value: true });
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "App Shell Target",
"description": "App Shell target options for Build Facade.",
"type": "object",
"properties": {
"browserTarget": {
"type": "string",
"description": "Target to build.",
"pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$"
},
"serverTarget": {
"type": "string",
"description": "Server target to use for rendering the app shell.",
"pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$"
},
"appModuleBundle": {
"type": "string",
"description": "Script that exports the Server AppModule to render. This should be the main JavaScript outputted by the server target. By default we will resolve the outputPath of the serverTarget and find a bundle named 'main' in it (whether or not there's a hash tag)."
},
"route": {
"type": "string",
"description": "The route to render.",
"default": "/"
},
"inputIndexPath": {
"type": "string",
"description": "The input path for the index.html file. By default uses the output index.html of the browser target."
},
"outputIndexPath": {
"type": "string",
"description": "The output path of the index.html file. By default will overwrite the input file."
}
},
"additionalProperties": false,
"required": [
"browserTarget",
"serverTarget"
]
}
/// <reference types="node" />
/**
* @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 { BuilderContext, BuilderOutput } from '@angular-devkit/architect';
import { WebpackLoggingCallback } from '@angular-devkit/build-webpack';
import { json, logging, virtualFs } from '@angular-devkit/core';
import * as fs from 'fs';
import { Observable } from 'rxjs';
import * as webpack from 'webpack';
import { IndexHtmlTransform } from '../angular-cli-files/utilities/index-file/write-index-html';
import { ExecutionTransformer } from '../transforms';
import { I18nOptions } from '../utils/i18n-options';
import { Schema as BrowserBuilderSchema } from './schema';
export declare type BrowserBuilderOutput = json.JsonObject & BuilderOutput & {
baseOutputPath: string;
outputPaths: string[];
/**
* @deprecated in version 9. Use 'outputPaths' instead.
*/
outputPath: string;
};
export declare function createBrowserLoggingCallback(verbose: boolean, logger: logging.LoggerApi): WebpackLoggingCallback;
interface ConfigFromContextReturn {
config: webpack.Configuration;
projectRoot: string;
projectSourceRoot?: string;
}
export declare function buildBrowserWebpackConfigFromContext(options: BrowserBuilderSchema, context: BuilderContext, host: virtualFs.Host<fs.Stats>, i18n: boolean): Promise<ConfigFromContextReturn & {
i18n: I18nOptions;
}>;
export declare function buildBrowserWebpackConfigFromContext(options: BrowserBuilderSchema, context: BuilderContext, host?: virtualFs.Host<fs.Stats>): Promise<ConfigFromContextReturn>;
export declare function buildWebpackBrowser(options: BrowserBuilderSchema, context: BuilderContext, transforms?: {
webpackConfiguration?: ExecutionTransformer<webpack.Configuration>;
logging?: WebpackLoggingCallback;
indexHtml?: IndexHtmlTransform;
}): Observable<BrowserBuilderOutput>;
declare const _default: import("@angular-devkit/architect/src/internal").Builder<json.JsonObject & BrowserBuilderSchema>;
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 architect_1 = require("@angular-devkit/architect");
const build_webpack_1 = require("@angular-devkit/build-webpack");
const core_1 = require("@angular-devkit/core");
const node_1 = require("@angular-devkit/core/node");
const fs = require("fs");
const path = require("path");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const typescript_1 = require("typescript");
const analytics_1 = require("../../plugins/webpack/analytics");
const webpack_configs_1 = require("../angular-cli-files/models/webpack-configs");
const async_chunks_1 = require("../angular-cli-files/utilities/async-chunks");
const bundle_calculator_1 = require("../angular-cli-files/utilities/bundle-calculator");
const write_index_html_1 = require("../angular-cli-files/utilities/index-file/write-index-html");
const read_tsconfig_1 = require("../angular-cli-files/utilities/read-tsconfig");
const service_worker_1 = require("../angular-cli-files/utilities/service-worker");
const stats_1 = require("../angular-cli-files/utilities/stats");
const utils_1 = require("../utils");
const action_executor_1 = require("../utils/action-executor");
const cache_path_1 = require("../utils/cache-path");
const copy_assets_1 = require("../utils/copy-assets");
const environment_options_1 = require("../utils/environment-options");
const i18n_inlining_1 = require("../utils/i18n-inlining");
const output_paths_1 = require("../utils/output-paths");
const version_1 = require("../utils/version");
const webpack_browser_config_1 = require("../utils/webpack-browser-config");
const cacheDownlevelPath = environment_options_1.cachingDisabled ? undefined : cache_path_1.findCachePath('angular-build-dl');
function createBrowserLoggingCallback(verbose, logger) {
return (stats, config) => {
// config.stats contains our own stats settings, added during buildWebpackConfig().
const json = stats.toJson(config.stats);
if (verbose) {
logger.info(stats.toString(config.stats));
}
else {
logger.info(stats_1.statsToString(json, config.stats));
}
if (stats.hasWarnings()) {
logger.warn(stats_1.statsWarningsToString(json, config.stats));
}
if (stats.hasErrors()) {
logger.error(stats_1.statsErrorsToString(json, config.stats));
}
};
}
exports.createBrowserLoggingCallback = createBrowserLoggingCallback;
async function buildBrowserWebpackConfigFromContext(options, context, host = new node_1.NodeJsSyncHost(), i18n = false) {
const webpackPartialGenerator = (wco) => [
webpack_configs_1.getCommonConfig(wco),
webpack_configs_1.getBrowserConfig(wco),
webpack_configs_1.getStylesConfig(wco),
webpack_configs_1.getStatsConfig(wco),
getAnalyticsConfig(wco, context),
getCompilerConfig(wco),
wco.buildOptions.webWorkerTsConfig ? webpack_configs_1.getWorkerConfig(wco) : {},
];
if (i18n) {
return webpack_browser_config_1.generateI18nBrowserWebpackConfigFromContext(options, context, webpackPartialGenerator, host);
}
return webpack_browser_config_1.generateBrowserWebpackConfigFromContext(options, context, webpackPartialGenerator, host);
}
exports.buildBrowserWebpackConfigFromContext = buildBrowserWebpackConfigFromContext;
function getAnalyticsConfig(wco, context) {
if (context.analytics) {
// If there's analytics, add our plugin. Otherwise no need to slow down the build.
let category = 'build';
if (context.builder) {
// We already vetted that this is a "safe" package, otherwise the analytics would be noop.
category =
context.builder.builderName.split(':')[1] || context.builder.builderName || 'build';
}
// The category is the builder name if it's an angular builder.
return {
plugins: [new analytics_1.NgBuildAnalyticsPlugin(wco.projectRoot, context.analytics, category, !!wco.tsConfig.options.enableIvy)],
};
}
return {};
}
function getCompilerConfig(wco) {
if (wco.buildOptions.main || wco.buildOptions.polyfills) {
return wco.buildOptions.aot ? webpack_configs_1.getAotConfig(wco) : webpack_configs_1.getNonAotConfig(wco);
}
return {};
}
async function initialize(options, context, host, webpackConfigurationTransform) {
const originalOutputPath = options.outputPath;
const { config, projectRoot, projectSourceRoot, i18n, } = await buildBrowserWebpackConfigFromContext(options, context, host, true);
let transformedConfig;
if (webpackConfigurationTransform) {
transformedConfig = await webpackConfigurationTransform(config);
}
if (options.deleteOutputPath) {
utils_1.deleteOutputDir(context.workspaceRoot, originalOutputPath);
}
return { config: transformedConfig || config, projectRoot, projectSourceRoot, i18n };
}
// tslint:disable-next-line: no-big-function
function buildWebpackBrowser(options, context, transforms = {}) {
const host = new node_1.NodeJsSyncHost();
const root = core_1.normalize(context.workspaceRoot);
const baseOutputPath = path.resolve(context.workspaceRoot, options.outputPath);
let outputPaths;
// Check Angular version.
version_1.assertCompatibleAngularVersion(context.workspaceRoot, context.logger);
return rxjs_1.from(initialize(options, context, host, transforms.webpackConfiguration)).pipe(
// tslint:disable-next-line: no-big-function
operators_1.switchMap(({ config, projectRoot, projectSourceRoot, i18n }) => {
const tsConfig = read_tsconfig_1.readTsconfig(options.tsConfig, context.workspaceRoot);
const target = tsConfig.options.target || typescript_1.ScriptTarget.ES5;
const buildBrowserFeatures = new utils_1.BuildBrowserFeatures(projectRoot, target);
const isDifferentialLoadingNeeded = buildBrowserFeatures.isDifferentialLoadingNeeded();
if (target > typescript_1.ScriptTarget.ES2015 && isDifferentialLoadingNeeded) {
context.logger.warn(core_1.tags.stripIndent `
WARNING: Using differential loading with targets ES5 and ES2016 or higher may
cause problems. Browsers with support for ES2015 will load the ES2016+ scripts
referenced with script[type="module"] but they may not support ES2016+ syntax.
`);
}
const useBundleDownleveling = isDifferentialLoadingNeeded && !options.watch;
const startTime = Date.now();
return build_webpack_1.runWebpack(config, context, {
webpackFactory: require('webpack'),
logging: transforms.logging ||
(useBundleDownleveling
? () => { }
: createBrowserLoggingCallback(!!options.verbose, context.logger)),
}).pipe(
// tslint:disable-next-line: no-big-function
operators_1.concatMap(async (buildEvent) => {
var _a, _b;
const { webpackStats: webpackRawStats, success, emittedFiles = [] } = buildEvent;
if (!webpackRawStats) {
throw new Error('Webpack stats build result is required.');
}
// Fix incorrectly set `initial` value on chunks.
const extraEntryPoints = webpack_configs_1.normalizeExtraEntryPoints(options.styles || [], 'styles')
.concat(webpack_configs_1.normalizeExtraEntryPoints(options.scripts || [], 'scripts'));
const webpackStats = {
...webpackRawStats,
chunks: async_chunks_1.markAsyncChunksNonInitial(webpackRawStats, extraEntryPoints),
};
if (!success && useBundleDownleveling) {
// If using bundle downleveling then there is only one build
// If it fails show any diagnostic messages and bail
if (webpackStats && webpackStats.warnings.length > 0) {
context.logger.warn(stats_1.statsWarningsToString(webpackStats, { colors: true }));
}
if (webpackStats && webpackStats.errors.length > 0) {
context.logger.error(stats_1.statsErrorsToString(webpackStats, { colors: true }));
}
return { success };
}
else if (success) {
outputPaths = output_paths_1.ensureOutputPaths(baseOutputPath, i18n);
let noModuleFiles;
let moduleFiles;
let files;
const scriptsEntryPointName = webpack_configs_1.normalizeExtraEntryPoints(options.scripts || [], 'scripts').map(x => x.bundleName);
if (isDifferentialLoadingNeeded && options.watch) {
moduleFiles = emittedFiles;
files = moduleFiles.filter(x => x.extension === '.css' || (x.name && scriptsEntryPointName.includes(x.name)));
if (i18n.shouldInline) {
const success = await i18n_inlining_1.i18nInlineEmittedFiles(context, emittedFiles, i18n, baseOutputPath, Array.from(outputPaths.values()), scriptsEntryPointName,
// tslint:disable-next-line: no-non-null-assertion
webpackStats.outputPath, target <= typescript_1.ScriptTarget.ES5, options.i18nMissingTranslation);
if (!success) {
return { success: false };
}
}
}
else if (isDifferentialLoadingNeeded) {
moduleFiles = [];
noModuleFiles = [];
// Common options for all bundle process actions
const sourceMapOptions = utils_1.normalizeSourceMaps(options.sourceMap || false);
const actionOptions = {
optimize: utils_1.normalizeOptimization(options.optimization).scripts,
sourceMaps: sourceMapOptions.scripts,
hiddenSourceMaps: sourceMapOptions.hidden,
vendorSourceMaps: sourceMapOptions.vendor,
integrityAlgorithm: options.subresourceIntegrity ? 'sha384' : undefined,
};
let mainChunkId;
const actions = [];
let workerReplacements;
const seen = new Set();
for (const file of emittedFiles) {
// Assets are not processed nor injected into the index
if (file.asset) {
// WorkerPlugin adds worker files to assets
if (file.file.endsWith('.worker.js')) {
if (!workerReplacements) {
workerReplacements = [];
}
workerReplacements.push([
file.file,
file.file.replace(/\-(es20\d{2}|esnext)/, '-es5'),
]);
}
else {
continue;
}
}
// Scripts and non-javascript files are not processed
if (file.extension !== '.js' ||
(file.name && scriptsEntryPointName.includes(file.name))) {
if (files === undefined) {
files = [];
}
files.push(file);
continue;
}
// Ignore already processed files; emittedFiles can contain duplicates
if (seen.has(file.file)) {
continue;
}
seen.add(file.file);
if (file.name === 'vendor' || (!mainChunkId && file.name === 'main')) {
// tslint:disable-next-line: no-non-null-assertion
mainChunkId = file.id.toString();
}
// All files at this point except ES5 polyfills are module scripts
const es5Polyfills = file.file.startsWith('polyfills-es5');
if (!es5Polyfills) {
moduleFiles.push(file);
}
// Retrieve the content/map for the file
// NOTE: Additional future optimizations will read directly from memory
// tslint:disable-next-line: no-non-null-assertion
let filename = path.join(webpackStats.outputPath, file.file);
const code = fs.readFileSync(filename, 'utf8');
let map;
if (actionOptions.sourceMaps) {
try {
map = fs.readFileSync(filename + '.map', 'utf8');
if (es5Polyfills) {
fs.unlinkSync(filename + '.map');
}
}
catch (_c) { }
}
if (es5Polyfills) {
fs.unlinkSync(filename);
filename = filename.replace(/\-es20\d{2}/, '');
}
const es2015Polyfills = file.file.startsWith('polyfills-es20');
// Record the bundle processing action
// The runtime chunk gets special processing for lazy loaded files
actions.push({
...actionOptions,
filename,
code,
map,
// id is always present for non-assets
// tslint:disable-next-line: no-non-null-assertion
name: file.id,
runtime: file.file.startsWith('runtime'),
ignoreOriginal: es5Polyfills,
optimizeOnly: es2015Polyfills,
});
// ES2015 polyfills are only optimized; optimization check was performed above
if (es2015Polyfills) {
continue;
}
// Add the newly created ES5 bundles to the index as nomodule scripts
const newFilename = es5Polyfills
? file.file.replace(/\-es20\d{2}/, '')
: file.file.replace(/\-(es20\d{2}|esnext)/, '-es5');
noModuleFiles.push({ ...file, file: newFilename });
}
const processActions = [];
let processRuntimeAction;
const processResults = [];
for (const action of actions) {
// If SRI is enabled always process the runtime bundle
// Lazy route integrity values are stored in the runtime bundle
if (action.integrityAlgorithm && action.runtime) {
processRuntimeAction = action;
}
else {
processActions.push({ replacements: workerReplacements, ...action });
}
}
const executor = new action_executor_1.BundleActionExecutor({ cachePath: cacheDownlevelPath, i18n }, options.subresourceIntegrity ? 'sha384' : undefined);
// Execute the bundle processing actions
try {
context.logger.info('Generating ES5 bundles for differential loading...');
for await (const result of executor.processAll(processActions)) {
processResults.push(result);
}
// Runtime must be processed after all other files
if (processRuntimeAction) {
const runtimeOptions = {
...processRuntimeAction,
runtimeData: processResults,
supportedBrowsers: buildBrowserFeatures.supportedBrowsers,
};
processResults.push(await Promise.resolve().then(() => require('../utils/process-bundle')).then(m => m.process(runtimeOptions)));
}
context.logger.info('ES5 bundle generation complete.');
if (i18n.shouldInline) {
context.logger.info('Generating localized bundles...');
const inlineActions = [];
const processedFiles = new Set();
for (const result of processResults) {
if (result.original) {
inlineActions.push({
filename: path.basename(result.original.filename),
code: fs.readFileSync(result.original.filename, 'utf8'),
map: result.original.map &&
fs.readFileSync(result.original.map.filename, 'utf8'),
outputPath: baseOutputPath,
es5: false,
missingTranslation: options.i18nMissingTranslation,
setLocale: result.name === mainChunkId,
});
processedFiles.add(result.original.filename);
if (result.original.map) {
processedFiles.add(result.original.map.filename);
}
}
if (result.downlevel) {
inlineActions.push({
filename: path.basename(result.downlevel.filename),
code: fs.readFileSync(result.downlevel.filename, 'utf8'),
map: result.downlevel.map &&
fs.readFileSync(result.downlevel.map.filename, 'utf8'),
outputPath: baseOutputPath,
es5: true,
missingTranslation: options.i18nMissingTranslation,
setLocale: result.name === mainChunkId,
});
processedFiles.add(result.downlevel.filename);
if (result.downlevel.map) {
processedFiles.add(result.downlevel.map.filename);
}
}
}
let hasErrors = false;
try {
for await (const result of executor.inlineAll(inlineActions)) {
if (options.verbose) {
context.logger.info(`Localized "${result.file}" [${result.count} translation(s)].`);
}
for (const diagnostic of result.diagnostics) {
if (diagnostic.type === 'error') {
hasErrors = true;
context.logger.error(diagnostic.message);
}
else {
context.logger.warn(diagnostic.message);
}
}
}
// Copy any non-processed files into the output locations
await copy_assets_1.copyAssets([
{
glob: '**/*',
// tslint:disable-next-line: no-non-null-assertion
input: webpackStats.outputPath,
output: '',
ignore: [...processedFiles].map(f =>
// tslint:disable-next-line: no-non-null-assertion
path.relative(webpackStats.outputPath, f)),
},
], Array.from(outputPaths.values()), '');
}
catch (err) {
context.logger.error('Localized bundle generation failed: ' + err.message);
return { success: false };
}
context.logger.info(`Localized bundle generation ${hasErrors ? 'failed' : 'complete'}.`);
if (hasErrors) {
return { success: false };
}
}
}
finally {
await executor.stop();
}
// Copy assets
if (options.assets) {
try {
await copy_assets_1.copyAssets(utils_1.normalizeAssetPatterns(options.assets, new core_1.virtualFs.SyncDelegateHost(host), root, core_1.normalize(projectRoot), projectSourceRoot === undefined ? undefined : core_1.normalize(projectSourceRoot)), Array.from(outputPaths.values()), context.workspaceRoot);
}
catch (err) {
context.logger.error('Unable to copy assets: ' + err.message);
return { success: false };
}
}
function generateBundleInfoStats(id, bundle, chunk) {
return stats_1.generateBundleStats({
id,
size: bundle.size,
files: bundle.map ? [bundle.filename, bundle.map.filename] : [bundle.filename],
names: chunk && chunk.names,
entry: !!chunk && chunk.names.includes('runtime'),
initial: !!chunk && chunk.initial,
rendered: true,
}, true);
}
let bundleInfoText = '';
for (const result of processResults) {
const chunk = webpackStats.chunks
&& webpackStats.chunks.find((chunk) => chunk.id.toString() === result.name);
if (result.original) {
bundleInfoText +=
'\n' + generateBundleInfoStats(result.name, result.original, chunk);
}
if (result.downlevel) {
bundleInfoText +=
'\n' + generateBundleInfoStats(result.name, result.downlevel, chunk);
}
}
const unprocessedChunks = webpackStats.chunks && webpackStats.chunks
.filter((chunk) => !processResults
.find((result) => chunk.id.toString() === result.name)) || [];
for (const chunk of unprocessedChunks) {
const asset = webpackStats.assets && webpackStats.assets.find(a => a.name === chunk.files[0]);
bundleInfoText +=
'\n' + stats_1.generateBundleStats({ ...chunk, size: asset && asset.size }, true);
}
bundleInfoText +=
'\n' +
stats_1.generateBuildStats((webpackStats && webpackStats.hash) || '<unknown>', Date.now() - startTime, true);
context.logger.info(bundleInfoText);
// Check for budget errors and display them to the user.
const budgets = options.budgets || [];
const budgetFailures = bundle_calculator_1.checkBudgets(budgets, webpackStats, processResults);
for (const { severity, message } of budgetFailures) {
const msg = `budgets: ${message}`;
switch (severity) {
case bundle_calculator_1.ThresholdSeverity.Warning:
webpackStats.warnings.push(msg);
break;
case bundle_calculator_1.ThresholdSeverity.Error:
webpackStats.errors.push(msg);
break;
default:
assertNever(severity);
break;
}
}
if (webpackStats && webpackStats.warnings.length > 0) {
context.logger.warn(stats_1.statsWarningsToString(webpackStats, { colors: true }));
}
if (webpackStats && webpackStats.errors.length > 0) {
context.logger.error(stats_1.statsErrorsToString(webpackStats, { colors: true }));
return { success: false };
}
}
else {
files = emittedFiles.filter(x => x.name !== 'polyfills-es5');
noModuleFiles = emittedFiles.filter(x => x.name === 'polyfills-es5');
if (i18n.shouldInline) {
const success = await i18n_inlining_1.i18nInlineEmittedFiles(context, emittedFiles, i18n, baseOutputPath, Array.from(outputPaths.values()), scriptsEntryPointName,
// tslint:disable-next-line: no-non-null-assertion
webpackStats.outputPath, target <= typescript_1.ScriptTarget.ES5, options.i18nMissingTranslation);
if (!success) {
return { success: false };
}
}
}
if (options.index) {
for (const [locale, outputPath] of outputPaths.entries()) {
let localeBaseHref;
if (i18n.locales[locale] && i18n.locales[locale].baseHref !== '') {
localeBaseHref = utils_1.urlJoin(options.baseHref || '', (_a = i18n.locales[locale].baseHref) !== null && _a !== void 0 ? _a : `/${locale}/`);
}
try {
await generateIndex(outputPath, options, root, files, noModuleFiles, moduleFiles, transforms.indexHtml,
// i18nLocale is used when Ivy is disabled
locale || options.i18nLocale, localeBaseHref || options.baseHref);
}
catch (err) {
return { success: false, error: mapErrorToMessage(err) };
}
}
}
if (!options.watch && options.serviceWorker) {
for (const [locale, outputPath] of outputPaths.entries()) {
let localeBaseHref;
if (i18n.locales[locale] && i18n.locales[locale].baseHref !== '') {
localeBaseHref = utils_1.urlJoin(options.baseHref || '', (_b = i18n.locales[locale].baseHref) !== null && _b !== void 0 ? _b : `/${locale}/`);
}
try {
await service_worker_1.augmentAppWithServiceWorker(host, root, core_1.normalize(projectRoot), core_1.normalize(outputPath), localeBaseHref || options.baseHref || '/', options.ngswConfigPath);
}
catch (err) {
return { success: false, error: mapErrorToMessage(err) };
}
}
}
}
return { success };
}), operators_1.map(event => ({
...event,
baseOutputPath,
outputPath: baseOutputPath,
outputPaths: outputPaths && Array.from(outputPaths.values()) || [baseOutputPath],
})));
}));
}
exports.buildWebpackBrowser = buildWebpackBrowser;
function generateIndex(baseOutputPath, options, root, files, noModuleFiles, moduleFiles, transformer, locale, baseHref) {
const host = new node_1.NodeJsSyncHost();
return write_index_html_1.writeIndexHtml({
host,
outputPath: core_1.join(core_1.normalize(baseOutputPath), webpack_browser_config_1.getIndexOutputFile(options)),
indexPath: core_1.join(core_1.normalize(root), webpack_browser_config_1.getIndexInputFile(options)),
files,
noModuleFiles,
moduleFiles,
baseHref,
deployUrl: options.deployUrl,
sri: options.subresourceIntegrity,
scripts: options.scripts,
styles: options.styles,
postTransform: transformer,
crossOrigin: options.crossOrigin,
lang: locale,
}).toPromise();
}
function mapErrorToMessage(error) {
if (error instanceof Error) {
return error.message;
}
if (typeof error === 'string') {
return error;
}
return undefined;
}
function assertNever(input) {
throw new Error(`Unexpected call to assertNever() with input: ${JSON.stringify(input, null /* replacer */, 4 /* tabSize */)}`);
}
exports.default = architect_1.createBuilder(buildWebpackBrowser);
/**
* Browser target options
*/
export interface Schema {
/**
* Build using Ahead of Time compilation.
*/
aot?: boolean;
/**
* List of static application assets.
*/
assets?: AssetPattern[];
/**
* Base url for the application being built.
*/
baseHref?: string;
/**
* Budget thresholds to ensure parts of your application stay within boundaries which you
* set.
*/
budgets?: Budget[];
/**
* Enables '@angular-devkit/build-optimizer' optimizations when using the 'aot' option.
*/
buildOptimizer?: boolean;
/**
* Use a separate bundle containing code used across multiple bundles.
*/
commonChunk?: boolean;
/**
* Define the crossorigin attribute setting of elements that provide CORS support.
*/
crossOrigin?: CrossOrigin;
/**
* Delete the output path before building.
*/
deleteOutputPath?: boolean;
/**
* URL where files will be deployed.
*/
deployUrl?: string;
/**
* Enables conditionally loaded ES2015 polyfills.
* @deprecated This will be determined from the list of supported browsers specified in the
* 'browserslist' file.
*/
es5BrowserSupport?: boolean;
/**
* Output in-file eval sourcemaps.
* @deprecated
*/
evalSourceMap?: boolean;
/**
* Concatenate modules with Rollup before bundling them with Webpack.
*/
experimentalRollupPass?: boolean;
/**
* Extract css from global styles into css files instead of js ones.
*/
extractCss?: boolean;
/**
* Extract all licenses in a separate file.
*/
extractLicenses?: boolean;
/**
* Replace files with other files in the build.
*/
fileReplacements?: FileReplacement[];
/**
* Run the TypeScript type checker in a forked process.
*/
forkTypeChecker?: boolean;
/**
* Localization file to use for i18n.
* @deprecated Use 'locales' object in the project metadata instead.
*/
i18nFile?: string;
/**
* Format of the localization file specified with --i18n-file.
* @deprecated No longer needed as the format will be determined automatically.
*/
i18nFormat?: string;
/**
* Locale to use for i18n.
* @deprecated Use 'localize' instead.
*/
i18nLocale?: string;
/**
* How to handle missing translations for i18n.
*/
i18nMissingTranslation?: I18NMissingTranslation;
/**
* Configures the generation of the application's HTML index.
*/
index: IndexUnion;
/**
* List of additional NgModule files that will be lazy loaded. Lazy router modules will be
* discovered automatically.
* @deprecated 'SystemJsNgModuleLoader' is deprecated, and this is part of its usage. Use
* 'import()' syntax instead.
*/
lazyModules?: string[];
localize?: Localize;
/**
* The full path for the main entry point to the app, relative to the current workspace.
*/
main: string;
/**
* Use file name for lazy loaded chunks.
*/
namedChunks?: boolean;
/**
* Path to ngsw-config.json.
*/
ngswConfigPath?: string;
/**
* Enables optimization of the build output.
*/
optimization?: OptimizationUnion;
/**
* Define the output filename cache-busting hashing mode.
*/
outputHashing?: OutputHashing;
/**
* The full path for the new output directory, relative to the current workspace.
*
* By default, writes output to a folder named dist/ in the current project.
*/
outputPath: string;
/**
* Enable and define the file watching poll time period in milliseconds.
*/
poll?: number;
/**
* The full path for the polyfills file, relative to the current workspace.
*/
polyfills?: string;
/**
* Do not use the real path when resolving modules.
*/
preserveSymlinks?: boolean;
/**
* Output profile events for Chrome profiler.
* @deprecated Use "NG_BUILD_PROFILING" environment variable instead.
*/
profile?: boolean;
/**
* Log progress to the console while building.
*/
progress?: boolean;
/**
* Change root relative URLs in stylesheets to include base HREF and deploy URL. Use only
* for compatibility and transition. The behavior of this option is non-standard and will be
* removed in the next major release.
* @deprecated
*/
rebaseRootRelativeCssUrls?: boolean;
/**
* The path where style resources will be placed, relative to outputPath.
*/
resourcesOutputPath?: string;
/**
* Global scripts to be included in the build.
*/
scripts?: ExtraEntryPoint[];
/**
* Generates a service worker config for production builds.
*/
serviceWorker?: boolean;
/**
* Show circular dependency warnings on builds.
*/
showCircularDependencies?: boolean;
/**
* Flag to prevent building an app shell.
* @deprecated
*/
skipAppShell?: boolean;
/**
* Output sourcemaps.
*/
sourceMap?: SourceMapUnion;
/**
* Generates a 'stats.json' file which can be analyzed using tools such as
* 'webpack-bundle-analyzer'.
*/
statsJson?: boolean;
/**
* Options to pass to style preprocessors.
*/
stylePreprocessorOptions?: StylePreprocessorOptions;
/**
* Global styles to be included in the build.
*/
styles?: ExtraEntryPoint[];
/**
* Enables the use of subresource integrity validation.
*/
subresourceIntegrity?: boolean;
/**
* The full path for the TypeScript configuration file, relative to the current workspace.
*/
tsConfig: string;
/**
* Use a separate bundle containing only vendor libraries.
*/
vendorChunk?: boolean;
/**
* Resolve vendor packages sourcemaps.
* @deprecated
*/
vendorSourceMap?: boolean;
/**
* Adds more details to output logging.
*/
verbose?: boolean;
/**
* Run build when files change.
*/
watch?: boolean;
/**
* TypeScript configuration for Web Worker modules.
*/
webWorkerTsConfig?: string;
}
export declare type AssetPattern = AssetPatternClass | string;
export interface AssetPatternClass {
/**
* The pattern to match.
*/
glob: string;
/**
* An array of globs to ignore.
*/
ignore?: string[];
/**
* The input directory path in which to apply 'glob'. Defaults to the project root.
*/
input: string;
/**
* Absolute path within the output.
*/
output: string;
}
export interface Budget {
/**
* The baseline size for comparison.
*/
baseline?: string;
/**
* The threshold for error relative to the baseline (min & max).
*/
error?: string;
/**
* The maximum threshold for error relative to the baseline.
*/
maximumError?: string;
/**
* The maximum threshold for warning relative to the baseline.
*/
maximumWarning?: string;
/**
* The minimum threshold for error relative to the baseline.
*/
minimumError?: string;
/**
* The minimum threshold for warning relative to the baseline.
*/
minimumWarning?: string;
/**
* The name of the bundle.
*/
name?: string;
/**
* The type of budget.
*/
type: Type;
/**
* The threshold for warning relative to the baseline (min & max).
*/
warning?: string;
}
/**
* The type of budget.
*/
export declare enum Type {
All = "all",
AllScript = "allScript",
Any = "any",
AnyComponentStyle = "anyComponentStyle",
AnyScript = "anyScript",
Bundle = "bundle",
Initial = "initial"
}
/**
* Define the crossorigin attribute setting of elements that provide CORS support.
*/
export declare enum CrossOrigin {
Anonymous = "anonymous",
None = "none",
UseCredentials = "use-credentials"
}
export interface FileReplacement {
replace?: string;
replaceWith?: string;
src?: string;
with?: string;
}
/**
* How to handle missing translations for i18n.
*/
export declare enum I18NMissingTranslation {
Error = "error",
Ignore = "ignore",
Warning = "warning"
}
/**
* Configures the generation of the application's HTML index.
*/
export declare type IndexUnion = IndexObject | string;
export interface IndexObject {
/**
* The path of a file to use for the application's generated HTML index.
*/
input: string;
/**
* The output path of the application's generated HTML index file. The full provided path
* will be used and will be considered relative to the application's configured output path.
*/
output?: string;
}
export declare type Localize = string[] | boolean;
/**
* Enables optimization of the build output.
*/
export declare type OptimizationUnion = boolean | OptimizationClass;
export interface OptimizationClass {
/**
* Enables optimization of the scripts output.
*/
scripts?: boolean;
/**
* Enables optimization of the styles output.
*/
styles?: boolean;
}
/**
* Define the output filename cache-busting hashing mode.
*/
export declare enum OutputHashing {
All = "all",
Bundles = "bundles",
Media = "media",
None = "none"
}
export declare type ExtraEntryPoint = ExtraEntryPointClass | string;
export interface ExtraEntryPointClass {
/**
* The bundle name for this extra entry point.
*/
bundleName?: string;
/**
* If the bundle will be referenced in the HTML file.
*/
inject?: boolean;
/**
* The file to include.
*/
input: string;
/**
* If the bundle will be lazy loaded.
*/
lazy?: boolean;
}
/**
* Output sourcemaps.
*/
export declare type SourceMapUnion = boolean | SourceMapClass;
export interface SourceMapClass {
/**
* Output sourcemaps used for error reporting tools.
*/
hidden?: boolean;
/**
* Output sourcemaps for all scripts.
*/
scripts?: boolean;
/**
* Output sourcemaps for all styles.
*/
styles?: boolean;
/**
* Resolve vendor packages sourcemaps.
*/
vendor?: boolean;
}
/**
* Options to pass to style preprocessors.
*/
export interface StylePreprocessorOptions {
/**
* Paths to include. Paths will be resolved to project root.
*/
includePaths?: string[];
}
"use strict";
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
Object.defineProperty(exports, "__esModule", { value: true });
/**
* The type of budget.
*/
var Type;
(function (Type) {
Type["All"] = "all";
Type["AllScript"] = "allScript";
Type["Any"] = "any";
Type["AnyComponentStyle"] = "anyComponentStyle";
Type["AnyScript"] = "anyScript";
Type["Bundle"] = "bundle";
Type["Initial"] = "initial";
})(Type = exports.Type || (exports.Type = {}));
/**
* Define the crossorigin attribute setting of elements that provide CORS support.
*/
var CrossOrigin;
(function (CrossOrigin) {
CrossOrigin["Anonymous"] = "anonymous";
CrossOrigin["None"] = "none";
CrossOrigin["UseCredentials"] = "use-credentials";
})(CrossOrigin = exports.CrossOrigin || (exports.CrossOrigin = {}));
/**
* How to handle missing translations for i18n.
*/
var I18NMissingTranslation;
(function (I18NMissingTranslation) {
I18NMissingTranslation["Error"] = "error";
I18NMissingTranslation["Ignore"] = "ignore";
I18NMissingTranslation["Warning"] = "warning";
})(I18NMissingTranslation = exports.I18NMissingTranslation || (exports.I18NMissingTranslation = {}));
/**
* Define the output filename cache-busting hashing mode.
*/
var OutputHashing;
(function (OutputHashing) {
OutputHashing["All"] = "all";
OutputHashing["Bundles"] = "bundles";
OutputHashing["Media"] = "media";
OutputHashing["None"] = "none";
})(OutputHashing = exports.OutputHashing || (exports.OutputHashing = {}));
{
"$schema": "http://json-schema.org/schema",
"title": "Webpack browser schema for Build Facade.",
"description": "Browser target options",
"type": "object",
"properties": {
"assets": {
"type": "array",
"description": "List of static application assets.",
"default": [],
"items": {
"$ref": "#/definitions/assetPattern"
}
},
"main": {
"type": "string",
"description": "The full path for the main entry point to the app, relative to the current workspace.",
"$valueDescription": "fileName"
},
"polyfills": {
"type": "string",
"description": "The full path for the polyfills file, relative to the current workspace."
},
"tsConfig": {
"type": "string",
"description": "The full path for the TypeScript configuration file, relative to the current workspace."
},
"scripts": {
"description": "Global scripts to be included in the build.",
"type": "array",
"default": [],
"items": {
"$ref": "#/definitions/extraEntryPoint"
}
},
"styles": {
"description": "Global styles to be included in the build.",
"type": "array",
"default": [],
"items": {
"$ref": "#/definitions/extraEntryPoint"
}
},
"stylePreprocessorOptions": {
"description": "Options to pass to style preprocessors.",
"type": "object",
"properties": {
"includePaths": {
"description": "Paths to include. Paths will be resolved to project root.",
"type": "array",
"items": {
"type": "string"
},
"default": []
}
},
"additionalProperties": false
},
"optimization": {
"description": "Enables optimization of the build output.",
"x-user-analytics": 16,
"oneOf": [
{
"type": "object",
"properties": {
"scripts": {
"type": "boolean",
"description": "Enables optimization of the scripts output.",
"default": true
},
"styles": {
"type": "boolean",
"description": "Enables optimization of the styles output.",
"default": true
}
},
"additionalProperties": false
},
{
"type": "boolean"
}
]
},
"fileReplacements": {
"description": "Replace files with other files in the build.",
"type": "array",
"items": {
"$ref": "#/definitions/fileReplacement"
},
"default": []
},
"outputPath": {
"type": "string",
"description": "The full path for the new output directory, relative to the current workspace.\n\nBy default, writes output to a folder named dist/ in the current project."
},
"resourcesOutputPath": {
"type": "string",
"description": "The path where style resources will be placed, relative to outputPath.",
"default": ""
},
"aot": {
"type": "boolean",
"description": "Build using Ahead of Time compilation.",
"x-user-analytics": 13,
"default": false
},
"sourceMap": {
"description": "Output sourcemaps.",
"default": true,
"oneOf": [
{
"type": "object",
"properties": {
"scripts": {
"type": "boolean",
"description": "Output sourcemaps for all scripts.",
"default": true
},
"styles": {
"type": "boolean",
"description": "Output sourcemaps for all styles.",
"default": true
},
"hidden": {
"type": "boolean",
"description": "Output sourcemaps used for error reporting tools.",
"default": false
},
"vendor": {
"type": "boolean",
"description": "Resolve vendor packages sourcemaps.",
"default": false
}
},
"additionalProperties": false
},
{
"type": "boolean"
}
]
},
"vendorSourceMap": {
"type": "boolean",
"description": "Resolve vendor packages sourcemaps.",
"x-deprecated": true,
"default": false
},
"evalSourceMap": {
"type": "boolean",
"description": "Output in-file eval sourcemaps.",
"default": false,
"x-deprecated": true
},
"vendorChunk": {
"type": "boolean",
"description": "Use a separate bundle containing only vendor libraries.",
"default": true
},
"commonChunk": {
"type": "boolean",
"description": "Use a separate bundle containing code used across multiple bundles.",
"default": true
},
"baseHref": {
"type": "string",
"description": "Base url for the application being built."
},
"deployUrl": {
"type": "string",
"description": "URL where files will be deployed."
},
"verbose": {
"type": "boolean",
"description": "Adds more details to output logging.",
"default": false
},
"progress": {
"type": "boolean",
"description": "Log progress to the console while building."
},
"i18nFile": {
"type": "string",
"description": "Localization file to use for i18n.",
"x-deprecated": "Use 'locales' object in the project metadata instead."
},
"i18nFormat": {
"type": "string",
"description": "Format of the localization file specified with --i18n-file.",
"x-deprecated": "No longer needed as the format will be determined automatically."
},
"i18nLocale": {
"type": "string",
"description": "Locale to use for i18n.",
"x-deprecated": "Use 'localize' instead."
},
"i18nMissingTranslation": {
"type": "string",
"description": "How to handle missing translations for i18n.",
"enum": ["warning", "error", "ignore"],
"default": "warning"
},
"localize": {
"oneOf": [
{
"type": "boolean",
"description": "Translate all locales."
},
{
"type": "array",
"description": "List of locales ID's to translate.",
"minItems": 1,
"items": {
"type": "string",
"pattern": "^[a-zA-Z]{2,3}(-[a-zA-Z]{4})?(-([a-zA-Z]{2}|[0-9]{3}))?(-[a-zA-Z]{5,8})?(-x(-[a-zA-Z0-9]{1,8})+)?$"
}
}
]
},
"extractCss": {
"type": "boolean",
"description": "Extract css from global styles into css files instead of js ones.",
"default": false
},
"watch": {
"type": "boolean",
"description": "Run build when files change.",
"default": false
},
"outputHashing": {
"type": "string",
"description": "Define the output filename cache-busting hashing mode.",
"default": "none",
"enum": [
"none",
"all",
"media",
"bundles"
]
},
"poll": {
"type": "number",
"description": "Enable and define the file watching poll time period in milliseconds."
},
"deleteOutputPath": {
"type": "boolean",
"description": "Delete the output path before building.",
"default": true
},
"preserveSymlinks": {
"type": "boolean",
"description": "Do not use the real path when resolving modules.",
"default": false
},
"extractLicenses": {
"type": "boolean",
"description": "Extract all licenses in a separate file.",
"default": false
},
"showCircularDependencies": {
"type": "boolean",
"description": "Show circular dependency warnings on builds.",
"default": true
},
"buildOptimizer": {
"type": "boolean",
"description": "Enables '@angular-devkit/build-optimizer' optimizations when using the 'aot' option.",
"default": false
},
"namedChunks": {
"type": "boolean",
"description": "Use file name for lazy loaded chunks.",
"default": true
},
"subresourceIntegrity": {
"type": "boolean",
"description": "Enables the use of subresource integrity validation.",
"default": false
},
"serviceWorker": {
"type": "boolean",
"description": "Generates a service worker config for production builds.",
"default": false
},
"ngswConfigPath": {
"type": "string",
"description": "Path to ngsw-config.json."
},
"skipAppShell": {
"type": "boolean",
"description": "Flag to prevent building an app shell.",
"default": false,
"x-deprecated": true
},
"index": {
"description": "Configures the generation of the application's HTML index.",
"oneOf": [
{
"type": "string",
"description": "The path of a file to use for the application's HTML index. The filename of the specified path will be used for the generated file and will be created in the root of the application's configured output path."
},
{
"type": "object",
"description": "",
"properties": {
"input": {
"type": "string",
"minLength": 1,
"description": "The path of a file to use for the application's generated HTML index."
},
"output": {
"type": "string",
"minLength": 1,
"default": "index.html",
"description": "The output path of the application's generated HTML index file. The full provided path will be used and will be considered relative to the application's configured output path."
}
},
"required": ["input"]
}
]
},
"statsJson": {
"type": "boolean",
"description": "Generates a 'stats.json' file which can be analyzed using tools such as 'webpack-bundle-analyzer'.",
"default": false
},
"forkTypeChecker": {
"type": "boolean",
"description": "Run the TypeScript type checker in a forked process.",
"default": true
},
"lazyModules": {
"description": "List of additional NgModule files that will be lazy loaded. Lazy router modules will be discovered automatically.",
"type": "array",
"items": {
"type": "string"
},
"x-deprecated": "'SystemJsNgModuleLoader' is deprecated, and this is part of its usage. Use 'import()' syntax instead.",
"default": []
},
"budgets": {
"description": "Budget thresholds to ensure parts of your application stay within boundaries which you set.",
"type": "array",
"items": {
"$ref": "#/definitions/budget"
},
"default": []
},
"profile": {
"type": "boolean",
"description": "Output profile events for Chrome profiler.",
"default": false,
"x-deprecated": "Use \"NG_BUILD_PROFILING\" environment variable instead."
},
"es5BrowserSupport": {
"description": "Enables conditionally loaded ES2015 polyfills.",
"type": "boolean",
"x-deprecated": "This will be determined from the list of supported browsers specified in the 'browserslist' file."
},
"rebaseRootRelativeCssUrls": {
"description": "Change root relative URLs in stylesheets to include base HREF and deploy URL. Use only for compatibility and transition. The behavior of this option is non-standard and will be removed in the next major release.",
"type": "boolean",
"default": false,
"x-deprecated": true
},
"webWorkerTsConfig": {
"type": "string",
"description": "TypeScript configuration for Web Worker modules."
},
"crossOrigin": {
"type": "string",
"description": "Define the crossorigin attribute setting of elements that provide CORS support.",
"default": "none",
"enum": [
"none",
"anonymous",
"use-credentials"
]
},
"experimentalRollupPass": {
"type": "boolean",
"description": "Concatenate modules with Rollup before bundling them with Webpack.",
"default": false
}
},
"additionalProperties": false,
"required": [
"outputPath",
"index",
"main",
"tsConfig"
],
"definitions": {
"assetPattern": {
"oneOf": [
{
"type": "object",
"properties": {
"glob": {
"type": "string",
"description": "The pattern to match."
},
"input": {
"type": "string",
"description": "The input directory path in which to apply 'glob'. Defaults to the project root."
},
"ignore": {
"description": "An array of globs to ignore.",
"type": "array",
"items": {
"type": "string"
}
},
"output": {
"type": "string",
"description": "Absolute path within the output."
}
},
"additionalProperties": false,
"required": [
"glob",
"input",
"output"
]
},
{
"type": "string"
}
]
},
"fileReplacement": {
"oneOf": [
{
"type": "object",
"properties": {
"src": {
"type": "string"
},
"replaceWith": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"src",
"replaceWith"
]
},
{
"type": "object",
"properties": {
"replace": {
"type": "string"
},
"with": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"replace",
"with"
]
}
]
},
"extraEntryPoint": {
"oneOf": [
{
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "The file to include."
},
"bundleName": {
"type": "string",
"description": "The bundle name for this extra entry point."
},
"lazy": {
"type": "boolean",
"description": "If the bundle will be lazy loaded.",
"default": false,
"x-deprecated": "Use 'inject' option with 'false' value instead."
},
"inject": {
"type": "boolean",
"description": "If the bundle will be referenced in the HTML file.",
"default": true
}
},
"additionalProperties": false,
"required": [
"input"
]
},
{
"type": "string",
"description": "The file to include."
}
]
},
"budget": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "The type of budget.",
"enum": [
"all",
"allScript",
"any",
"anyScript",
"anyComponentStyle",
"bundle",
"initial"
]
},
"name": {
"type": "string",
"description": "The name of the bundle."
},
"baseline": {
"type": "string",
"description": "The baseline size for comparison."
},
"maximumWarning": {
"type": "string",
"description": "The maximum threshold for warning relative to the baseline."
},
"maximumError": {
"type": "string",
"description": "The maximum threshold for error relative to the baseline."
},
"minimumWarning": {
"type": "string",
"description": "The minimum threshold for warning relative to the baseline."
},
"minimumError": {
"type": "string",
"description": "The minimum threshold for error relative to the baseline."
},
"warning": {
"type": "string",
"description": "The threshold for warning relative to the baseline (min & max)."
},
"error": {
"type": "string",
"description": "The threshold for error relative to the baseline (min & max)."
}
},
"additionalProperties": false,
"required": [
"type"
]
}
}
}
/**
* @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 { BuilderContext } from '@angular-devkit/architect';
import { DevServerBuildOutput, WebpackLoggingCallback } from '@angular-devkit/build-webpack';
import { json, logging } from '@angular-devkit/core';
import { Observable } from 'rxjs';
import * as webpack from 'webpack';
import * as WebpackDevServer from 'webpack-dev-server';
import { IndexHtmlTransform } from '../angular-cli-files/utilities/index-file/write-index-html';
import { Schema as BrowserBuilderSchema } from '../browser/schema';
import { ExecutionTransformer } from '../transforms';
import { Schema } from './schema';
export declare type DevServerBuilderOptions = Schema & json.JsonObject;
export declare type DevServerBuilderOutput = DevServerBuildOutput & {
baseUrl: string;
};
/**
* Reusable implementation of the build angular webpack dev server builder.
* @param options Dev Server options.
* @param context The build context.
* @param transforms A map of transforms that can be used to hook into some logic (such as
* transforming webpack configuration before passing it to webpack).
*/
export declare function serveWebpackBrowser(options: DevServerBuilderOptions, context: BuilderContext, transforms?: {
webpackConfiguration?: ExecutionTransformer<webpack.Configuration>;
logging?: WebpackLoggingCallback;
indexHtml?: IndexHtmlTransform;
}): Observable<DevServerBuilderOutput>;
/**
* Create a webpack configuration for the dev server.
* @param workspaceRoot The root of the workspace. This comes from the context.
* @param serverOptions DevServer options, based on the dev server input schema.
* @param browserOptions Browser builder options. See the browser builder from this package.
* @param logger A generic logger to use for showing warnings.
* @returns A webpack dev-server configuration.
*/
export declare function buildServerConfig(workspaceRoot: string, serverOptions: DevServerBuilderOptions, browserOptions: BrowserBuilderSchema, logger: logging.LoggerApi): WebpackDevServer.Configuration;
/**
* Resolve and build a URL _path_ that will be the root of the server. This resolved base href and
* deploy URL from the browser options and returns a path from the root.
* @param serverOptions The server options that were passed to the server builder.
* @param browserOptions The browser options that were passed to the browser builder.
* @param logger A generic logger to use for showing warnings.
*/
export declare function buildServePath(serverOptions: DevServerBuilderOptions, browserOptions: BrowserBuilderSchema, logger: logging.LoggerApi): string;
declare const _default: import("@angular-devkit/architect/src/internal").Builder<DevServerBuilderOptions>;
export default _default;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const architect_1 = require("@angular-devkit/architect");
const build_webpack_1 = require("@angular-devkit/build-webpack");
const core_1 = require("@angular-devkit/core");
const node_1 = require("@angular-devkit/core/node");
const fs_1 = require("fs");
const path = require("path");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const ts = require("typescript");
const url = require("url");
const webpack = require("webpack");
const index_html_webpack_plugin_1 = require("../angular-cli-files/plugins/index-html-webpack-plugin");
const check_port_1 = require("../angular-cli-files/utilities/check-port");
const package_chunk_sort_1 = require("../angular-cli-files/utilities/package-chunk-sort");
const read_tsconfig_1 = require("../angular-cli-files/utilities/read-tsconfig");
const browser_1 = require("../browser");
const utils_1 = require("../utils");
const cache_path_1 = require("../utils/cache-path");
const version_1 = require("../utils/version");
const webpack_browser_config_1 = require("../utils/webpack-browser-config");
const open = require('open');
const devServerBuildOverriddenKeys = [
'watch',
'optimization',
'aot',
'sourceMap',
'vendorSourceMap',
'evalSourceMap',
'vendorChunk',
'commonChunk',
'baseHref',
'progress',
'poll',
'verbose',
'deployUrl',
];
async function createI18nPlugins(locale, translation, missingTranslation) {
const plugins = [];
// tslint:disable-next-line: no-implicit-dependencies
const localizeDiag = await Promise.resolve().then(() => require('@angular/localize/src/tools/src/diagnostics'));
const diagnostics = new localizeDiag.Diagnostics();
const es2015 = await Promise.resolve().then(() => require(
// tslint:disable-next-line: trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/source_files/es2015_translate_plugin'));
plugins.push(
// tslint:disable-next-line: no-any
es2015.makeEs2015TranslatePlugin(diagnostics, (translation || {}), {
missingTranslation: translation === undefined ? 'ignore' : missingTranslation,
}));
const es5 = await Promise.resolve().then(() => require(
// tslint:disable-next-line: trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/source_files/es5_translate_plugin'));
plugins.push(
// tslint:disable-next-line: no-any
es5.makeEs5TranslatePlugin(diagnostics, (translation || {}), {
missingTranslation: translation === undefined ? 'ignore' : missingTranslation,
}));
const inlineLocale = await Promise.resolve().then(() => require(
// tslint:disable-next-line: trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/source_files/locale_plugin'));
plugins.push(inlineLocale.makeLocalePlugin(locale));
return { diagnostics, plugins };
}
/**
* Reusable implementation of the build angular webpack dev server builder.
* @param options Dev Server options.
* @param context The build context.
* @param transforms A map of transforms that can be used to hook into some logic (such as
* transforming webpack configuration before passing it to webpack).
*/
// tslint:disable-next-line: no-big-function
function serveWebpackBrowser(options, context, transforms = {}) {
// Check Angular version.
version_1.assertCompatibleAngularVersion(context.workspaceRoot, context.logger);
const browserTarget = architect_1.targetFromTargetString(options.browserTarget);
const root = context.workspaceRoot;
let first = true;
const host = new node_1.NodeJsSyncHost();
const loggingFn = transforms.logging || browser_1.createBrowserLoggingCallback(!!options.verbose, context.logger);
async function setup() {
// Get the browser configuration from the target name.
const rawBrowserOptions = await context.getTargetOptions(browserTarget);
// Override options we need to override, if defined.
const overrides = Object.keys(options)
.filter(key => options[key] !== undefined && devServerBuildOverriddenKeys.includes(key))
.reduce((previous, key) => ({
...previous,
[key]: options[key],
}), {});
// In dev server we should not have budgets because of extra libs such as socks-js
overrides.budgets = undefined;
const browserName = await context.getBuilderNameForTarget(browserTarget);
const browserOptions = await context.validateOptions({ ...rawBrowserOptions, ...overrides }, browserName);
const { config, projectRoot, i18n } = await browser_1.buildBrowserWebpackConfigFromContext(browserOptions, context, host, true);
let webpackConfig = config;
const tsConfig = read_tsconfig_1.readTsconfig(browserOptions.tsConfig, context.workspaceRoot);
if (i18n.shouldInline && tsConfig.options.enableIvy !== false) {
if (i18n.inlineLocales.size > 1) {
throw new Error('The development server only supports localizing a single locale per build');
}
await setupLocalize(i18n, browserOptions, webpackConfig);
}
const port = await check_port_1.checkPort(options.port || 0, options.host || 'localhost', 4200);
const webpackDevServerConfig = (webpackConfig.devServer = buildServerConfig(root, options, browserOptions, context.logger));
if (transforms.webpackConfiguration) {
webpackConfig = await transforms.webpackConfiguration(webpackConfig);
}
return {
browserOptions,
webpackConfig,
webpackDevServerConfig,
port,
projectRoot,
};
}
return rxjs_1.from(setup()).pipe(operators_1.switchMap(({ browserOptions, webpackConfig, webpackDevServerConfig, port, projectRoot }) => {
options.port = port;
// Resolve public host and client address.
let clientAddress = url.parse(`${options.ssl ? 'https' : 'http'}://0.0.0.0:0`);
if (options.publicHost) {
let publicHost = options.publicHost;
if (!/^\w+:\/\//.test(publicHost)) {
publicHost = `${options.ssl ? 'https' : 'http'}://${publicHost}`;
}
clientAddress = url.parse(publicHost);
options.publicHost = clientAddress.host;
}
// Add live reload config.
if (options.liveReload) {
_addLiveReload(options, browserOptions, webpackConfig, clientAddress, context.logger);
}
else if (options.hmr) {
context.logger.warn('Live reload is disabled. HMR option ignored.');
}
webpackConfig.plugins = [...(webpackConfig.plugins || [])];
if (!options.watch) {
// There's no option to turn off file watching in webpack-dev-server, but
// we can override the file watcher instead.
webpackConfig.plugins.push({
// tslint:disable-next-line:no-any
apply: (compiler) => {
compiler.hooks.afterEnvironment.tap('angular-cli', () => {
compiler.watchFileSystem = { watch: () => { } };
});
},
});
}
if (browserOptions.index) {
const { scripts = [], styles = [], baseHref, tsConfig } = browserOptions;
const { options: compilerOptions } = read_tsconfig_1.readTsconfig(tsConfig, context.workspaceRoot);
const target = compilerOptions.target || ts.ScriptTarget.ES5;
const buildBrowserFeatures = new utils_1.BuildBrowserFeatures(projectRoot, target);
const entrypoints = package_chunk_sort_1.generateEntryPoints({ scripts, styles });
const moduleEntrypoints = buildBrowserFeatures.isDifferentialLoadingNeeded()
? package_chunk_sort_1.generateEntryPoints({ scripts: [], styles })
: [];
webpackConfig.plugins.push(new index_html_webpack_plugin_1.IndexHtmlWebpackPlugin({
input: path.resolve(root, webpack_browser_config_1.getIndexInputFile(browserOptions)),
output: webpack_browser_config_1.getIndexOutputFile(browserOptions),
baseHref,
moduleEntrypoints,
entrypoints,
deployUrl: browserOptions.deployUrl,
sri: browserOptions.subresourceIntegrity,
noModuleEntrypoints: ['polyfills-es5'],
postTransform: transforms.indexHtml,
crossOrigin: browserOptions.crossOrigin,
lang: browserOptions.i18nLocale,
}));
}
const normalizedOptimization = utils_1.normalizeOptimization(browserOptions.optimization);
if (normalizedOptimization.scripts || normalizedOptimization.styles) {
context.logger.error(core_1.tags.stripIndents `
****************************************************************************************
This is a simple server for use in testing or debugging Angular applications locally.
It hasn't been reviewed for security issues.
DON'T USE IT FOR PRODUCTION!
****************************************************************************************
`);
}
return build_webpack_1.runWebpackDevServer(webpackConfig, context, {
logging: loggingFn,
webpackFactory: require('webpack'),
webpackDevServerFactory: require('webpack-dev-server'),
}).pipe(operators_1.map(buildEvent => {
// Resolve serve address.
const serverAddress = url.format({
protocol: options.ssl ? 'https' : 'http',
hostname: options.host === '0.0.0.0' ? 'localhost' : options.host,
pathname: webpackDevServerConfig.publicPath,
port: buildEvent.port,
});
if (first) {
first = false;
context.logger.info(core_1.tags.oneLine `
**
Angular Live Development Server is listening on ${options.host}:${buildEvent.port},
open your browser on ${serverAddress}
**
`);
if (options.open) {
open(serverAddress);
}
}
if (buildEvent.success) {
context.logger.info(': Compiled successfully.');
}
return { ...buildEvent, baseUrl: serverAddress };
}));
}));
}
exports.serveWebpackBrowser = serveWebpackBrowser;
async function setupLocalize(i18n, browserOptions, webpackConfig) {
const locale = [...i18n.inlineLocales][0];
const localeDescription = i18n.locales[locale];
const { plugins, diagnostics } = await createI18nPlugins(locale, localeDescription && localeDescription.translation, browserOptions.i18nMissingTranslation);
// Modify main entrypoint to include locale data
if (localeDescription &&
localeDescription.dataPath &&
typeof webpackConfig.entry === 'object' &&
!Array.isArray(webpackConfig.entry) &&
webpackConfig.entry['main']) {
if (Array.isArray(webpackConfig.entry['main'])) {
webpackConfig.entry['main'].unshift(localeDescription.dataPath);
}
else {
webpackConfig.entry['main'] = [localeDescription.dataPath, webpackConfig.entry['main']];
}
}
// Get the insertion point for the i18n babel loader rule
// This is currently dependent on the rule order/construction in common.ts
// A future refactor of the webpack configuration definition will improve this situation
// tslint:disable-next-line: no-non-null-assertion
const rules = webpackConfig.module.rules;
const index = rules.findIndex(r => r.enforce === 'pre');
if (index === -1) {
throw new Error('Invalid internal webpack configuration');
}
const i18nRule = {
test: /\.(?:m?js|ts)$/,
enforce: 'post',
use: [
{
loader: require.resolve('babel-loader'),
options: {
babelrc: false,
configFile: false,
compact: false,
cacheCompression: false,
cacheDirectory: cache_path_1.findCachePath('babel-loader'),
cacheIdentifier: JSON.stringify({
buildAngular: require('../../package.json').version,
locale,
translationIntegrity: localeDescription && localeDescription.integrity,
}),
plugins,
parserOpts: {
plugins: ['dynamicImport'],
},
},
},
],
};
rules.splice(index, 0, i18nRule);
// Add a plugin to inject the i18n diagnostics
// tslint:disable-next-line: no-non-null-assertion
webpackConfig.plugins.push({
apply: (compiler) => {
compiler.hooks.thisCompilation.tap('build-angular', compilation => {
compilation.hooks.finishModules.tap('build-angular', () => {
if (!diagnostics) {
return;
}
for (const diagnostic of diagnostics.messages) {
if (diagnostic.type === 'error') {
compilation.errors.push(diagnostic.message);
}
else {
compilation.warnings.push(diagnostic.message);
}
}
diagnostics.messages.length = 0;
});
});
},
});
}
/**
* Create a webpack configuration for the dev server.
* @param workspaceRoot The root of the workspace. This comes from the context.
* @param serverOptions DevServer options, based on the dev server input schema.
* @param browserOptions Browser builder options. See the browser builder from this package.
* @param logger A generic logger to use for showing warnings.
* @returns A webpack dev-server configuration.
*/
function buildServerConfig(workspaceRoot, serverOptions, browserOptions, logger) {
// Check that the host is either localhost or prints out a message.
if (serverOptions.host
&& !/^127\.\d+\.\d+\.\d+/g.test(serverOptions.host)
&& serverOptions.host !== 'localhost') {
logger.warn(core_1.tags.stripIndent `
WARNING: This is a simple server for use in testing or debugging Angular applications
locally. It hasn't been reviewed for security issues.
Binding this server to an open connection can result in compromising your application or
computer. Using a different host than the one passed to the "--host" flag might result in
websocket connection issues. You might need to use "--disableHostCheck" if that's the
case.
`);
}
if (serverOptions.disableHostCheck) {
logger.warn(core_1.tags.oneLine `
WARNING: Running a server with --disable-host-check is a security risk.
See https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
for more information.
`);
}
const servePath = buildServePath(serverOptions, browserOptions, logger);
const { styles, scripts } = utils_1.normalizeOptimization(browserOptions.optimization);
const config = {
host: serverOptions.host,
port: serverOptions.port,
headers: { 'Access-Control-Allow-Origin': '*' },
historyApiFallback: !!browserOptions.index && {
index: `${servePath}/${webpack_browser_config_1.getIndexOutputFile(browserOptions)}`,
disableDotRule: true,
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'],
rewrites: [
{
from: new RegExp(`^(?!${servePath})/.*`),
to: context => url.format(context.parsedUrl),
},
],
},
stats: false,
compress: styles || scripts,
watchOptions: {
// Using just `--poll` will result in a value of 0 which is very likely not the intention
// A value of 0 is falsy and will disable polling rather then enable
// 500 ms is a sensible default in this case
poll: serverOptions.poll === 0 ? 500 : serverOptions.poll,
ignored: serverOptions.poll === undefined ? undefined : /[\\\/]node_modules[\\\/]/,
},
https: serverOptions.ssl,
overlay: {
errors: !(styles || scripts),
warnings: false,
},
// inline is always false, because we add live reloading scripts in _addLiveReload when needed
inline: false,
public: serverOptions.publicHost,
allowedHosts: serverOptions.allowedHosts,
disableHostCheck: serverOptions.disableHostCheck,
publicPath: servePath,
hot: serverOptions.hmr,
contentBase: false,
logLevel: 'silent',
};
if (serverOptions.ssl) {
_addSslConfig(workspaceRoot, serverOptions, config);
}
if (serverOptions.proxyConfig) {
_addProxyConfig(workspaceRoot, serverOptions, config);
}
return config;
}
exports.buildServerConfig = buildServerConfig;
/**
* Resolve and build a URL _path_ that will be the root of the server. This resolved base href and
* deploy URL from the browser options and returns a path from the root.
* @param serverOptions The server options that were passed to the server builder.
* @param browserOptions The browser options that were passed to the browser builder.
* @param logger A generic logger to use for showing warnings.
*/
function buildServePath(serverOptions, browserOptions, logger) {
let servePath = serverOptions.servePath;
if (!servePath && servePath !== '') {
const defaultPath = _findDefaultServePath(browserOptions.baseHref, browserOptions.deployUrl);
const showWarning = serverOptions.servePathDefaultWarning;
if (defaultPath == null && showWarning) {
logger.warn(core_1.tags.oneLine `
WARNING: --deploy-url and/or --base-href contain unsupported values for ng serve. Default
serve path of '/' used. Use --serve-path to override.
`);
}
servePath = defaultPath || '';
}
if (servePath.endsWith('/')) {
servePath = servePath.substr(0, servePath.length - 1);
}
if (!servePath.startsWith('/')) {
servePath = `/${servePath}`;
}
return servePath;
}
exports.buildServePath = buildServePath;
/**
* Private method to enhance a webpack config with live reload configuration.
* @private
*/
function _addLiveReload(options, browserOptions, webpackConfig, clientAddress, logger) {
if (webpackConfig.plugins === undefined) {
webpackConfig.plugins = [];
}
// Workaround node shim hoisting issues with live reload client
// Only needed in dev server mode to support live reload capabilities in all package managers
const webpackPath = path.dirname(require.resolve('webpack/package.json'));
const nodeLibsBrowserPath = require.resolve('node-libs-browser', { paths: [webpackPath] });
const nodeLibsBrowser = require(nodeLibsBrowserPath);
webpackConfig.plugins.push(new webpack.NormalModuleReplacementPlugin(/^events|url|querystring$/, (resource) => {
if (!resource.issuer) {
return;
}
if (/[\/\\]hot[\/\\]emitter\.js$/.test(resource.issuer)) {
if (resource.request === 'events') {
resource.request = nodeLibsBrowser.events;
}
}
else if (/[\/\\]webpack-dev-server[\/\\]client[\/\\]utils[\/\\]createSocketUrl\.js$/.test(resource.issuer)) {
switch (resource.request) {
case 'url':
resource.request = nodeLibsBrowser.url;
break;
case 'querystring':
resource.request = nodeLibsBrowser.querystring;
break;
}
}
}));
// This allows for live reload of page when changes are made to repo.
// https://webpack.js.org/configuration/dev-server/#devserver-inline
let webpackDevServerPath;
try {
webpackDevServerPath = require.resolve('webpack-dev-server/client');
}
catch (_a) {
throw new Error('The "webpack-dev-server" package could not be found.');
}
// If a custom path is provided the webpack dev server client drops the sockjs-node segment.
// This adds it back so that behavior is consistent when using a custom URL path
let sockjsPath = '';
if (clientAddress.pathname) {
clientAddress.pathname = path.posix.join(clientAddress.pathname, 'sockjs-node');
sockjsPath = '&sockPath=' + clientAddress.pathname;
}
const entryPoints = [`${webpackDevServerPath}?${url.format(clientAddress)}${sockjsPath}`];
if (options.hmr) {
const webpackHmrLink = 'https://webpack.js.org/guides/hot-module-replacement';
logger.warn(core_1.tags.oneLine `NOTICE: Hot Module Replacement (HMR) is enabled for the dev server.`);
const showWarning = options.hmrWarning;
if (showWarning) {
logger.info(core_1.tags.stripIndents `
The project will still live reload when HMR is enabled,
but to take advantage of HMR additional application code is required'
(not included in an Angular CLI project by default).'
See ${webpackHmrLink}
for information on working with HMR for Webpack.`);
logger.warn(core_1.tags.oneLine `To disable this warning use "hmrWarning: false" under "serve"
options in "angular.json".`);
}
entryPoints.push('webpack/hot/dev-server');
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
if (browserOptions.extractCss) {
logger.warn(core_1.tags.oneLine `NOTICE: (HMR) does not allow for CSS hot reload
when used together with '--extract-css'.`);
}
}
if (typeof webpackConfig.entry !== 'object' || Array.isArray(webpackConfig.entry)) {
webpackConfig.entry = {};
}
if (!Array.isArray(webpackConfig.entry.main)) {
webpackConfig.entry.main = [];
}
webpackConfig.entry.main.unshift(...entryPoints);
}
/**
* Private method to enhance a webpack config with SSL configuration.
* @private
*/
function _addSslConfig(root, options, config) {
let sslKey = undefined;
let sslCert = undefined;
if (options.sslKey) {
const keyPath = path.resolve(root, options.sslKey);
if (fs_1.existsSync(keyPath)) {
sslKey = fs_1.readFileSync(keyPath, 'utf-8');
}
}
if (options.sslCert) {
const certPath = path.resolve(root, options.sslCert);
if (fs_1.existsSync(certPath)) {
sslCert = fs_1.readFileSync(certPath, 'utf-8');
}
}
config.https = true;
if (sslKey != null && sslCert != null) {
config.https = {
key: sslKey,
cert: sslCert,
};
}
}
/**
* Private method to enhance a webpack config with Proxy configuration.
* @private
*/
function _addProxyConfig(root, options, config) {
let proxyConfig = {};
const proxyPath = path.resolve(root, options.proxyConfig);
if (fs_1.existsSync(proxyPath)) {
proxyConfig = require(proxyPath);
}
else {
const message = 'Proxy config file ' + proxyPath + ' does not exist.';
throw new Error(message);
}
config.proxy = proxyConfig;
}
/**
* Find the default server path. We don't want to expose baseHref and deployUrl as arguments, only
* the browser options where needed. This method should stay private (people who want to resolve
* baseHref and deployUrl should use the buildServePath exported function.
* @private
*/
function _findDefaultServePath(baseHref, deployUrl) {
if (!baseHref && !deployUrl) {
return '';
}
if (/^(\w+:)?\/\//.test(baseHref || '') || /^(\w+:)?\/\//.test(deployUrl || '')) {
// If baseHref or deployUrl is absolute, unsupported by ng serve
return null;
}
// normalize baseHref
// for ng serve the starting base is always `/` so a relative
// and root relative value are identical
const baseHrefParts = (baseHref || '').split('/').filter(part => part !== '');
if (baseHref && !baseHref.endsWith('/')) {
baseHrefParts.pop();
}
const normalizedBaseHref = baseHrefParts.length === 0 ? '/' : `/${baseHrefParts.join('/')}/`;
if (deployUrl && deployUrl[0] === '/') {
if (baseHref && baseHref[0] === '/' && normalizedBaseHref !== deployUrl) {
// If baseHref and deployUrl are root relative and not equivalent, unsupported by ng serve
return null;
}
return deployUrl;
}
// Join together baseHref and deployUrl
return `${normalizedBaseHref}${deployUrl || ''}`;
}
exports.default = architect_1.createBuilder(serveWebpackBrowser);
/**
* Dev Server target options for Build Facade.
*/
export interface Schema {
/**
* Whitelist of hosts that are allowed to access the dev server.
*/
allowedHosts?: string[];
/**
* Build using Ahead of Time compilation.
*/
aot?: boolean;
/**
* Base url for the application being built.
*/
baseHref?: string;
/**
* Target to serve.
*/
browserTarget: string;
/**
* Use a separate bundle containing code used across multiple bundles.
*/
commonChunk?: boolean;
/**
* URL where files will be deployed.
*/
deployUrl?: string;
/**
* Don't verify connected clients are part of allowed hosts.
*/
disableHostCheck?: boolean;
/**
* Output in-file eval sourcemaps.
* @deprecated
*/
evalSourceMap?: boolean;
/**
* Enable hot module replacement.
*/
hmr?: boolean;
/**
* Show a warning when the --hmr option is enabled.
*/
hmrWarning?: boolean;
/**
* Host to listen on.
*/
host?: string;
/**
* Whether to reload the page on change, using live-reload.
*/
liveReload?: boolean;
/**
* Opens the url in default browser.
*/
open?: boolean;
/**
* Enables optimization of the build output.
*/
optimization?: OptimizationUnion;
/**
* Enable and define the file watching poll time period in milliseconds.
*/
poll?: number;
/**
* Port to listen on.
*/
port?: number;
/**
* Log progress to the console while building.
*/
progress?: boolean;
/**
* Proxy configuration file.
*/
proxyConfig?: string;
/**
* The URL that the browser client (or live-reload client, if enabled) should use to connect
* to the development server. Use for a complex dev server setup, such as one with reverse
* proxies.
*/
publicHost?: string;
/**
* The pathname where the app will be served.
*/
servePath?: string;
/**
* Show a warning when deploy-url/base-href use unsupported serve path values.
*/
servePathDefaultWarning?: boolean;
/**
* Output sourcemaps.
*/
sourceMap?: SourceMapUnion;
/**
* Serve using HTTPS.
*/
ssl?: boolean;
/**
* SSL certificate to use for serving HTTPS.
*/
sslCert?: string;
/**
* SSL key to use for serving HTTPS.
*/
sslKey?: string;
/**
* Use a separate bundle containing only vendor libraries.
*/
vendorChunk?: boolean;
/**
* Resolve vendor packages sourcemaps.
* @deprecated
*/
vendorSourceMap?: boolean;
/**
* Adds more details to output logging.
*/
verbose?: boolean;
/**
* Rebuild on change.
*/
watch?: boolean;
}
/**
* Enables optimization of the build output.
*/
export declare type OptimizationUnion = boolean | OptimizationClass;
export interface OptimizationClass {
/**
* Enables optimization of the scripts output.
*/
scripts?: boolean;
/**
* Enables optimization of the styles output.
*/
styles?: boolean;
}
/**
* Output sourcemaps.
*/
export declare type SourceMapUnion = boolean | SourceMapClass;
export interface SourceMapClass {
/**
* Output sourcemaps used for error reporting tools.
*/
hidden?: boolean;
/**
* Output sourcemaps for all scripts.
*/
scripts?: boolean;
/**
* Output sourcemaps for all styles.
*/
styles?: boolean;
/**
* Resolve vendor packages sourcemaps.
*/
vendor?: boolean;
}
"use strict";
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
Object.defineProperty(exports, "__esModule", { value: true });
{
"$schema": "http://json-schema.org/schema",
"title": "Dev Server Target",
"description": "Dev Server target options for Build Facade.",
"type": "object",
"properties": {
"browserTarget": {
"type": "string",
"description": "Target to serve.",
"pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$"
},
"port": {
"type": "number",
"description": "Port to listen on.",
"default": 4200
},
"host": {
"type": "string",
"description": "Host to listen on.",
"default": "localhost"
},
"proxyConfig": {
"type": "string",
"description": "Proxy configuration file."
},
"ssl": {
"type": "boolean",
"description": "Serve using HTTPS.",
"default": false
},
"sslKey": {
"type": "string",
"description": "SSL key to use for serving HTTPS."
},
"sslCert": {
"type": "string",
"description": "SSL certificate to use for serving HTTPS."
},
"open": {
"type": "boolean",
"description": "Opens the url in default browser.",
"default": false,
"alias": "o"
},
"verbose": {
"type": "boolean",
"description": "Adds more details to output logging."
},
"liveReload": {
"type": "boolean",
"description": "Whether to reload the page on change, using live-reload.",
"default": true
},
"publicHost": {
"type": "string",
"description": "The URL that the browser client (or live-reload client, if enabled) should use to connect to the development server. Use for a complex dev server setup, such as one with reverse proxies."
},
"allowedHosts": {
"type": "array",
"description": "Whitelist of hosts that are allowed to access the dev server.",
"default": [],
"items": {
"type": "string"
}
},
"servePath": {
"type": "string",
"description": "The pathname where the app will be served."
},
"disableHostCheck": {
"type": "boolean",
"description": "Don't verify connected clients are part of allowed hosts.",
"default": false
},
"hmr": {
"type": "boolean",
"description": "Enable hot module replacement.",
"default": false
},
"watch": {
"type": "boolean",
"description": "Rebuild on change.",
"default": true
},
"hmrWarning": {
"type": "boolean",
"description": "Show a warning when the --hmr option is enabled.",
"default": true
},
"servePathDefaultWarning": {
"type": "boolean",
"description": "Show a warning when deploy-url/base-href use unsupported serve path values.",
"default": true
},
"optimization": {
"description": "Enables optimization of the build output.",
"x-user-analytics": 16,
"oneOf": [
{
"type": "object",
"properties": {
"scripts": {
"type": "boolean",
"description": "Enables optimization of the scripts output.",
"default": true
},
"styles": {
"type": "boolean",
"description": "Enables optimization of the styles output.",
"default": true
}
},
"additionalProperties": false
},
{
"type": "boolean"
}
]
},
"aot": {
"type": "boolean",
"description": "Build using Ahead of Time compilation.",
"x-user-analytics": 13
},
"sourceMap": {
"description": "Output sourcemaps.",
"oneOf": [
{
"type": "object",
"properties": {
"scripts": {
"type": "boolean",
"description": "Output sourcemaps for all scripts.",
"default": true
},
"styles": {
"type": "boolean",
"description": "Output sourcemaps for all styles.",
"default": true
},
"hidden": {
"type": "boolean",
"description": "Output sourcemaps used for error reporting tools.",
"default": false
},
"vendor": {
"type": "boolean",
"description": "Resolve vendor packages sourcemaps.",
"default": false
}
},
"additionalProperties": false
},
{
"type": "boolean"
}
]
},
"vendorSourceMap": {
"type": "boolean",
"description": "Resolve vendor packages sourcemaps.",
"x-deprecated": true
},
"evalSourceMap": {
"type": "boolean",
"description": "Output in-file eval sourcemaps.",
"x-deprecated": true
},
"vendorChunk": {
"type": "boolean",
"description": "Use a separate bundle containing only vendor libraries."
},
"commonChunk": {
"type": "boolean",
"description": "Use a separate bundle containing code used across multiple bundles."
},
"baseHref": {
"type": "string",
"description": "Base url for the application being built."
},
"deployUrl": {
"type": "string",
"description": "URL where files will be deployed."
},
"progress": {
"type": "boolean",
"description": "Log progress to the console while building."
},
"poll": {
"type": "number",
"description": "Enable and define the file watching poll time period in milliseconds."
}
},
"additionalProperties": false,
"required": [
"browserTarget"
]
}
/**
* @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 { BuilderContext } from '@angular-devkit/architect';
import { BuildResult } from '@angular-devkit/build-webpack';
import { JsonObject } from '@angular-devkit/core';
import { Schema } from './schema';
export declare type ExtractI18nBuilderOptions = Schema & JsonObject;
export declare function execute(options: ExtractI18nBuilderOptions, context: BuilderContext): Promise<BuildResult>;
declare const _default: import("@angular-devkit/architect/src/internal").Builder<JsonObject & Schema>;
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 architect_1 = require("@angular-devkit/architect");
const build_webpack_1 = require("@angular-devkit/build-webpack");
const path = require("path");
const webpack = require("webpack");
const webpack_configs_1 = require("../angular-cli-files/models/webpack-configs");
const stats_1 = require("../angular-cli-files/utilities/stats");
const i18n_options_1 = require("../utils/i18n-options");
const version_1 = require("../utils/version");
const webpack_browser_config_1 = require("../utils/webpack-browser-config");
const schema_1 = require("./schema");
function getI18nOutfile(format) {
switch (format) {
case 'xmb':
return 'messages.xmb';
case 'xlf':
case 'xlif':
case 'xliff':
case 'xlf2':
case 'xliff2':
return 'messages.xlf';
default:
throw new Error(`Unsupported format "${format}"`);
}
}
class InMemoryOutputPlugin {
apply(compiler) {
// tslint:disable-next-line:no-any
compiler.outputFileSystem = new webpack.MemoryOutputFileSystem();
}
}
async function execute(options, context) {
// Check Angular version.
version_1.assertCompatibleAngularVersion(context.workspaceRoot, context.logger);
const browserTarget = architect_1.targetFromTargetString(options.browserTarget);
const browserOptions = await context.validateOptions(await context.getTargetOptions(browserTarget), await context.getBuilderNameForTarget(browserTarget));
if (options.i18nFormat !== schema_1.Format.Xlf) {
options.format = options.i18nFormat;
}
switch (options.format) {
case schema_1.Format.Xlf:
case schema_1.Format.Xlif:
case schema_1.Format.Xliff:
options.format = schema_1.Format.Xlf;
break;
case schema_1.Format.Xlf2:
case schema_1.Format.Xliff2:
options.format = schema_1.Format.Xlf2;
break;
}
// We need to determine the outFile name so that AngularCompiler can retrieve it.
let outFile = options.outFile || getI18nOutfile(options.format);
if (options.outputPath) {
// AngularCompilerPlugin doesn't support genDir so we have to adjust outFile instead.
outFile = path.join(options.outputPath, outFile);
}
const projectName = context.target && context.target.project;
if (!projectName) {
throw new Error('The builder requires a target.');
}
// target is verified in the above call
// tslint:disable-next-line: no-non-null-assertion
const metadata = await context.getProjectMetadata(context.target);
const i18n = i18n_options_1.createI18nOptions(metadata);
const { config } = await webpack_browser_config_1.generateBrowserWebpackConfigFromContext({
...browserOptions,
optimization: {
scripts: false,
styles: false,
},
buildOptimizer: false,
i18nLocale: options.i18nLocale || i18n.sourceLocale,
i18nFormat: options.format,
i18nFile: outFile,
aot: true,
progress: options.progress,
assets: [],
scripts: [],
styles: [],
deleteOutputPath: false,
}, context, wco => [
{ plugins: [new InMemoryOutputPlugin()] },
webpack_configs_1.getCommonConfig(wco),
webpack_configs_1.getAotConfig(wco, true),
webpack_configs_1.getStylesConfig(wco),
webpack_configs_1.getStatsConfig(wco),
]);
const logging = (stats, config) => {
const json = stats.toJson({ errors: true, warnings: true });
if (stats.hasWarnings()) {
context.logger.warn(stats_1.statsWarningsToString(json, config.stats));
}
if (stats.hasErrors()) {
context.logger.error(stats_1.statsErrorsToString(json, config.stats));
}
};
return build_webpack_1.runWebpack(config, context, {
logging,
webpackFactory: await Promise.resolve().then(() => require('webpack')),
}).toPromise();
}
exports.execute = execute;
exports.default = architect_1.createBuilder(execute);
/**
* Extract i18n target options for Build Facade.
*/
export interface Schema {
/**
* Target to extract from.
*/
browserTarget: string;
/**
* Output format for the generated file.
*/
format?: Format;
/**
* Output format for the generated file.
* @deprecated Use 'format' option instead.
*/
i18nFormat?: Format;
/**
* Specifies the source language of the application.
* @deprecated Use 'i18n' project level sub-option 'sourceLocale' instead.
*/
i18nLocale?: string;
/**
* Name of the file to output.
*/
outFile?: string;
/**
* Path where output will be placed.
*/
outputPath?: string;
/**
* Log progress to the console.
*/
progress?: boolean;
}
/**
* Output format for the generated file.
*
* Output format for the generated file.
* @deprecated Use 'format' option instead.
*/
export declare enum Format {
Xlf = "xlf",
Xlf2 = "xlf2",
Xlif = "xlif",
Xliff = "xliff",
Xliff2 = "xliff2",
Xmb = "xmb"
}
"use strict";
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Output format for the generated file.
*
* Output format for the generated file.
* @deprecated Use 'format' option instead.
*/
var Format;
(function (Format) {
Format["Xlf"] = "xlf";
Format["Xlf2"] = "xlf2";
Format["Xlif"] = "xlif";
Format["Xliff"] = "xliff";
Format["Xliff2"] = "xliff2";
Format["Xmb"] = "xmb";
})(Format = exports.Format || (exports.Format = {}));
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "Extract i18n Target",
"description": "Extract i18n target options for Build Facade.",
"type": "object",
"properties": {
"browserTarget": {
"type": "string",
"description": "Target to extract from.",
"pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$"
},
"format": {
"type": "string",
"description": "Output format for the generated file.",
"default": "xlf",
"enum": [
"xmb",
"xlf",
"xlif",
"xliff",
"xlf2",
"xliff2"
]
},
"i18nFormat": {
"type": "string",
"description": "Output format for the generated file.",
"default": "xlf",
"x-deprecated": "Use 'format' option instead.",
"enum": [
"xmb",
"xlf",
"xlif",
"xliff",
"xlf2",
"xliff2"
]
},
"i18nLocale": {
"type": "string",
"description": "Specifies the source language of the application.",
"x-deprecated": "Use 'i18n' project level sub-option 'sourceLocale' instead."
},
"progress": {
"type": "boolean",
"description": "Log progress to the console.",
"default": true
},
"outputPath": {
"type": "string",
"description": "Path where output will be placed."
},
"outFile": {
"type": "string",
"description": "Name of the file to output."
}
},
"additionalProperties": false,
"required": [
"browserTarget"
]
}
/**
* @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
*/
export * from './transforms';
export { AssetPattern, AssetPatternClass as AssetPatternObject, Budget, ExtraEntryPoint, ExtraEntryPointClass as ExtraEntryPointObject, FileReplacement, OptimizationClass as OptimizationObject, OptimizationUnion, OutputHashing, Schema as BrowserBuilderOptions, SourceMapClass as SourceMapObject, SourceMapUnion, StylePreprocessorOptions, Type, } from './browser/schema';
export { buildWebpackBrowser as executeBrowserBuilder, BrowserBuilderOutput, } from './browser';
export { serveWebpackBrowser as executeDevServerBuilder, DevServerBuilderOptions, DevServerBuilderOutput, } from './dev-server';
export { execute as executeExtractI18nBuilder, ExtractI18nBuilderOptions, } from './extract-i18n';
export { execute as executeKarmaBuilder, KarmaBuilderOptions, KarmaConfigOptions, } from './karma';
export { execute as executeProtractorBuilder, ProtractorBuilderOptions, } from './protractor';
export { execute as executeServerBuilder, ServerBuilderOptions, ServerBuilderOutput, } from './server';
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
var schema_1 = require("./browser/schema");
exports.OutputHashing = schema_1.OutputHashing;
exports.Type = schema_1.Type;
var browser_1 = require("./browser");
exports.executeBrowserBuilder = browser_1.buildWebpackBrowser;
var dev_server_1 = require("./dev-server");
exports.executeDevServerBuilder = dev_server_1.serveWebpackBrowser;
var extract_i18n_1 = require("./extract-i18n");
exports.executeExtractI18nBuilder = extract_i18n_1.execute;
var karma_1 = require("./karma");
exports.executeKarmaBuilder = karma_1.execute;
var protractor_1 = require("./protractor");
exports.executeProtractorBuilder = protractor_1.execute;
var server_1 = require("./server");
exports.executeServerBuilder = server_1.execute;
/**
* @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 { BuilderContext, BuilderOutput } from '@angular-devkit/architect';
import { Observable } from 'rxjs';
import * as webpack from 'webpack';
import { ExecutionTransformer } from '../transforms';
import { Schema as KarmaBuilderOptions } from './schema';
export declare type KarmaConfigOptions = import('karma').ConfigOptions & {
buildWebpack?: unknown;
configFile?: string;
};
export declare function execute(options: KarmaBuilderOptions, context: BuilderContext, transforms?: {
webpackConfiguration?: ExecutionTransformer<webpack.Configuration>;
karmaOptions?: (options: KarmaConfigOptions) => KarmaConfigOptions;
}): Observable<BuilderOutput>;
export { KarmaBuilderOptions };
declare const _default: import("@angular-devkit/architect/src/internal").Builder<Record<string, string> & KarmaBuilderOptions>;
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 architect_1 = require("@angular-devkit/architect");
const core_1 = require("@angular-devkit/core");
const path_1 = require("path");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const webpack_configs_1 = require("../angular-cli-files/models/webpack-configs");
const single_test_transform_1 = require("../angular-cli-files/plugins/single-test-transform");
const find_tests_1 = require("../angular-cli-files/utilities/find-tests");
const version_1 = require("../utils/version");
const webpack_browser_config_1 = require("../utils/webpack-browser-config");
async function initialize(options, context, webpackConfigurationTransformer) {
const { config } = await webpack_browser_config_1.generateBrowserWebpackConfigFromContext(
// only two properties are missing:
// * `outputPath` which is fixed for tests
// * `budgets` which might be incorrect due to extra dev libs
{ ...options, outputPath: '', budgets: undefined }, context, wco => [
webpack_configs_1.getCommonConfig(wco),
webpack_configs_1.getStylesConfig(wco),
webpack_configs_1.getNonAotConfig(wco),
webpack_configs_1.getTestConfig(wco),
webpack_configs_1.getWorkerConfig(wco),
]);
// tslint:disable-next-line:no-implicit-dependencies
const karma = await Promise.resolve().then(() => require('karma'));
return [
karma,
webpackConfigurationTransformer ? await webpackConfigurationTransformer(config) : config,
];
}
function execute(options, context, transforms = {}) {
// Check Angular version.
version_1.assertCompatibleAngularVersion(context.workspaceRoot, context.logger);
return rxjs_1.from(initialize(options, context, transforms.webpackConfiguration)).pipe(operators_1.switchMap(([karma, webpackConfig]) => new rxjs_1.Observable(subscriber => {
const karmaOptions = {};
if (options.watch !== undefined) {
karmaOptions.singleRun = !options.watch;
}
// Convert browsers from a string to an array
if (options.browsers) {
karmaOptions.browsers = options.browsers.split(',');
}
if (options.reporters) {
// Split along commas to make it more natural, and remove empty strings.
const reporters = options.reporters
.reduce((acc, curr) => acc.concat(curr.split(',')), [])
.filter(x => !!x);
if (reporters.length > 0) {
karmaOptions.reporters = reporters;
}
}
// prepend special webpack loader that will transform test.ts
if (webpackConfig &&
webpackConfig.module &&
options.include &&
options.include.length > 0) {
const mainFilePath = core_1.getSystemPath(core_1.join(core_1.normalize(context.workspaceRoot), options.main));
const files = find_tests_1.findTests(options.include, path_1.dirname(mainFilePath), context.workspaceRoot);
// early exit, no reason to start karma
if (!files.length) {
subscriber.error(`Specified patterns: "${options.include.join(', ')}" did not match any spec files`);
return;
}
webpackConfig.module.rules.unshift({
test: path => path === mainFilePath,
use: {
// cannot be a simple path as it differs between environments
loader: single_test_transform_1.SingleTestTransformLoader,
options: {
files,
logger: context.logger,
},
},
});
}
// Assign additional karmaConfig options to the local ngapp config
karmaOptions.configFile = path_1.resolve(context.workspaceRoot, options.karmaConfig);
karmaOptions.buildWebpack = {
options,
webpackConfig,
// Pass onto Karma to emit BuildEvents.
successCb: () => subscriber.next({ success: true }),
failureCb: () => subscriber.next({ success: false }),
// Workaround for https://github.com/karma-runner/karma/issues/3154
// When this workaround is removed, user projects need to be updated to use a Karma
// version that has a fix for this issue.
toJSON: () => { },
logger: context.logger,
};
// Complete the observable once the Karma server returns.
const karmaServer = new karma.Server(transforms.karmaOptions ? transforms.karmaOptions(karmaOptions) : karmaOptions, () => subscriber.complete());
// karma typings incorrectly define start's return value as void
// tslint:disable-next-line:no-use-of-empty-return-value
const karmaStart = karmaServer.start();
// Cleanup, signal Karma to exit.
return () => {
// Karma only has the `stop` method start with 3.1.1, so we must defensively check.
const karmaServerWithStop = karmaServer;
if (typeof karmaServerWithStop.stop === 'function') {
return karmaStart.then(() => karmaServerWithStop.stop());
}
};
})), operators_1.defaultIfEmpty({ success: false }));
}
exports.execute = execute;
exports.default = architect_1.createBuilder(execute);
/**
* Karma target options for Build Facade.
*/
export interface Schema {
/**
* List of static application assets.
*/
assets?: AssetPattern[];
/**
* Override which browsers tests are run against.
*/
browsers?: string;
/**
* Output a code coverage report.
*/
codeCoverage?: boolean;
/**
* Globs to exclude from code coverage.
*/
codeCoverageExclude?: string[];
/**
* Defines the build environment.
* @deprecated This option has no effect.
*/
environment?: string;
/**
* Output in-file eval sourcemaps.
* @deprecated
*/
evalSourceMap?: boolean;
/**
* Replace files with other files in the build.
*/
fileReplacements?: FileReplacement[];
/**
* Globs of files to include, relative to workspace or project root.
* There are 2 special cases:
* - when a path to directory is provided, all spec files ending ".spec.@(ts|tsx)" will be
* included
* - when a path to a file is provided, and a matching spec file exists it will be included
* instead
*/
include?: string[];
/**
* The name of the Karma configuration file.
*/
karmaConfig: string;
/**
* The name of the main entry-point file.
*/
main: string;
/**
* Enable and define the file watching poll time period in milliseconds.
*/
poll?: number;
/**
* The name of the polyfills file.
*/
polyfills?: string;
/**
* Do not use the real path when resolving modules.
*/
preserveSymlinks?: boolean;
/**
* Log progress to the console while building.
*/
progress?: boolean;
/**
* Karma reporters to use. Directly passed to the karma runner.
*/
reporters?: string[];
/**
* Global scripts to be included in the build.
*/
scripts?: ExtraEntryPoint[];
/**
* Output sourcemaps.
*/
sourceMap?: SourceMapUnion;
/**
* Options to pass to style preprocessors
*/
stylePreprocessorOptions?: StylePreprocessorOptions;
/**
* Global styles to be included in the build.
*/
styles?: ExtraEntryPoint[];
/**
* The name of the TypeScript configuration file.
*/
tsConfig: string;
/**
* Resolve vendor packages sourcemaps.
* @deprecated
*/
vendorSourceMap?: boolean;
/**
* Run build when files change.
*/
watch?: boolean;
/**
* TypeScript configuration for Web Worker modules.
*/
webWorkerTsConfig?: string;
}
export declare type AssetPattern = AssetPatternClass | string;
export interface AssetPatternClass {
/**
* The pattern to match.
*/
glob: string;
/**
* An array of globs to ignore.
*/
ignore?: string[];
/**
* The input directory path in which to apply 'glob'. Defaults to the project root.
*/
input: string;
/**
* Absolute path within the output.
*/
output: string;
}
export interface FileReplacement {
replace?: string;
replaceWith?: string;
src?: string;
with?: string;
}
export declare type ExtraEntryPoint = ExtraEntryPointClass | string;
export interface ExtraEntryPointClass {
/**
* The bundle name for this extra entry point.
*/
bundleName?: string;
/**
* If the bundle will be referenced in the HTML file.
*/
inject?: boolean;
/**
* The file to include.
*/
input: string;
/**
* If the bundle will be lazy loaded.
*/
lazy?: boolean;
}
/**
* Output sourcemaps.
*/
export declare type SourceMapUnion = boolean | SourceMapClass;
export interface SourceMapClass {
/**
* Output sourcemaps for all scripts.
*/
scripts?: boolean;
/**
* Output sourcemaps for all styles.
*/
styles?: boolean;
/**
* Resolve vendor packages sourcemaps.
*/
vendor?: boolean;
}
/**
* Options to pass to style preprocessors
*/
export interface StylePreprocessorOptions {
/**
* Paths to include. Paths will be resolved to project root.
*/
includePaths?: string[];
}
"use strict";
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
Object.defineProperty(exports, "__esModule", { value: true });
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "Karma Target",
"description": "Karma target options for Build Facade.",
"type": "object",
"properties": {
"main": {
"type": "string",
"description": "The name of the main entry-point file."
},
"tsConfig": {
"type": "string",
"description": "The name of the TypeScript configuration file."
},
"karmaConfig": {
"type": "string",
"description": "The name of the Karma configuration file."
},
"polyfills": {
"type": "string",
"description": "The name of the polyfills file."
},
"assets": {
"type": "array",
"description": "List of static application assets.",
"default": [],
"items": {
"$ref": "#/definitions/assetPattern"
}
},
"scripts": {
"description": "Global scripts to be included in the build.",
"type": "array",
"default": [],
"items": {
"$ref": "#/definitions/extraEntryPoint"
}
},
"styles": {
"description": "Global styles to be included in the build.",
"type": "array",
"default": [],
"items": {
"$ref": "#/definitions/extraEntryPoint"
}
},
"stylePreprocessorOptions": {
"description": "Options to pass to style preprocessors",
"type": "object",
"properties": {
"includePaths": {
"description": "Paths to include. Paths will be resolved to project root.",
"type": "array",
"items": {
"type": "string"
},
"default": []
}
},
"additionalProperties": false
},
"environment": {
"type": "string",
"description": "Defines the build environment.",
"x-deprecated": "This option has no effect."
},
"include": {
"type": "array",
"items": {
"type": "string"
},
"description": "Globs of files to include, relative to workspace or project root. \nThere are 2 special cases:\n - when a path to directory is provided, all spec files ending \".spec.@(ts|tsx)\" will be included\n - when a path to a file is provided, and a matching spec file exists it will be included instead"
},
"sourceMap": {
"description": "Output sourcemaps.",
"default": true,
"oneOf": [
{
"type": "object",
"properties": {
"scripts": {
"type": "boolean",
"description": "Output sourcemaps for all scripts.",
"default": true
},
"styles": {
"type": "boolean",
"description": "Output sourcemaps for all styles.",
"default": true
},
"vendor": {
"type": "boolean",
"description": "Resolve vendor packages sourcemaps.",
"default": false
}
},
"additionalProperties": false
},
{
"type": "boolean"
}
]
},
"vendorSourceMap": {
"type": "boolean",
"description": "Resolve vendor packages sourcemaps.",
"x-deprecated": true,
"default": false
},
"evalSourceMap": {
"type": "boolean",
"description": "Output in-file eval sourcemaps.",
"x-deprecated": true
},
"progress": {
"type": "boolean",
"description": "Log progress to the console while building."
},
"watch": {
"type": "boolean",
"description": "Run build when files change."
},
"poll": {
"type": "number",
"description": "Enable and define the file watching poll time period in milliseconds."
},
"preserveSymlinks": {
"type": "boolean",
"description": "Do not use the real path when resolving modules.",
"default": false
},
"browsers": {
"type": "string",
"description": "Override which browsers tests are run against."
},
"codeCoverage": {
"type": "boolean",
"description": "Output a code coverage report.",
"default": false
},
"codeCoverageExclude": {
"type": "array",
"description": "Globs to exclude from code coverage.",
"items": {
"type": "string"
},
"default": []
},
"fileReplacements": {
"description": "Replace files with other files in the build.",
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"properties": {
"src": {
"type": "string"
},
"replaceWith": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"src",
"replaceWith"
]
},
{
"type": "object",
"properties": {
"replace": {
"type": "string"
},
"with": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"replace",
"with"
]
}
]
},
"default": []
},
"reporters": {
"type": "array",
"description": "Karma reporters to use. Directly passed to the karma runner.",
"items": {
"type": "string"
}
},
"webWorkerTsConfig": {
"type": "string",
"description": "TypeScript configuration for Web Worker modules."
}
},
"additionalProperties": false,
"required": [
"main",
"tsConfig",
"karmaConfig"
],
"definitions": {
"assetPattern": {
"oneOf": [
{
"type": "object",
"properties": {
"glob": {
"type": "string",
"description": "The pattern to match."
},
"input": {
"type": "string",
"description": "The input directory path in which to apply 'glob'. Defaults to the project root."
},
"output": {
"type": "string",
"description": "Absolute path within the output."
},
"ignore": {
"description": "An array of globs to ignore.",
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false,
"required": [
"glob",
"input",
"output"
]
},
{
"type": "string"
}
]
},
"extraEntryPoint": {
"oneOf": [
{
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "The file to include."
},
"bundleName": {
"type": "string",
"description": "The bundle name for this extra entry point."
},
"lazy": {
"type": "boolean",
"description": "If the bundle will be lazy loaded.",
"default": false,
"x-deprecated": "Use 'inject' option with 'false' value instead."
},
"inject": {
"type": "boolean",
"description": "If the bundle will be referenced in the HTML file.",
"default": true
}
},
"additionalProperties": false,
"required": [
"input"
]
},
{
"type": "string",
"description": "The file to include."
}
]
}
}
}
\ No newline at end of file
/**
* @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 { BuilderContext, BuilderOutput } from '@angular-devkit/architect';
import { JsonObject } from '@angular-devkit/core';
import { Schema as ProtractorBuilderOptions } from './schema';
export { ProtractorBuilderOptions };
export declare function execute(options: ProtractorBuilderOptions, context: BuilderContext): Promise<BuilderOutput>;
declare const _default: import("@angular-devkit/architect/src/internal").Builder<JsonObject & ProtractorBuilderOptions>;
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 architect_1 = require("@angular-devkit/architect");
const core_1 = require("@angular-devkit/core");
const path_1 = require("path");
const url = require("url");
const utils_1 = require("../utils");
function runProtractor(root, options) {
const additionalProtractorConfig = {
baseUrl: options.baseUrl,
specs: options.specs && options.specs.length ? options.specs : undefined,
suite: options.suite,
jasmineNodeOpts: {
grep: options.grep,
invertGrep: options.invertGrep,
},
};
// TODO: Protractor manages process.exit itself, so this target will allways quit the
// process. To work around this we run it in a subprocess.
// https://github.com/angular/protractor/issues/4160
return utils_1.runModuleAsObservableFork(root, 'protractor/built/launcher', 'init', [path_1.resolve(root, options.protractorConfig), additionalProtractorConfig]).toPromise();
}
async function updateWebdriver() {
// The webdriver-manager update command can only be accessed via a deep import.
const webdriverDeepImport = 'webdriver-manager/built/lib/cmds/update';
let path;
try {
const protractorPath = require.resolve('protractor');
path = require.resolve(webdriverDeepImport, { paths: [protractorPath] });
}
catch (error) {
if (error.code !== 'MODULE_NOT_FOUND') {
throw error;
}
}
if (!path) {
throw new Error(core_1.tags.stripIndents `
Cannot automatically find webdriver-manager to update.
Update webdriver-manager manually and run 'ng e2e --no-webdriver-update' instead.
`);
}
// tslint:disable-next-line:max-line-length no-implicit-dependencies
const webdriverUpdate = await Promise.resolve().then(() => require(path));
// run `webdriver-manager update --standalone false --gecko false --quiet`
// if you change this, update the command comment in prev line
return webdriverUpdate.program.run({
standalone: false,
gecko: false,
quiet: true,
});
}
async function execute(options, context) {
// ensure that only one of these options is used
if (options.devServerTarget && options.baseUrl) {
throw new Error(core_1.tags.stripIndents `
The 'baseUrl' option cannot be used with 'devServerTarget'.
When present, 'devServerTarget' will be used to automatically setup 'baseUrl' for Protractor.
`);
}
if (options.webdriverUpdate) {
await updateWebdriver();
}
let baseUrl = options.baseUrl;
let server;
if (options.devServerTarget) {
const target = architect_1.targetFromTargetString(options.devServerTarget);
const serverOptions = await context.getTargetOptions(target);
const overrides = { watch: false };
if (options.host !== undefined) {
overrides.host = options.host;
}
else if (typeof serverOptions.host === 'string') {
options.host = serverOptions.host;
}
else {
options.host = overrides.host = 'localhost';
}
if (options.port !== undefined) {
overrides.port = options.port;
}
else if (typeof serverOptions.port === 'number') {
options.port = serverOptions.port;
}
server = await context.scheduleTarget(target, overrides);
const result = await server.result;
if (!result.success) {
return { success: false };
}
if (typeof serverOptions.publicHost === 'string') {
let publicHost = serverOptions.publicHost;
if (!/^\w+:\/\//.test(publicHost)) {
publicHost = `${serverOptions.ssl
? 'https'
: 'http'}://${publicHost}`;
}
const clientUrl = url.parse(publicHost);
baseUrl = url.format(clientUrl);
}
else if (typeof result.baseUrl === 'string') {
baseUrl = result.baseUrl;
}
else if (typeof result.port === 'number') {
baseUrl = url.format({
protocol: serverOptions.ssl ? 'https' : 'http',
hostname: options.host,
port: result.port.toString(),
});
}
}
// Like the baseUrl in protractor config file when using the API we need to add
// a trailing slash when provide to the baseUrl.
if (baseUrl && !baseUrl.endsWith('/')) {
baseUrl += '/';
}
try {
return await runProtractor(context.workspaceRoot, { ...options, baseUrl });
}
catch (_a) {
return { success: false };
}
finally {
if (server) {
await server.stop();
}
}
}
exports.execute = execute;
exports.default = architect_1.createBuilder(execute);
/**
* Protractor target options for Build Facade.
*/
export interface Schema {
/**
* Base URL for protractor to connect to.
*/
baseUrl?: string;
/**
* Dev server target to run tests against.
*/
devServerTarget?: string;
/**
* Start Protractor's Element Explorer for debugging.
* @deprecated This option has no effect. See:
* https://github.com/angular/protractor/blob/master/docs/debugging.md#enabled-control-flow
* for alternative methods.
*/
elementExplorer?: boolean;
/**
* Execute specs whose names match the pattern, which is internally compiled to a RegExp.
*/
grep?: string;
/**
* Host to listen on.
*/
host?: string;
/**
* Invert the selection specified by the 'grep' option.
*/
invertGrep?: boolean;
/**
* The port to use to serve the application.
*/
port?: number;
/**
* The name of the Protractor configuration file.
*/
protractorConfig: string;
/**
* Override specs in the protractor config.
*/
specs?: string[];
/**
* Override suite in the protractor config.
*/
suite?: string;
/**
* Try to update webdriver.
*/
webdriverUpdate?: boolean;
}
"use strict";
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
Object.defineProperty(exports, "__esModule", { value: true });
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "Protractor Target",
"description": "Protractor target options for Build Facade.",
"type": "object",
"properties": {
"protractorConfig": {
"type": "string",
"description": "The name of the Protractor configuration file."
},
"devServerTarget": {
"type": "string",
"description": "Dev server target to run tests against.",
"pattern": "^([^:\\s]+:[^:\\s]+(:[^\\s]+)?)?$"
},
"grep": {
"type": "string",
"description": "Execute specs whose names match the pattern, which is internally compiled to a RegExp."
},
"invertGrep": {
"type": "boolean",
"description": "Invert the selection specified by the 'grep' option.",
"default": false
},
"specs": {
"type": "array",
"description": "Override specs in the protractor config.",
"default": [],
"items": {
"type": "string",
"description": "Spec name."
}
},
"suite": {
"type": "string",
"description": "Override suite in the protractor config."
},
"elementExplorer": {
"type": "boolean",
"description": "Start Protractor's Element Explorer for debugging.",
"default": false,
"x-deprecated": "This option has no effect. See: https://github.com/angular/protractor/blob/master/docs/debugging.md#enabled-control-flow for alternative methods."
},
"webdriverUpdate": {
"type": "boolean",
"description": "Try to update webdriver.",
"default": true
},
"port": {
"type": "number",
"description": "The port to use to serve the application."
},
"host": {
"type": "string",
"description": "Host to listen on."
},
"baseUrl": {
"type": "string",
"description": "Base URL for protractor to connect to."
}
},
"additionalProperties": false,
"required": [
"protractorConfig"
]
}
/**
* @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 { BuilderContext, BuilderOutput } from '@angular-devkit/architect';
import { json } from '@angular-devkit/core';
import { Observable } from 'rxjs';
import * as webpack from 'webpack';
import { ExecutionTransformer } from '../transforms';
import { Schema as ServerBuilderOptions } from './schema';
export declare type ServerBuilderOutput = json.JsonObject & BuilderOutput & {
baseOutputPath: string;
outputPaths: string[];
/**
* @deprecated in version 9. Use 'outputPaths' instead.
*/
outputPath: string;
};
export { ServerBuilderOptions };
export declare function execute(options: ServerBuilderOptions, context: BuilderContext, transforms?: {
webpackConfiguration?: ExecutionTransformer<webpack.Configuration>;
}): Observable<ServerBuilderOutput>;
declare const _default: import("@angular-devkit/architect/src/internal").Builder<json.JsonObject & ServerBuilderOptions>;
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 architect_1 = require("@angular-devkit/architect");
const build_webpack_1 = require("@angular-devkit/build-webpack");
const core_1 = require("@angular-devkit/core");
const path = require("path");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const typescript_1 = require("typescript");
const webpack_configs_1 = require("../angular-cli-files/models/webpack-configs");
const read_tsconfig_1 = require("../angular-cli-files/utilities/read-tsconfig");
const utils_1 = require("../utils");
const i18n_inlining_1 = require("../utils/i18n-inlining");
const output_paths_1 = require("../utils/output-paths");
const version_1 = require("../utils/version");
const webpack_browser_config_1 = require("../utils/webpack-browser-config");
function execute(options, context, transforms = {}) {
const root = context.workspaceRoot;
// Check Angular version.
version_1.assertCompatibleAngularVersion(root, context.logger);
const tsConfig = read_tsconfig_1.readTsconfig(options.tsConfig, root);
const target = tsConfig.options.target || typescript_1.ScriptTarget.ES5;
const baseOutputPath = path.resolve(root, options.outputPath);
let outputPaths;
if (typeof options.bundleDependencies === 'string') {
options.bundleDependencies = options.bundleDependencies === 'all';
context.logger.warn(`Option 'bundleDependencies' string value is deprecated since version 9. Use a boolean value instead.`);
}
if (!options.bundleDependencies && tsConfig.options.enableIvy) {
// tslint:disable-next-line: no-implicit-dependencies
const { __processed_by_ivy_ngcc__, main = '' } = require('@angular/core/package.json');
if (!__processed_by_ivy_ngcc__ ||
!__processed_by_ivy_ngcc__.main ||
main.includes('__ivy_ngcc__')) {
context.logger.warn(core_1.tags.stripIndent `
WARNING: Turning off 'bundleDependencies' with Ivy may result in undefined behaviour
unless 'node_modules' are transformed using the standalone Angular compatibility compiler (NGCC).
See: http://v9.angular.io/guide/ivy#ivy-and-universal-app-shell
`);
}
}
return rxjs_1.from(initialize(options, context, transforms.webpackConfiguration)).pipe(operators_1.concatMap(({ config, i18n }) => {
return build_webpack_1.runWebpack(config, context, {
webpackFactory: require('webpack'),
}).pipe(operators_1.concatMap(async (output) => {
const { emittedFiles = [], webpackStats } = output;
if (!output.success || !i18n.shouldInline) {
return output;
}
if (!webpackStats) {
throw new Error('Webpack stats build result is required.');
}
outputPaths = output_paths_1.ensureOutputPaths(baseOutputPath, i18n);
const success = await i18n_inlining_1.i18nInlineEmittedFiles(context, emittedFiles, i18n, baseOutputPath, Array.from(outputPaths.values()), [],
// tslint:disable-next-line: no-non-null-assertion
webpackStats.outputPath, target <= typescript_1.ScriptTarget.ES5, options.i18nMissingTranslation);
return { output, success };
}));
}), operators_1.map(output => {
if (!output.success) {
return output;
}
return {
...output,
baseOutputPath,
outputPath: baseOutputPath,
outputPaths: outputPaths || [baseOutputPath],
};
}));
}
exports.execute = execute;
exports.default = architect_1.createBuilder(execute);
async function initialize(options, context, webpackConfigurationTransform) {
const originalOutputPath = options.outputPath;
const { config, i18n } = await webpack_browser_config_1.generateI18nBrowserWebpackConfigFromContext({
...options,
buildOptimizer: false,
aot: true,
platform: 'server',
}, context, wco => [
webpack_configs_1.getCommonConfig(wco),
webpack_configs_1.getServerConfig(wco),
webpack_configs_1.getStylesConfig(wco),
webpack_configs_1.getStatsConfig(wco),
webpack_configs_1.getAotConfig(wco),
]);
let transformedConfig;
if (webpackConfigurationTransform) {
transformedConfig = await webpackConfigurationTransform(config);
}
if (options.deleteOutputPath) {
utils_1.deleteOutputDir(context.workspaceRoot, originalOutputPath);
}
return { config: transformedConfig || config, i18n };
}
export interface Schema {
/**
* Which external dependencies to bundle into the bundle. By default, all of node_modules
* will be bundled.
*/
bundleDependencies?: BundleDependenciesUnion;
/**
* Use a separate bundle containing code used across multiple bundles.
* @deprecated Since version 9. This option has no effect on server platform.
*/
commonChunk?: boolean;
/**
* Delete the output path before building.
*/
deleteOutputPath?: boolean;
/**
* URL where files will be deployed.
*/
deployUrl?: string;
/**
* Output in-file eval sourcemaps.
* @deprecated
*/
evalSourceMap?: boolean;
/**
* Exclude the listed external dependencies from being bundled into the bundle. Instead, the
* created bundle relies on these dependencies to be available during runtime.
*/
externalDependencies?: string[];
/**
* Extract all licenses in a separate file, in the case of production builds only.
*/
extractLicenses?: boolean;
/**
* Replace files with other files in the build.
*/
fileReplacements?: FileReplacement[];
/**
* Run the TypeScript type checker in a forked process.
*/
forkTypeChecker?: boolean;
/**
* Localization file to use for i18n.
* @deprecated Use 'locales' object in the project metadata instead.
*/
i18nFile?: string;
/**
* Format of the localization file specified with --i18n-file.
* @deprecated No longer needed as the format will be determined automatically.
*/
i18nFormat?: string;
/**
* Locale to use for i18n.
* @deprecated Use 'localize' instead.
*/
i18nLocale?: string;
/**
* How to handle missing translations for i18n.
*/
i18nMissingTranslation?: I18NMissingTranslation;
/**
* List of additional NgModule files that will be lazy loaded. Lazy router modules will be
* discovered automatically.
* @deprecated 'SystemJsNgModuleLoader' is deprecated, and this is part of its usage. Use
* 'import()' syntax instead.
*/
lazyModules?: string[];
localize?: Localize;
/**
* The name of the main entry-point file.
*/
main: string;
/**
* Use file name for lazy loaded chunks.
* @deprecated Since version 9. This option has no effect on server platform.
*/
namedChunks?: boolean;
/**
* Enables optimization of the build output.
*/
optimization?: OptimizationUnion;
/**
* Define the output filename cache-busting hashing mode.
*/
outputHashing?: OutputHashing;
/**
* Path where output will be placed.
*/
outputPath: string;
/**
* Enable and define the file watching poll time period in milliseconds.
*/
poll?: number;
/**
* Do not use the real path when resolving modules.
*/
preserveSymlinks?: boolean;
/**
* Log progress to the console while building.
*/
progress?: boolean;
/**
* The path where style resources will be placed, relative to outputPath.
*/
resourcesOutputPath?: string;
/**
* Show circular dependency warnings on builds.
*/
showCircularDependencies?: boolean;
/**
* Output sourcemaps.
*/
sourceMap?: SourceMapUnion;
/**
* Generates a 'stats.json' file which can be analyzed using tools such as
* 'webpack-bundle-analyzer'.
*/
statsJson?: boolean;
/**
* Options to pass to style preprocessors
*/
stylePreprocessorOptions?: StylePreprocessorOptions;
/**
* The name of the TypeScript configuration file.
*/
tsConfig: string;
/**
* Use a separate bundle containing only vendor libraries.
* @deprecated Since version 9. This option has no effect on server platform.
*/
vendorChunk?: boolean;
/**
* Resolve vendor packages sourcemaps.
* @deprecated
*/
vendorSourceMap?: boolean;
/**
* Adds more details to output logging.
*/
verbose?: boolean;
/**
* Run build when files change.
*/
watch?: boolean;
}
/**
* Which external dependencies to bundle into the bundle. By default, all of node_modules
* will be bundled.
*/
export declare type BundleDependenciesUnion = boolean | BundleDependenciesEnum;
export declare enum BundleDependenciesEnum {
All = "all",
None = "none"
}
export interface FileReplacement {
replace?: string;
replaceWith?: string;
src?: string;
with?: string;
}
/**
* How to handle missing translations for i18n.
*/
export declare enum I18NMissingTranslation {
Error = "error",
Ignore = "ignore",
Warning = "warning"
}
export declare type Localize = string[] | boolean;
/**
* Enables optimization of the build output.
*/
export declare type OptimizationUnion = boolean | OptimizationClass;
export interface OptimizationClass {
/**
* Enables optimization of the scripts output.
*/
scripts?: boolean;
/**
* Enables optimization of the styles output.
*/
styles?: boolean;
}
/**
* Define the output filename cache-busting hashing mode.
*/
export declare enum OutputHashing {
All = "all",
Bundles = "bundles",
Media = "media",
None = "none"
}
/**
* Output sourcemaps.
*/
export declare type SourceMapUnion = boolean | SourceMapClass;
export interface SourceMapClass {
/**
* Output sourcemaps used for error reporting tools.
*/
hidden?: boolean;
/**
* Output sourcemaps for all scripts.
*/
scripts?: boolean;
/**
* Output sourcemaps for all styles.
*/
styles?: boolean;
/**
* Resolve vendor packages sourcemaps.
*/
vendor?: boolean;
}
/**
* Options to pass to style preprocessors
*/
export interface StylePreprocessorOptions {
/**
* Paths to include. Paths will be resolved to project root.
*/
includePaths?: string[];
}
"use strict";
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
Object.defineProperty(exports, "__esModule", { value: true });
var BundleDependenciesEnum;
(function (BundleDependenciesEnum) {
BundleDependenciesEnum["All"] = "all";
BundleDependenciesEnum["None"] = "none";
})(BundleDependenciesEnum = exports.BundleDependenciesEnum || (exports.BundleDependenciesEnum = {}));
/**
* How to handle missing translations for i18n.
*/
var I18NMissingTranslation;
(function (I18NMissingTranslation) {
I18NMissingTranslation["Error"] = "error";
I18NMissingTranslation["Ignore"] = "ignore";
I18NMissingTranslation["Warning"] = "warning";
})(I18NMissingTranslation = exports.I18NMissingTranslation || (exports.I18NMissingTranslation = {}));
/**
* Define the output filename cache-busting hashing mode.
*/
var OutputHashing;
(function (OutputHashing) {
OutputHashing["All"] = "all";
OutputHashing["Bundles"] = "bundles";
OutputHashing["Media"] = "media";
OutputHashing["None"] = "none";
})(OutputHashing = exports.OutputHashing || (exports.OutputHashing = {}));
{
"$schema": "http://json-schema.org/schema",
"id": "BuildAngularWebpackServerSchema",
"title": "Universal Target",
"type": "object",
"properties": {
"main": {
"type": "string",
"description": "The name of the main entry-point file."
},
"tsConfig": {
"type": "string",
"default": "tsconfig.app.json",
"description": "The name of the TypeScript configuration file."
},
"stylePreprocessorOptions": {
"description": "Options to pass to style preprocessors",
"type": "object",
"properties": {
"includePaths": {
"description": "Paths to include. Paths will be resolved to project root.",
"type": "array",
"items": {
"type": "string"
},
"default": []
}
},
"additionalProperties": false
},
"optimization": {
"description": "Enables optimization of the build output.",
"x-user-analytics": 16,
"oneOf": [
{
"type": "object",
"properties": {
"scripts": {
"type": "boolean",
"description": "Enables optimization of the scripts output.",
"default": true
},
"styles": {
"type": "boolean",
"description": "Enables optimization of the styles output.",
"default": true
}
},
"additionalProperties": false
},
{
"type": "boolean"
}
]
},
"fileReplacements": {
"description": "Replace files with other files in the build.",
"type": "array",
"items": {
"$ref": "#/definitions/fileReplacement"
},
"default": []
},
"outputPath": {
"type": "string",
"description": "Path where output will be placed."
},
"resourcesOutputPath": {
"type": "string",
"description": "The path where style resources will be placed, relative to outputPath.",
"default": ""
},
"sourceMap": {
"description": "Output sourcemaps.",
"default": true,
"oneOf": [
{
"type": "object",
"properties": {
"scripts": {
"type": "boolean",
"description": "Output sourcemaps for all scripts.",
"default": true
},
"styles": {
"type": "boolean",
"description": "Output sourcemaps for all styles.",
"default": true
},
"hidden": {
"type": "boolean",
"description": "Output sourcemaps used for error reporting tools.",
"default": false
},
"vendor": {
"type": "boolean",
"description": "Resolve vendor packages sourcemaps.",
"default": false
}
},
"additionalProperties": false
},
{
"type": "boolean"
}
]
},
"vendorSourceMap": {
"type": "boolean",
"description": "Resolve vendor packages sourcemaps.",
"x-deprecated": true,
"default": false
},
"evalSourceMap": {
"type": "boolean",
"description": "Output in-file eval sourcemaps.",
"default": false,
"x-deprecated": true
},
"vendorChunk": {
"type": "boolean",
"description": "Use a separate bundle containing only vendor libraries.",
"default": true,
"x-deprecated": "Since version 9. This option has no effect on server platform."
},
"commonChunk": {
"type": "boolean",
"description": "Use a separate bundle containing code used across multiple bundles.",
"default": true,
"x-deprecated": "Since version 9. This option has no effect on server platform."
},
"deployUrl": {
"type": "string",
"description": "URL where files will be deployed."
},
"verbose": {
"type": "boolean",
"description": "Adds more details to output logging.",
"default": false
},
"progress": {
"type": "boolean",
"description": "Log progress to the console while building."
},
"i18nFile": {
"type": "string",
"description": "Localization file to use for i18n.",
"x-deprecated": "Use 'locales' object in the project metadata instead."
},
"i18nFormat": {
"type": "string",
"description": "Format of the localization file specified with --i18n-file.",
"x-deprecated": "No longer needed as the format will be determined automatically."
},
"i18nLocale": {
"type": "string",
"description": "Locale to use for i18n.",
"x-deprecated": "Use 'localize' instead."
},
"i18nMissingTranslation": {
"type": "string",
"description": "How to handle missing translations for i18n.",
"enum": ["warning", "error", "ignore"],
"default": "warning"
},
"localize": {
"oneOf": [
{
"type": "boolean",
"description": "Translate all locales."
},
{
"type": "array",
"description": "List of locales ID's to translate.",
"minItems": 1,
"items": {
"type": "string",
"pattern": "^[a-zA-Z]{2,3}(-[a-zA-Z]{4})?(-([a-zA-Z]{2}|[0-9]{3}))?(-[a-zA-Z]{5,8})?(-x(-[a-zA-Z0-9]{1,8})+)?$"
}
}
]
},
"outputHashing": {
"type": "string",
"description": "Define the output filename cache-busting hashing mode.",
"default": "none",
"enum": [
"none",
"all",
"media",
"bundles"
]
},
"deleteOutputPath": {
"type": "boolean",
"description": "Delete the output path before building.",
"default": true
},
"preserveSymlinks": {
"type": "boolean",
"description": "Do not use the real path when resolving modules.",
"default": false
},
"extractLicenses": {
"type": "boolean",
"description": "Extract all licenses in a separate file, in the case of production builds only.",
"default": true
},
"showCircularDependencies": {
"type": "boolean",
"description": "Show circular dependency warnings on builds.",
"default": true
},
"namedChunks": {
"type": "boolean",
"description": "Use file name for lazy loaded chunks.",
"default": true,
"x-deprecated": "Since version 9. This option has no effect on server platform."
},
"bundleDependencies": {
"description": "Which external dependencies to bundle into the bundle. By default, all of node_modules will be bundled.",
"default": true,
"oneOf": [
{
"type": "boolean"
},
{
"type": "string",
"enum": [
"none",
"all"
]
}
]
},
"externalDependencies": {
"description": "Exclude the listed external dependencies from being bundled into the bundle. Instead, the created bundle relies on these dependencies to be available during runtime.",
"type": "array",
"items": {
"type": "string"
},
"default": []
},
"statsJson": {
"type": "boolean",
"description": "Generates a 'stats.json' file which can be analyzed using tools such as 'webpack-bundle-analyzer'.",
"default": false
},
"forkTypeChecker": {
"type": "boolean",
"description": "Run the TypeScript type checker in a forked process.",
"default": true
},
"lazyModules": {
"description": "List of additional NgModule files that will be lazy loaded. Lazy router modules will be discovered automatically.",
"type": "array",
"items": {
"type": "string"
},
"x-deprecated": "'SystemJsNgModuleLoader' is deprecated, and this is part of its usage. Use 'import()' syntax instead.",
"default": []
},
"watch": {
"type": "boolean",
"description": "Run build when files change.",
"default": false
},
"poll": {
"type": "number",
"description": "Enable and define the file watching poll time period in milliseconds."
}
},
"additionalProperties": false,
"required": [
"outputPath",
"main",
"tsConfig"
],
"definitions": {
"fileReplacement": {
"oneOf": [
{
"type": "object",
"properties": {
"src": {
"type": "string"
},
"replaceWith": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"src",
"replaceWith"
]
},
{
"type": "object",
"properties": {
"replace": {
"type": "string"
},
"with": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"replace",
"with"
]
}
]
}
}
}
/**
* @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
*/
export declare type ExecutionTransformer<T> = (input: T) => T | Promise<T>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
import { json } from '@angular-devkit/core';
import { Schema as RealTslintBuilderOptions } from './schema';
declare type TslintBuilderOptions = RealTslintBuilderOptions & json.JsonObject;
declare const _default: import("@angular-devkit/architect/src/internal").Builder<TslintBuilderOptions>;
export default _default;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 architect_1 = require("@angular-devkit/architect");
const fs_1 = require("fs");
const glob = require("glob");
const minimatch_1 = require("minimatch");
const path = require("path");
const strip_bom_1 = require("../angular-cli-files/utilities/strip-bom");
async function _loadTslint() {
let tslint;
try {
tslint = await Promise.resolve().then(() => require('tslint')); // tslint:disable-line:no-implicit-dependencies
}
catch (_a) {
throw new Error('Unable to find TSLint. Ensure TSLint is installed.');
}
const version = tslint.Linter.VERSION && tslint.Linter.VERSION.split('.');
if (!version || version.length < 2
|| (Number(version[0]) === 5 && Number(version[1]) < 5) // 5.5+
|| Number(version[0]) < 5 // 6.0+
) {
throw new Error('TSLint must be version 5.5 or higher.');
}
return tslint;
}
async function _run(options, context) {
const systemRoot = context.workspaceRoot;
process.chdir(context.currentDirectory);
const projectName = (context.target && context.target.project) || '<???>';
// Print formatter output only for non human-readable formats.
const printInfo = ['prose', 'verbose', 'stylish'].includes(options.format || '') && !options.silent;
context.reportStatus(`Linting ${JSON.stringify(projectName)}...`);
if (printInfo) {
context.logger.info(`Linting ${JSON.stringify(projectName)}...`);
}
if (!options.tsConfig && options.typeCheck) {
throw new Error('A "project" must be specified to enable type checking.');
}
const projectTslint = await _loadTslint();
const tslintConfigPath = options.tslintConfig
? path.resolve(systemRoot, options.tslintConfig)
: null;
const Linter = projectTslint.Linter;
let result = undefined;
if (options.tsConfig) {
const tsConfigs = Array.isArray(options.tsConfig) ? options.tsConfig : [options.tsConfig];
context.reportProgress(0, tsConfigs.length);
const allPrograms = tsConfigs.map(tsConfig => {
return Linter.createProgram(path.resolve(systemRoot, tsConfig));
});
let i = 0;
for (const program of allPrograms) {
const partial = await _lint(projectTslint, systemRoot, tslintConfigPath, options, program, allPrograms);
if (result === undefined) {
result = partial;
}
else {
result.failures = result.failures
.filter(curr => {
return !partial.failures.some(prev => curr.equals(prev));
})
.concat(partial.failures);
// we are not doing much with 'errorCount' and 'warningCount'
// apart from checking if they are greater than 0 thus no need to dedupe these.
result.errorCount += partial.errorCount;
result.warningCount += partial.warningCount;
result.fileNames = [...new Set([...result.fileNames, ...partial.fileNames])];
if (partial.fixes) {
result.fixes = result.fixes ? result.fixes.concat(partial.fixes) : partial.fixes;
}
}
context.reportProgress(++i, allPrograms.length);
}
}
else {
result = await _lint(projectTslint, systemRoot, tslintConfigPath, options);
}
if (result == undefined) {
throw new Error('Invalid lint configuration. Nothing to lint.');
}
if (!options.silent) {
const Formatter = projectTslint.findFormatter(options.format || '');
if (!Formatter) {
throw new Error(`Invalid lint format "${options.format}".`);
}
const formatter = new Formatter();
const output = formatter.format(result.failures, result.fixes, result.fileNames);
if (output.trim()) {
context.logger.info(output);
}
}
if (result.warningCount > 0 && printInfo) {
context.logger.warn('Lint warnings found in the listed files.');
}
if (result.errorCount > 0 && printInfo) {
context.logger.error('Lint errors found in the listed files.');
}
if (result.warningCount === 0 && result.errorCount === 0 && printInfo) {
context.logger.info('All files pass linting.');
}
return {
success: options.force || result.errorCount === 0,
};
}
exports.default = architect_1.createBuilder(_run);
async function _lint(projectTslint, systemRoot, tslintConfigPath, options, program, allPrograms) {
const Linter = projectTslint.Linter;
const Configuration = projectTslint.Configuration;
const files = getFilesToLint(systemRoot, options, Linter, program);
const lintOptions = {
fix: !!options.fix,
formatter: options.format,
};
const linter = new Linter(lintOptions, program);
let lastDirectory = undefined;
let configLoad;
const lintedFiles = [];
for (const file of files) {
if (program && allPrograms) {
// If it cannot be found in ANY program, then this is an error.
if (allPrograms.every(p => p.getSourceFile(file) === undefined)) {
throw new Error(`File ${JSON.stringify(file)} is not part of a TypeScript project '${options.tsConfig}'.`);
}
else if (program.getSourceFile(file) === undefined) {
// The file exists in some other programs. We will lint it later (or earlier) in the loop.
continue;
}
}
const contents = getFileContents(file);
// Only check for a new tslint config if the path changes.
const currentDirectory = path.dirname(file);
if (currentDirectory !== lastDirectory) {
configLoad = Configuration.findConfiguration(tslintConfigPath, file);
lastDirectory = currentDirectory;
}
if (configLoad) {
// Give some breathing space to other promises that might be waiting.
await Promise.resolve();
linter.lint(file, contents, configLoad.results);
lintedFiles.push(file);
}
}
return {
...linter.getResult(),
fileNames: lintedFiles,
};
}
function getFilesToLint(root, options, linter, program) {
const ignore = options.exclude;
const files = options.files || [];
if (files.length > 0) {
return files
.map(file => glob.sync(file, { cwd: root, ignore, nodir: true }))
.reduce((prev, curr) => prev.concat(curr), [])
.map(file => path.join(root, file));
}
if (!program) {
return [];
}
let programFiles = linter.getFileNames(program);
if (ignore && ignore.length > 0) {
// normalize to support ./ paths
const ignoreMatchers = ignore
.map(pattern => new minimatch_1.Minimatch(path.normalize(pattern), { dot: true }));
programFiles = programFiles
.filter(file => !ignoreMatchers.some(matcher => matcher.match(path.relative(root, file))));
}
return programFiles;
}
function getFileContents(file) {
// NOTE: The tslint CLI checks for and excludes MPEG transport streams; this does not.
try {
return strip_bom_1.stripBom(fs_1.readFileSync(file, 'utf-8'));
}
catch (_a) {
throw new Error(`Could not read file '${file}'.`);
}
}
/**
* TSlint target options for Build Facade.
*/
export interface Schema {
/**
* Files to exclude from linting.
*/
exclude?: string[];
/**
* Files to include in linting.
*/
files?: string[];
/**
* Fixes linting errors (may overwrite linted files).
*/
fix?: boolean;
/**
* Succeeds even if there was linting errors.
*/
force?: boolean;
/**
* Output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist).
*/
format?: string;
/**
* Show output text.
*/
silent?: boolean;
/**
* The name of the TypeScript configuration file.
*/
tsConfig?: TsConfig;
/**
* The name of the TSLint configuration file.
*/
tslintConfig?: string;
/**
* Controls the type check for linting.
*/
typeCheck?: boolean;
}
/**
* The name of the TypeScript configuration file.
*/
export declare type TsConfig = string[] | string;
"use strict";
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
Object.defineProperty(exports, "__esModule", { value: true });
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "TSlint Target",
"description": "TSlint target options for Build Facade.",
"type": "object",
"properties": {
"tslintConfig": {
"type": "string",
"description": "The name of the TSLint configuration file."
},
"tsConfig": {
"description": "The name of the TypeScript configuration file.",
"oneOf": [
{ "type": "string" },
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"fix": {
"type": "boolean",
"description": "Fixes linting errors (may overwrite linted files).",
"default": false
},
"typeCheck": {
"type": "boolean",
"description": "Controls the type check for linting.",
"default": false
},
"force": {
"type": "boolean",
"description": "Succeeds even if there was linting errors.",
"default": false
},
"silent": {
"type": "boolean",
"description": "Show output text.",
"default": false
},
"format": {
"type": "string",
"description": "Output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist).",
"default": "prose",
"anyOf": [
{
"enum": [
"checkstyle",
"codeFrame",
"filesList",
"json",
"junit",
"msbuild",
"pmd",
"prose",
"stylish",
"tap",
"verbose",
"vso"
]
},
{ "minLength": 1 }
]
},
"exclude": {
"type": "array",
"description": "Files to exclude from linting.",
"default": [],
"items": {
"type": "string"
}
},
"files": {
"type": "array",
"description": "Files to include in linting.",
"default": [],
"items": {
"type": "string"
}
}
},
"additionalProperties": false,
"required": []
}
\ No newline at end of file
/// <reference types="node" />
import * as fs from 'fs';
import { ProcessBundleOptions, ProcessBundleResult } from './process-bundle';
export interface CacheEntry {
path: string;
size: number;
integrity?: string;
}
export declare class BundleActionCache {
private readonly cachePath;
private readonly integrityAlgorithm?;
constructor(cachePath: string, integrityAlgorithm?: string | undefined);
static copyEntryContent(entry: CacheEntry | string, dest: fs.PathLike): void;
generateBaseCacheKey(content: string): string;
generateCacheKeys(action: ProcessBundleOptions): string[];
getCacheEntries(cacheKeys: (string | undefined)[]): Promise<(CacheEntry | null)[] | false>;
getCachedBundleResult(action: ProcessBundleOptions): Promise<ProcessBundleResult | null>;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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);
}
}
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 algorithm = this.integrityAlgorithm || 'sha1';
const codeHash = crypto_1.createHash(algorithm)
.update(content)
.digest('base64');
let baseCacheKey = `${packageVersion}|${content.length}|${algorithm}-${codeHash}`;
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 };
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;
import { I18nOptions } from './i18n-options';
import { InlineOptions, ProcessBundleOptions, ProcessBundleResult } from './process-bundle';
export declare class BundleActionExecutor {
private workerOptions;
private readonly sizeThreshold;
private largeWorker?;
private smallWorker?;
private cache?;
constructor(workerOptions: {
cachePath?: string;
i18n: I18nOptions;
}, integrityAlgorithm?: string, sizeThreshold?: number);
private static executeMethod;
private ensureLarge;
private ensureSmall;
private executeAction;
process(action: ProcessBundleOptions): Promise<ProcessBundleResult>;
processAll(actions: Iterable<ProcessBundleOptions>): AsyncIterable<ProcessBundleResult>;
inline(action: InlineOptions): Promise<{
file: string;
diagnostics: {
type: string;
message: string;
}[];
count: number;
}>;
inlineAll(actions: Iterable<InlineOptions>): AsyncIterable<{
file: string;
diagnostics: {
type: string;
message: string;
}[];
count: number;
}>;
private static executeAll;
stop(): Promise<void>;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 jest_worker_1 = require("jest-worker");
const os = require("os");
const path = require("path");
const v8 = require("v8");
const action_cache_1 = require("./action-cache");
const workers_1 = require("./workers");
const hasThreadSupport = (() => {
try {
require('worker_threads');
return true;
}
catch (_a) {
return false;
}
})();
// This is used to normalize serialization messaging across threads and processes
// Threads use the structured clone algorithm which handles more types
// Processes use JSON which is much more limited
const serialize = v8.serialize;
let workerFile = require.resolve('./process-bundle');
workerFile =
path.extname(workerFile) === '.ts'
? require.resolve('./process-bundle-bootstrap')
: workerFile;
class BundleActionExecutor {
constructor(workerOptions, integrityAlgorithm, sizeThreshold = 32 * 1024) {
this.workerOptions = workerOptions;
this.sizeThreshold = sizeThreshold;
if (workerOptions.cachePath) {
this.cache = new action_cache_1.BundleActionCache(workerOptions.cachePath, integrityAlgorithm);
}
}
static executeMethod(worker, method, input) {
return worker[method](input);
}
ensureLarge() {
if (this.largeWorker) {
return this.largeWorker;
}
// larger files are processed in a separate process to limit memory usage in the main process
return (this.largeWorker = new jest_worker_1.default(workerFile, {
exposedMethods: ['process', 'inlineLocales'],
setupArgs: [[...serialize(this.workerOptions)]],
numWorkers: workers_1.maxWorkers,
}));
}
ensureSmall() {
if (this.smallWorker) {
return this.smallWorker;
}
// small files are processed in a limited number of threads to improve speed
// The limited number also prevents a large increase in memory usage for an otherwise short operation
return (this.smallWorker = new jest_worker_1.default(workerFile, {
exposedMethods: ['process', 'inlineLocales'],
setupArgs: hasThreadSupport ? [this.workerOptions] : [[...serialize(this.workerOptions)]],
numWorkers: os.cpus().length < 2 ? 1 : 2,
enableWorkerThreads: hasThreadSupport,
}));
}
executeAction(method, action) {
// code.length is not an exact byte count but close enough for this
if (action.code.length > this.sizeThreshold) {
return BundleActionExecutor.executeMethod(this.ensureLarge(), method, action);
}
else {
return BundleActionExecutor.executeMethod(this.ensureSmall(), method, action);
}
}
async process(action) {
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 (_a) { }
}
return this.executeAction('process', action);
}
processAll(actions) {
return BundleActionExecutor.executeAll(actions, action => this.process(action));
}
async inline(action) {
return this.executeAction('inlineLocales', action);
}
inlineAll(actions) {
return BundleActionExecutor.executeAll(actions, action => this.inline(action));
}
static async *executeAll(actions, executor) {
const executions = new Map();
for (const action of actions) {
const execution = executor(action);
executions.set(execution, execution.then(result => {
executions.delete(execution);
return result;
}));
}
while (executions.size > 0) {
yield Promise.race(executions.values());
}
}
async stop() {
if (this.largeWorker) {
await this.largeWorker.end();
}
if (this.smallWorker) {
await this.smallWorker.end();
}
}
}
exports.BundleActionExecutor = BundleActionExecutor;
/**
* @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 ts from 'typescript';
export declare class BuildBrowserFeatures {
private projectRoot;
private scriptTarget;
private readonly _es6TargetOrLater;
readonly supportedBrowsers: string[];
constructor(projectRoot: string, scriptTarget: ts.ScriptTarget);
/**
* True, when one or more browsers requires ES5
* support and the scirpt target is ES2015 or greater.
*/
isDifferentialLoadingNeeded(): boolean;
/**
* True, when one or more browsers requires ES5 support
*/
isEs5SupportNeeded(): boolean;
/**
* True, when a browser feature is supported partially or fully.
*/
isFeatureSupported(featureId: string): boolean;
}
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const browserslist = require("browserslist");
const caniuse_lite_1 = require("caniuse-lite");
const ts = require("typescript");
class BuildBrowserFeatures {
constructor(projectRoot, scriptTarget) {
this.projectRoot = projectRoot;
this.scriptTarget = scriptTarget;
this.supportedBrowsers = browserslist(undefined, { path: this.projectRoot });
this._es6TargetOrLater = this.scriptTarget > ts.ScriptTarget.ES5;
}
/**
* True, when one or more browsers requires ES5
* support and the scirpt target is ES2015 or greater.
*/
isDifferentialLoadingNeeded() {
return this._es6TargetOrLater && this.isEs5SupportNeeded();
}
/**
* True, when one or more browsers requires ES5 support
*/
isEs5SupportNeeded() {
return !this.isFeatureSupported('es6-module');
}
/**
* True, when a browser feature is supported partially or fully.
*/
isFeatureSupported(featureId) {
// y: feature is fully available
// n: feature is unavailable
// a: feature is partially supported
// x: feature is prefixed
const criteria = [
'y',
'a',
];
const data = caniuse_lite_1.feature(caniuse_lite_1.features[featureId]);
return !this.supportedBrowsers
.some(browser => {
const [agentId, version] = browser.split(' ');
const browserData = data.stats[agentId];
const featureStatus = (browserData && browserData[version]);
// We are only interested in the first character
// Ex: when 'a #4 #5', we only need to check for 'a'
// as for such cases we should polyfill these features as needed
return !featureStatus || !criteria.includes(featureStatus.charAt(0));
});
}
}
exports.BuildBrowserFeatures = BuildBrowserFeatures;
export declare function findCachePath(name: string): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 findCacheDirectory = require("find-cache-dir");
const os_1 = require("os");
const path_1 = require("path");
const environment_options_1 = require("./environment-options");
function findCachePath(name) {
if (environment_options_1.cachingBasePath) {
return path_1.resolve(environment_options_1.cachingBasePath, name);
}
return findCacheDirectory({ name }) || os_1.tmpdir();
}
exports.findCachePath = findCachePath;
export declare function copyAssets(entries: {
glob: string;
ignore?: string[];
input: string;
output: string;
flatten?: boolean;
}[], basePaths: Iterable<string>, root: string, changed?: Set<string>): Promise<void>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 fs = require("fs");
const glob = require("glob");
const path = require("path");
const copy_file_1 = require("./copy-file");
function globAsync(pattern, options) {
return new Promise((resolve, reject) => glob(pattern, options, (e, m) => (e ? reject(e) : resolve(m))));
}
async function copyAssets(entries, basePaths, root, changed) {
const defaultIgnore = ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'];
for (const entry of entries) {
const cwd = path.resolve(root, entry.input);
const files = await globAsync(entry.glob, {
cwd,
dot: true,
nodir: true,
ignore: entry.ignore ? defaultIgnore.concat(entry.ignore) : defaultIgnore,
});
const directoryExists = new Set();
for (const file of files) {
const src = path.join(cwd, file);
if (changed && !changed.has(src)) {
continue;
}
const filePath = entry.flatten ? path.basename(file) : file;
for (const base of basePaths) {
const dest = path.join(base, entry.output, filePath);
const dir = path.dirname(dest);
if (!directoryExists.has(dir)) {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
directoryExists.add(dir);
}
copy_file_1.copyFile(src, dest);
}
}
}
}
exports.copyAssets = copyAssets;
/// <reference types="node" />
/**
* @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 fs from 'fs';
export declare function copyFile(src: fs.PathLike, dest: fs.PathLike): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 fs = require("fs");
// Workaround Node.js issue prior to 10.16 with copyFile on macOS
// https://github.com/angular/angular-cli/issues/15544 & https://github.com/nodejs/node/pull/27241
let copyFileWorkaround = false;
if (process.platform === 'darwin') {
const version = process.versions.node.split('.').map(part => Number(part));
if (version[0] < 10 || version[0] === 11 || (version[0] === 10 && version[1] < 16)) {
copyFileWorkaround = true;
}
}
function copyFile(src, dest) {
if (copyFileWorkaround) {
try {
fs.unlinkSync(dest);
}
catch (_a) { }
}
fs.copyFileSync(src, dest, fs.constants.COPYFILE_FICLONE);
}
exports.copyFile = copyFile;
/**
* @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
*/
export declare function defaultProgress(progress: boolean | undefined): boolean;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
function defaultProgress(progress) {
if (progress === undefined) {
return process.stdout.isTTY === true;
}
return progress;
}
exports.defaultProgress = defaultProgress;
/**
* Delete an output directory, but error out if it's the root of the project.
*/
export declare function deleteOutputDir(root: string, outputPath: string): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 path_1 = require("path");
const rimraf = require("rimraf");
/**
* Delete an output directory, but error out if it's the root of the project.
*/
function deleteOutputDir(root, outputPath) {
const resolvedOutputPath = path_1.resolve(root, outputPath);
if (resolvedOutputPath === root) {
throw new Error('Output path MUST not be project root directory!');
}
rimraf.sync(resolvedOutputPath);
}
exports.deleteOutputDir = deleteOutputDir;
export declare const allowMangle: boolean;
export declare const shouldBeautify: boolean;
export declare const allowMinify: boolean;
export declare const cachingDisabled: boolean;
export declare const cachingBasePath: string | null;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 path = require("path");
function isDisabled(variable) {
return variable === '0' || variable.toLowerCase() === 'false';
}
function isEnabled(variable) {
return variable === '1' || variable.toLowerCase() === 'true';
}
function isPresent(variable) {
return typeof variable === 'string' && variable !== '';
}
const debugOptimizeVariable = process.env['NG_BUILD_DEBUG_OPTIMIZE'];
const debugOptimize = (() => {
if (!isPresent(debugOptimizeVariable) || isDisabled(debugOptimizeVariable)) {
return {
mangle: true,
minify: true,
beautify: false,
};
}
const debugValue = {
mangle: false,
minify: false,
beautify: true,
};
if (isEnabled(debugOptimizeVariable)) {
return debugValue;
}
for (const part of debugOptimizeVariable.split(',')) {
switch (part.trim().toLowerCase()) {
case 'mangle':
debugValue.mangle = true;
break;
case 'minify':
debugValue.minify = true;
break;
case 'beautify':
debugValue.beautify = true;
break;
}
}
return debugValue;
})();
const mangleVariable = process.env['NG_BUILD_MANGLE'];
exports.allowMangle = isPresent(mangleVariable)
? !isDisabled(mangleVariable)
: debugOptimize.mangle;
exports.shouldBeautify = debugOptimize.beautify;
exports.allowMinify = debugOptimize.minify;
const cacheVariable = process.env['NG_BUILD_CACHE'];
exports.cachingDisabled = isPresent(cacheVariable) && isDisabled(cacheVariable);
exports.cachingBasePath = (() => {
if (exports.cachingDisabled || !isPresent(cacheVariable) || isEnabled(cacheVariable)) {
return null;
}
if (!path.isAbsolute(cacheVariable)) {
throw new Error('NG_BUILD_CACHE path value must be absolute.');
}
return cacheVariable;
})();
/**
* @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 { BuilderContext } from '@angular-devkit/architect';
import { EmittedFiles } from '@angular-devkit/build-webpack';
import { I18nOptions } from './i18n-options';
export declare function i18nInlineEmittedFiles(context: BuilderContext, emittedFiles: EmittedFiles[], i18n: I18nOptions, baseOutputPath: string, outputPaths: string[], scriptsEntryPointName: string[], emittedPath: string, es5: boolean, missingTranslation: 'error' | 'warning' | 'ignore' | undefined): Promise<boolean>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const path = require("path");
const action_executor_1 = require("./action-executor");
const copy_assets_1 = require("./copy-assets");
function emittedFilesToInlineOptions(emittedFiles, scriptsEntryPointName, emittedPath, outputPath, es5, missingTranslation) {
const options = [];
const originalFiles = [];
for (const emittedFile of emittedFiles) {
if (emittedFile.asset ||
emittedFile.extension !== '.js' ||
(emittedFile.name && scriptsEntryPointName.includes(emittedFile.name))) {
continue;
}
const originalPath = path.join(emittedPath, emittedFile.file);
const action = {
filename: emittedFile.file,
code: fs.readFileSync(originalPath, 'utf8'),
es5,
outputPath,
missingTranslation,
setLocale: emittedFile.name === 'main' || emittedFile.name === 'vendor',
};
originalFiles.push(originalPath);
try {
const originalMapPath = originalPath + '.map';
action.map = fs.readFileSync(originalMapPath, 'utf8');
originalFiles.push(originalMapPath);
}
catch (err) {
if (err.code !== 'ENOENT') {
throw err;
}
}
options.push(action);
}
return { options, originalFiles };
}
async function i18nInlineEmittedFiles(context, emittedFiles, i18n, baseOutputPath, outputPaths, scriptsEntryPointName, emittedPath, es5, missingTranslation) {
const executor = new action_executor_1.BundleActionExecutor({ i18n });
let hasErrors = false;
try {
const { options, originalFiles: processedFiles } = emittedFilesToInlineOptions(emittedFiles, scriptsEntryPointName, emittedPath, baseOutputPath, es5, missingTranslation);
for await (const result of executor.inlineAll(options)) {
for (const diagnostic of result.diagnostics) {
if (diagnostic.type === 'error') {
hasErrors = true;
context.logger.error(diagnostic.message);
}
else {
context.logger.warn(diagnostic.message);
}
}
}
// Copy any non-processed files into the output locations
await copy_assets_1.copyAssets([
{
glob: '**/*',
input: emittedPath,
output: '',
ignore: [...processedFiles].map(f => path.relative(emittedPath, f)),
},
], outputPaths, '');
}
catch (err) {
context.logger.error('Localized bundle generation failed: ' + err.message);
return false;
}
finally {
await executor.stop();
}
if (hasErrors) {
context.logger.error('Localized bundle generation failed.');
}
else {
context.logger.info('Localized bundle generation complete.');
}
return !hasErrors;
}
exports.i18nInlineEmittedFiles = i18nInlineEmittedFiles;
/**
* @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 { BuilderContext } from '@angular-devkit/architect';
import { json } from '@angular-devkit/core';
import { Schema as BrowserBuilderSchema } from '../browser/schema';
import { Schema as ServerBuilderSchema } from '../server/schema';
export interface I18nOptions {
inlineLocales: Set<string>;
sourceLocale: string;
locales: Record<string, {
file: string;
format?: string;
translation?: unknown;
dataPath?: string;
integrity?: string;
baseHref?: string;
}>;
flatOutput?: boolean;
readonly shouldInline: boolean;
veCompatLocale?: string;
}
export declare function createI18nOptions(metadata: json.JsonObject, inline?: boolean | string[]): I18nOptions;
export declare function configureI18nBuild<T extends BrowserBuilderSchema | ServerBuilderSchema>(context: BuilderContext, options: T): Promise<{
buildOptions: T;
i18n: I18nOptions;
}>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@angular-devkit/core");
const fs = require("fs");
const os = require("os");
const path = require("path");
const rimraf = require("rimraf");
const read_tsconfig_1 = require("../angular-cli-files/utilities/read-tsconfig");
const load_translations_1 = require("./load-translations");
function createI18nOptions(metadata, inline) {
if (metadata.i18n !== undefined && !core_1.json.isJsonObject(metadata.i18n)) {
throw new Error('Project i18n field is malformed. Expected an object.');
}
metadata = metadata.i18n || {};
const i18n = {
inlineLocales: new Set(),
// en-US is the default locale added to Angular applications (https://angular.io/guide/i18n#i18n-pipes)
sourceLocale: 'en-US',
locales: {},
get shouldInline() {
return this.inlineLocales.size > 0;
},
};
let rawSourceLocale;
let rawSourceLocaleBaseHref;
if (core_1.json.isJsonObject(metadata.sourceLocale)) {
rawSourceLocale = metadata.sourceLocale.code;
if (metadata.sourceLocale.baseHref !== undefined && typeof metadata.sourceLocale.baseHref !== 'string') {
throw new Error('Project i18n sourceLocale baseHref field is malformed. Expected a string.');
}
rawSourceLocaleBaseHref = metadata.sourceLocale.baseHref;
}
else {
rawSourceLocale = metadata.sourceLocale;
}
if (rawSourceLocale !== undefined) {
if (typeof rawSourceLocale !== 'string') {
throw new Error('Project i18n sourceLocale field is malformed. Expected a string.');
}
i18n.sourceLocale = rawSourceLocale;
}
i18n.locales[i18n.sourceLocale] = {
file: '',
baseHref: rawSourceLocaleBaseHref,
};
if (metadata.locales !== undefined && !core_1.json.isJsonObject(metadata.locales)) {
throw new Error('Project i18n locales field is malformed. Expected an object.');
}
else if (metadata.locales) {
for (const [locale, options] of Object.entries(metadata.locales)) {
let translationFile;
let baseHref;
if (core_1.json.isJsonObject(options)) {
if (typeof options.translation !== 'string') {
throw new Error(`Project i18n locales translation field value for '${locale}' is malformed. Expected a string.`);
}
translationFile = options.translation;
if (typeof options.baseHref === 'string') {
baseHref = options.baseHref;
}
}
else if (typeof options !== 'string') {
throw new Error(`Project i18n locales field value for '${locale}' is malformed. Expected a string or object.`);
}
else {
translationFile = options;
}
if (locale === i18n.sourceLocale) {
throw new Error(`An i18n locale ('${locale}') cannot both be a source locale and provide a translation.`);
}
i18n.locales[locale] = {
file: translationFile,
baseHref,
};
}
}
if (inline === true) {
i18n.inlineLocales.add(i18n.sourceLocale);
Object.keys(i18n.locales).forEach(locale => i18n.inlineLocales.add(locale));
}
else if (inline) {
for (const locale of inline) {
if (!i18n.locales[locale] && i18n.sourceLocale !== locale) {
throw new Error(`Requested locale '${locale}' is not defined for the project.`);
}
i18n.inlineLocales.add(locale);
}
}
return i18n;
}
exports.createI18nOptions = createI18nOptions;
async function configureI18nBuild(context, options) {
if (!context.target) {
throw new Error('The builder requires a target.');
}
const buildOptions = { ...options };
const tsConfig = read_tsconfig_1.readTsconfig(buildOptions.tsConfig, context.workspaceRoot);
const usingIvy = tsConfig.options.enableIvy !== false;
const metadata = await context.getProjectMetadata(context.target);
const i18n = createI18nOptions(metadata, buildOptions.localize);
// Until 11.0, support deprecated i18n options when not using new localize option
// i18nFormat is automatically calculated
if (buildOptions.localize === undefined && usingIvy) {
mergeDeprecatedI18nOptions(i18n, buildOptions.i18nLocale, buildOptions.i18nFile);
}
else if (buildOptions.localize !== undefined && !usingIvy) {
if (buildOptions.localize === true ||
(Array.isArray(buildOptions.localize) && buildOptions.localize.length > 1)) {
throw new Error(`Localization with multiple locales in one build is not supported with View Engine.`);
}
for (const deprecatedOption of ['i18nLocale', 'i18nFormat', 'i18nFile']) {
// tslint:disable-next-line: no-any
if (typeof buildOptions[deprecatedOption] !== 'undefined') {
context.logger.warn(`Option 'localize' and deprecated '${deprecatedOption}' found. Using 'localize'.`);
}
}
if (buildOptions.localize === false ||
(Array.isArray(buildOptions.localize) && buildOptions.localize.length === 0)) {
buildOptions.i18nFile = undefined;
buildOptions.i18nLocale = undefined;
buildOptions.i18nFormat = undefined;
}
}
// Clear deprecated options when using Ivy to prevent unintended behavior
if (usingIvy) {
buildOptions.i18nFile = undefined;
buildOptions.i18nFormat = undefined;
buildOptions.i18nLocale = undefined;
}
if (i18n.inlineLocales.size > 0) {
const projectRoot = path.join(context.workspaceRoot, metadata.root || '');
const localeDataBasePath = findLocaleDataBasePath(projectRoot);
if (!localeDataBasePath) {
throw new Error(`Unable to find locale data within '@angular/common'. Please ensure '@angular/common' is installed.`);
}
// Load locales
const loader = await load_translations_1.createTranslationLoader();
const usedFormats = new Set();
for (const [locale, desc] of Object.entries(i18n.locales)) {
if (!i18n.inlineLocales.has(locale)) {
continue;
}
let localeDataPath = findLocaleDataPath(locale, localeDataBasePath);
if (!localeDataPath) {
const [first] = locale.split('-');
if (first) {
localeDataPath = findLocaleDataPath(first.toLowerCase(), localeDataBasePath);
if (localeDataPath) {
context.logger.warn(`Locale data for '${locale}' cannot be found. Using locale data for '${first}'.`);
}
}
}
if (!localeDataPath) {
context.logger.warn(`Locale data for '${locale}' cannot be found. No locale data will be included for this locale.`);
}
else {
desc.dataPath = localeDataPath;
}
if (!desc.file) {
continue;
}
const result = loader(path.join(context.workspaceRoot, desc.file));
for (const diagnostics of result.diagnostics.messages) {
if (diagnostics.type === 'error') {
throw new Error(`Error parsing translation file '${desc.file}': ${diagnostics.message}`);
}
else {
context.logger.warn(`WARNING [${desc.file}]: ${diagnostics.message}`);
}
}
usedFormats.add(result.format);
if (usedFormats.size > 1 && tsConfig.options.enableI18nLegacyMessageIdFormat !== false) {
// This limitation is only for legacy message id support (defaults to true as of 9.0)
throw new Error('Localization currently only supports using one type of translation file format for the entire application.');
}
desc.format = result.format;
desc.translation = result.translation;
desc.integrity = result.integrity;
}
// Legacy message id's require the format of the translations
if (usedFormats.size > 0) {
buildOptions.i18nFormat = [...usedFormats][0];
}
// Provide support for using the Ivy i18n options with VE
if (!usingIvy) {
i18n.veCompatLocale = buildOptions.i18nLocale = [...i18n.inlineLocales][0];
if (buildOptions.i18nLocale !== i18n.sourceLocale) {
buildOptions.i18nFile = i18n.locales[buildOptions.i18nLocale].file;
}
// Clear inline locales to prevent any new i18n related processing
i18n.inlineLocales.clear();
// Update the output path to include the locale to mimic Ivy localize behavior
buildOptions.outputPath = path.join(buildOptions.outputPath, buildOptions.i18nLocale);
}
}
// If inlining store the output in a temporary location to facilitate post-processing
if (i18n.shouldInline) {
const tempPath = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'angular-cli-i18n-'));
buildOptions.outputPath = tempPath;
// Remove temporary directory used for i18n processing
process.on('exit', () => {
try {
rimraf.sync(tempPath);
}
catch (_a) { }
});
}
return { buildOptions, i18n };
}
exports.configureI18nBuild = configureI18nBuild;
function mergeDeprecatedI18nOptions(i18n, i18nLocale, i18nFile) {
if (i18nFile !== undefined && i18nLocale === undefined) {
throw new Error(`Option 'i18nFile' cannot be used without the 'i18nLocale' option.`);
}
if (i18nLocale !== undefined) {
i18n.inlineLocales.clear();
i18n.inlineLocales.add(i18nLocale);
if (i18nFile !== undefined) {
i18n.locales[i18nLocale] = { file: i18nFile, baseHref: '' };
}
else {
// If no file, treat the locale as the source locale
// This mimics deprecated behavior
i18n.sourceLocale = i18nLocale;
i18n.locales[i18nLocale] = { file: '', baseHref: '' };
}
i18n.flatOutput = true;
}
return i18n;
}
function findLocaleDataBasePath(projectRoot) {
try {
const commonPath = path.dirname(require.resolve('@angular/common/package.json', { paths: [projectRoot] }));
const localesPath = path.join(commonPath, 'locales/global');
if (!fs.existsSync(localesPath)) {
return null;
}
return localesPath;
}
catch (_a) {
return null;
}
}
function findLocaleDataPath(locale, basePath) {
// Remove private use subtags
const scrubbedLocale = locale.replace(/-x(-[a-zA-Z0-9]{1,8})+$/, '');
const localeDataPath = path.join(basePath, scrubbedLocale + '.js');
if (!fs.existsSync(localeDataPath)) {
if (scrubbedLocale === 'en-US') {
// fallback to known existing en-US locale data as of 9.0
return findLocaleDataPath('en-US-POSIX', basePath);
}
return null;
}
return localeDataPath;
}
/**
* @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
*/
export * from './build-browser-features';
export * from './default-progress';
export * from './delete-output-dir';
export * from './run-module-as-observable-fork';
export * from './normalize-file-replacements';
export * from './normalize-asset-patterns';
export * from './normalize-source-maps';
export * from './normalize-optimization';
export * from './normalize-builder-schema';
export * from './url';
export * from './workers';
"use strict";
/**
* @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
*/
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("./build-browser-features"));
__export(require("./default-progress"));
__export(require("./delete-output-dir"));
__export(require("./run-module-as-observable-fork"));
__export(require("./normalize-file-replacements"));
__export(require("./normalize-asset-patterns"));
__export(require("./normalize-source-maps"));
__export(require("./normalize-optimization"));
__export(require("./normalize-builder-schema"));
__export(require("./url"));
__export(require("./workers"));
export declare type TranslationLoader = (path: string) => {
translation: unknown;
format: string;
diagnostics: import('@angular/localize/src/tools/src/diagnostics').Diagnostics;
integrity: string;
};
export declare function createTranslationLoader(): Promise<TranslationLoader>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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");
async function createTranslationLoader() {
const { parsers, diagnostics } = await importParsers();
return (path) => {
const content = fs.readFileSync(path, 'utf8');
for (const [format, parser] of Object.entries(parsers)) {
if (parser.canParse(path, content)) {
const result = parser.parse(path, content);
const integrity = 'sha256-' + crypto_1.createHash('sha256').update(content).digest('base64');
return { format, translation: result.translations, diagnostics, integrity };
}
}
throw new Error('Unsupported translation file format.');
};
}
exports.createTranslationLoader = createTranslationLoader;
async function importParsers() {
try {
// tslint:disable-next-line: no-implicit-dependencies
const localizeDiag = await Promise.resolve().then(() => require('@angular/localize/src/tools/src/diagnostics'));
const diagnostics = new localizeDiag.Diagnostics();
const parsers = {
json: new (await Promise.resolve().then(() => require(
// tslint:disable-next-line:trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser'))).SimpleJsonTranslationParser(),
xlf: new (await Promise.resolve().then(() => require(
// tslint:disable-next-line:trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser'))).Xliff1TranslationParser(),
xlf2: new (await Promise.resolve().then(() => require(
// tslint:disable-next-line:trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2_translation_parser'))).Xliff2TranslationParser(),
// The name ('xmb') needs to match the AOT compiler option
xmb: new (await Promise.resolve().then(() => require(
// tslint:disable-next-line:trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/translation_files/translation_parsers/xtb_translation_parser'))).XtbTranslationParser(),
};
return { parsers, diagnostics };
}
catch (_a) {
throw new Error(`Unable to load translation file parsers. Please ensure '@angular/localize' is installed.`);
}
}
/**
* @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 { BaseException, Path, virtualFs } from '@angular-devkit/core';
import { AssetPattern, AssetPatternClass } from '../browser/schema';
export declare class MissingAssetSourceRootException extends BaseException {
constructor(path: String);
}
export declare function normalizeAssetPatterns(assetPatterns: AssetPattern[], host: virtualFs.SyncDelegateHost, root: Path, projectRoot: Path, maybeSourceRoot: Path | undefined): AssetPatternClass[];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 core_1 = require("@angular-devkit/core");
class MissingAssetSourceRootException extends core_1.BaseException {
constructor(path) {
super(`The ${path} asset path must start with the project source root.`);
}
}
exports.MissingAssetSourceRootException = MissingAssetSourceRootException;
function normalizeAssetPatterns(assetPatterns, host, root, projectRoot, maybeSourceRoot) {
// When sourceRoot is not available, we default to ${projectRoot}/src.
const sourceRoot = maybeSourceRoot || core_1.join(projectRoot, 'src');
const resolvedSourceRoot = core_1.resolve(root, sourceRoot);
if (assetPatterns.length === 0) {
return [];
}
return assetPatterns
.map(assetPattern => {
// Normalize string asset patterns to objects.
if (typeof assetPattern === 'string') {
const assetPath = core_1.normalize(assetPattern);
const resolvedAssetPath = core_1.resolve(root, assetPath);
// Check if the string asset is within sourceRoot.
if (!resolvedAssetPath.startsWith(resolvedSourceRoot)) {
throw new MissingAssetSourceRootException(assetPattern);
}
let glob, input, output;
let isDirectory = false;
try {
isDirectory = host.isDirectory(resolvedAssetPath);
}
catch (_a) {
isDirectory = true;
}
if (isDirectory) {
// Folders get a recursive star glob.
glob = '**/*';
// Input directory is their original path.
input = assetPath;
}
else {
// Files are their own glob.
glob = core_1.basename(assetPath);
// Input directory is their original dirname.
input = core_1.dirname(assetPath);
}
// Output directory for both is the relative path from source root to input.
output = core_1.relative(resolvedSourceRoot, core_1.resolve(root, input));
// Return the asset pattern in object format.
return { glob, input, output };
}
else {
// It's already an AssetPatternObject, no need to convert.
return assetPattern;
}
});
}
exports.normalizeAssetPatterns = normalizeAssetPatterns;
/**
* @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 { Path, virtualFs } from '@angular-devkit/core';
import { BuildOptions } from '../angular-cli-files/models/build-options';
import { AssetPatternClass, OptimizationClass, Schema as BrowserBuilderSchema, SourceMapClass } from '../browser/schema';
import { NormalizedFileReplacement } from './normalize-file-replacements';
/**
* A normalized browser builder schema.
*/
export declare type NormalizedBrowserBuilderSchema = BrowserBuilderSchema & BuildOptions & {
sourceMap: SourceMapClass;
assets: AssetPatternClass[];
fileReplacements: NormalizedFileReplacement[];
optimization: OptimizationClass;
};
export declare function normalizeBrowserSchema(host: virtualFs.Host<{}>, root: Path, projectRoot: Path, sourceRoot: Path | undefined, options: BrowserBuilderSchema): NormalizedBrowserBuilderSchema;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@angular-devkit/core");
const normalize_asset_patterns_1 = require("./normalize-asset-patterns");
const normalize_file_replacements_1 = require("./normalize-file-replacements");
const normalize_optimization_1 = require("./normalize-optimization");
const normalize_source_maps_1 = require("./normalize-source-maps");
function normalizeBrowserSchema(host, root, projectRoot, sourceRoot, options) {
const syncHost = new core_1.virtualFs.SyncDelegateHost(host);
const normalizedSourceMapOptions = normalize_source_maps_1.normalizeSourceMaps(options.sourceMap || false);
normalizedSourceMapOptions.vendor = normalizedSourceMapOptions.vendor || options.vendorSourceMap;
return {
...options,
assets: normalize_asset_patterns_1.normalizeAssetPatterns(options.assets || [], syncHost, root, projectRoot, sourceRoot),
fileReplacements: normalize_file_replacements_1.normalizeFileReplacements(options.fileReplacements || [], syncHost, root),
optimization: normalize_optimization_1.normalizeOptimization(options.optimization),
sourceMap: normalizedSourceMapOptions,
statsJson: options.statsJson || false,
forkTypeChecker: options.forkTypeChecker || false,
budgets: options.budgets || [],
scripts: options.scripts || [],
styles: options.styles || [],
stylePreprocessorOptions: {
includePaths: options.stylePreprocessorOptions
&& options.stylePreprocessorOptions.includePaths
|| [],
},
lazyModules: options.lazyModules || [],
// Using just `--poll` will result in a value of 0 which is very likely not the intention
// A value of 0 is falsy and will disable polling rather then enable
// 500 ms is a sensible default in this case
poll: options.poll === 0 ? 500 : options.poll,
};
}
exports.normalizeBrowserSchema = normalizeBrowserSchema;
/**
* @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 { BaseException, Path, virtualFs } from '@angular-devkit/core';
import { FileReplacement } from '../browser/schema';
export declare class MissingFileReplacementException extends BaseException {
constructor(path: String);
}
export interface NormalizedFileReplacement {
replace: Path;
with: Path;
}
export declare function normalizeFileReplacements(fileReplacements: FileReplacement[], host: virtualFs.SyncDelegateHost, root: Path): NormalizedFileReplacement[];
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@angular-devkit/core");
class MissingFileReplacementException extends core_1.BaseException {
constructor(path) {
super(`The ${path} path in file replacements does not exist.`);
}
}
exports.MissingFileReplacementException = MissingFileReplacementException;
function normalizeFileReplacements(fileReplacements, host, root) {
if (fileReplacements.length === 0) {
return [];
}
const normalizedReplacement = fileReplacements
.map(replacement => normalizeFileReplacement(replacement, root));
for (const { replace, with: replacementWith } of normalizedReplacement) {
if (!host.exists(replacementWith)) {
throw new MissingFileReplacementException(core_1.getSystemPath(replacementWith));
}
if (!host.exists(replace)) {
throw new MissingFileReplacementException(core_1.getSystemPath(replace));
}
}
return normalizedReplacement;
}
exports.normalizeFileReplacements = normalizeFileReplacements;
function normalizeFileReplacement(fileReplacement, root) {
let replacePath;
let withPath;
if (fileReplacement.src && fileReplacement.replaceWith) {
replacePath = core_1.normalize(fileReplacement.src);
withPath = core_1.normalize(fileReplacement.replaceWith);
}
else if (fileReplacement.replace && fileReplacement.with) {
replacePath = core_1.normalize(fileReplacement.replace);
withPath = core_1.normalize(fileReplacement.with);
}
else {
throw new Error(`Invalid file replacement: ${JSON.stringify(fileReplacement)}`);
}
// TODO: For 7.x should this only happen if not absolute?
if (root) {
replacePath = core_1.join(root, replacePath);
}
if (root) {
withPath = core_1.join(root, withPath);
}
return { replace: replacePath, with: withPath };
}
/**
* @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 { OptimizationClass, OptimizationUnion } from '../browser/schema';
export declare function normalizeOptimization(optimization?: OptimizationUnion): Required<OptimizationClass>;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
function normalizeOptimization(optimization = false) {
return {
scripts: typeof optimization === 'object' ? !!optimization.scripts : optimization,
styles: typeof optimization === 'object' ? !!optimization.styles : optimization,
};
}
exports.normalizeOptimization = normalizeOptimization;
/**
* @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 { SourceMapClass, SourceMapUnion } from '../browser/schema';
export declare function normalizeSourceMaps(sourceMap: SourceMapUnion): SourceMapClass;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
function normalizeSourceMaps(sourceMap) {
const scripts = typeof sourceMap === 'object' ? sourceMap.scripts : sourceMap;
const styles = typeof sourceMap === 'object' ? sourceMap.styles : sourceMap;
const hidden = typeof sourceMap === 'object' && sourceMap.hidden || false;
const vendor = typeof sourceMap === 'object' && sourceMap.vendor || false;
return {
vendor,
hidden,
scripts,
styles,
};
}
exports.normalizeSourceMaps = normalizeSourceMaps;
import { I18nOptions } from './i18n-options';
export declare function ensureOutputPaths(baseOutputPath: string, i18n: I18nOptions): Map<string, string>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 fs_1 = require("fs");
const path_1 = require("path");
function ensureOutputPaths(baseOutputPath, i18n) {
const outputPaths = i18n.shouldInline
? [...i18n.inlineLocales].map(l => [l, i18n.flatOutput ? baseOutputPath : path_1.join(baseOutputPath, l)])
: [
i18n.veCompatLocale
? [i18n.veCompatLocale, path_1.join(baseOutputPath, i18n.veCompatLocale)]
: ['', baseOutputPath],
];
for (const [, outputPath] of outputPaths) {
if (!fs_1.existsSync(outputPath)) {
fs_1.mkdirSync(outputPath, { recursive: true });
}
}
return new Map(outputPaths);
}
exports.ensureOutputPaths = ensureOutputPaths;
/**
* @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
*/
require('../../../../../lib/bootstrap-local');
module.exports = require('./process-bundle.ts');
\ No newline at end of file
import { I18nOptions } from './i18n-options';
export interface ProcessBundleOptions {
filename: string;
code: string;
map?: string;
name: string;
sourceMaps?: boolean;
hiddenSourceMaps?: boolean;
vendorSourceMaps?: boolean;
runtime?: boolean;
optimize?: boolean;
optimizeOnly?: boolean;
ignoreOriginal?: boolean;
cacheKeys?: (string | undefined)[];
integrityAlgorithm?: 'sha256' | 'sha384' | 'sha512';
runtimeData?: ProcessBundleResult[];
replacements?: [string, string][];
supportedBrowsers?: string[] | Record<string, string>;
}
export interface ProcessBundleResult {
name: string;
integrity?: string;
original?: ProcessBundleFile;
downlevel?: ProcessBundleFile;
}
export interface ProcessBundleFile {
filename: string;
size: number;
integrity?: string;
map?: {
filename: string;
size: number;
};
}
export declare const enum CacheKey {
OriginalCode = 0,
OriginalMap = 1,
DownlevelCode = 2,
DownlevelMap = 3
}
export declare function setup(data: number[] | {
cachePath: string;
i18n: I18nOptions;
}): void;
export declare function process(options: ProcessBundleOptions): Promise<ProcessBundleResult>;
export interface InlineOptions {
filename: string;
code: string;
map?: string;
es5: boolean;
outputPath: string;
missingTranslation?: 'warning' | 'error' | 'ignore';
setLocale?: boolean;
}
export declare function inlineLocales(options: InlineOptions): Promise<{
file: string;
diagnostics: {
type: "error" | "warning";
message: string;
}[];
count: number;
} | {
file: string;
diagnostics: {
type: "error" | "warning";
message: string;
}[];
}>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 core_1 = require("@babel/core");
const template_1 = require("@babel/template");
const crypto_1 = require("crypto");
const fs = require("fs");
const path = require("path");
const source_map_1 = require("source-map");
const terser_1 = require("terser");
const v8 = require("v8");
const webpack_sources_1 = require("webpack-sources");
const environment_options_1 = require("./environment-options");
const cacache = require('cacache');
const deserialize = v8.deserialize;
// If code size is larger than 500KB, consider lower fidelity but faster sourcemap merge
const FAST_SOURCEMAP_THRESHOLD = 500 * 1024;
let cachePath;
let i18n;
function setup(data) {
const options = Array.isArray(data)
? deserialize(Buffer.from(data))
: data;
cachePath = options.cachePath;
i18n = options.i18n;
}
exports.setup = setup;
async function cachePut(content, key, integrity) {
if (cachePath && key) {
await cacache.put(cachePath, key || null, content, {
metadata: { integrity },
});
}
}
async function process(options) {
if (!options.cacheKeys) {
options.cacheKeys = [];
}
const result = { name: options.name };
if (options.integrityAlgorithm) {
// Store unmodified code integrity value -- used for SRI value replacement
result.integrity = generateIntegrityValue(options.integrityAlgorithm, options.code);
}
// Runtime chunk requires specialized handling
if (options.runtime) {
return { ...result, ...(await processRuntime(options)) };
}
const basePath = path.dirname(options.filename);
const filename = path.basename(options.filename);
const downlevelFilename = filename.replace(/\-(es20\d{2}|esnext)/, '-es5');
const downlevel = !options.optimizeOnly;
const sourceCode = options.code;
const sourceMap = options.map ? JSON.parse(options.map) : undefined;
let downlevelCode;
let downlevelMap;
if (downlevel) {
const { supportedBrowsers: targets = [] } = options;
// todo: revisit this in version 10, when we update our defaults browserslist
// Without this workaround bundles will not be downlevelled because Babel doesn't know handle to 'op_mini all'
// See: https://github.com/babel/babel/issues/11155
if (Array.isArray(targets) && targets.includes('op_mini all')) {
targets.push('ie_mob 11');
}
else if ('op_mini' in targets) {
targets['ie_mob'] = '11';
}
// Downlevel the bundle
const transformResult = await core_1.transformAsync(sourceCode, {
filename,
// using false ensures that babel will NOT search and process sourcemap comments (large memory usage)
// The types do not include the false option even though it is valid
// tslint:disable-next-line: no-any
inputSourceMap: false,
babelrc: false,
configFile: false,
presets: [[
require.resolve('@babel/preset-env'),
{
// browserslist-compatible query or object of minimum environment versions to support
targets,
// modules aren't needed since the bundles use webpack's custom module loading
modules: false,
// 'transform-typeof-symbol' generates slower code
exclude: ['transform-typeof-symbol'],
},
]],
plugins: options.replacements ? [createReplacePlugin(options.replacements)] : [],
minified: environment_options_1.allowMinify && !!options.optimize,
compact: !environment_options_1.shouldBeautify && !!options.optimize,
sourceMaps: !!sourceMap,
});
if (!transformResult || !transformResult.code) {
throw new Error(`Unknown error occurred processing bundle for "${options.filename}".`);
}
downlevelCode = transformResult.code;
if (sourceMap && transformResult.map) {
// String length is used as an estimate for byte length
const fastSourceMaps = sourceCode.length > FAST_SOURCEMAP_THRESHOLD;
downlevelMap = await mergeSourceMaps(sourceCode, sourceMap, downlevelCode, transformResult.map, filename,
// When not optimizing, the sourcemaps are significantly less complex
// and can use the higher fidelity merge
!!options.optimize && fastSourceMaps);
}
}
if (downlevelCode) {
result.downlevel = await processBundle({
...options,
code: downlevelCode,
map: downlevelMap,
filename: path.join(basePath, downlevelFilename),
isOriginal: false,
});
}
if (!result.original && !options.ignoreOriginal) {
result.original = await processBundle({
...options,
isOriginal: true,
});
}
return result;
}
exports.process = process;
async function mergeSourceMaps(inputCode, inputSourceMap, resultCode, resultSourceMap, filename, fast = false) {
if (fast) {
return mergeSourceMapsFast(inputSourceMap, resultSourceMap);
}
// SourceMapSource produces high-quality sourcemaps
// The last argument is not yet in the typings
// tslint:disable-next-line: no-any
return new webpack_sources_1.SourceMapSource(resultCode, filename, resultSourceMap, inputCode, inputSourceMap, true).map();
}
async function mergeSourceMapsFast(first, second) {
const sourceRoot = first.sourceRoot;
const generator = new source_map_1.SourceMapGenerator();
// sourcemap package adds the sourceRoot to all position source paths if not removed
delete first.sourceRoot;
await source_map_1.SourceMapConsumer.with(first, null, originalConsumer => {
return source_map_1.SourceMapConsumer.with(second, null, newConsumer => {
newConsumer.eachMapping(mapping => {
if (mapping.originalLine === null) {
return;
}
const originalPosition = originalConsumer.originalPositionFor({
line: mapping.originalLine,
column: mapping.originalColumn,
});
if (originalPosition.line === null ||
originalPosition.column === null ||
originalPosition.source === null) {
return;
}
generator.addMapping({
generated: {
line: mapping.generatedLine,
column: mapping.generatedColumn,
},
name: originalPosition.name || undefined,
original: {
line: originalPosition.line,
column: originalPosition.column,
},
source: originalPosition.source,
});
});
});
});
const map = generator.toJSON();
map.file = second.file;
map.sourceRoot = sourceRoot;
// Add source content if present
if (first.sourcesContent) {
// Source content array is based on index of sources
const sourceContentMap = new Map();
for (let i = 0; i < first.sources.length; i++) {
// make paths "absolute" so they can be compared (`./a.js` and `a.js` are equivalent)
sourceContentMap.set(path.resolve('/', first.sources[i]), i);
}
map.sourcesContent = [];
for (let i = 0; i < map.sources.length; i++) {
const contentIndex = sourceContentMap.get(path.resolve('/', map.sources[i]));
if (contentIndex === undefined) {
map.sourcesContent.push('');
}
else {
map.sourcesContent.push(first.sourcesContent[contentIndex]);
}
}
}
// Put the sourceRoot back
if (sourceRoot) {
first.sourceRoot = sourceRoot;
}
return map;
}
async function processBundle(options) {
const { optimize, isOriginal, code, map, filename: filepath, hiddenSourceMaps, cacheKeys = [], integrityAlgorithm, } = options;
const rawMap = typeof map === 'string' ? JSON.parse(map) : map;
const filename = path.basename(filepath);
let result;
if (rawMap) {
rawMap.file = filename;
}
if (optimize) {
result = await terserMangle(code, {
filename,
map: rawMap,
compress: !isOriginal,
ecma: isOriginal ? 6 : 5,
});
}
else {
result = {
map: rawMap,
code,
};
}
let mapContent;
if (result.map) {
if (!hiddenSourceMaps) {
result.code += `\n//# sourceMappingURL=${filename}.map`;
}
mapContent = JSON.stringify(result.map);
await cachePut(mapContent, cacheKeys[isOriginal ? 1 /* OriginalMap */ : 3 /* DownlevelMap */]);
fs.writeFileSync(filepath + '.map', mapContent);
}
const fileResult = createFileEntry(filepath, result.code, mapContent, integrityAlgorithm);
await cachePut(result.code, cacheKeys[isOriginal ? 0 /* OriginalCode */ : 2 /* DownlevelCode */], fileResult.integrity);
fs.writeFileSync(filepath, result.code);
return fileResult;
}
async function terserMangle(code, options = {}) {
// Note: Investigate converting the AST instead of re-parsing
// estree -> terser is already supported; need babel -> estree/terser
// Mangle downlevel code
const minifyOutput = terser_1.minify(options.filename ? { [options.filename]: code } : code, {
compress: environment_options_1.allowMinify && !!options.compress,
ecma: options.ecma || 5,
mangle: environment_options_1.allowMangle,
safari10: true,
output: {
ascii_only: true,
webkit: true,
beautify: environment_options_1.shouldBeautify,
},
sourceMap: !!options.map &&
{
asObject: true,
},
});
if (minifyOutput.error) {
throw minifyOutput.error;
}
// tslint:disable-next-line: no-non-null-assertion
const outputCode = minifyOutput.code;
let outputMap;
if (options.map && minifyOutput.map) {
outputMap = await mergeSourceMaps(code, options.map, outputCode, minifyOutput.map, options.filename || '0', code.length > FAST_SOURCEMAP_THRESHOLD);
}
return { code: outputCode, map: outputMap };
}
function createFileEntry(filename, code, map, integrityAlgorithm) {
return {
filename: filename,
size: Buffer.byteLength(code),
integrity: integrityAlgorithm && generateIntegrityValue(integrityAlgorithm, code),
map: !map
? undefined
: {
filename: filename + '.map',
size: Buffer.byteLength(map),
},
};
}
function generateIntegrityValue(hashAlgorithm, code) {
return (hashAlgorithm +
'-' +
crypto_1.createHash(hashAlgorithm)
.update(code)
.digest('base64'));
}
// The webpack runtime chunk is already ES5.
// However, two variants are still needed due to lazy routing and SRI differences
// NOTE: This should eventually be a babel plugin
async function processRuntime(options) {
let originalCode = options.code;
let downlevelCode = options.code;
// Replace integrity hashes with updated values
if (options.integrityAlgorithm && options.runtimeData) {
for (const data of options.runtimeData) {
if (!data.integrity) {
continue;
}
if (data.original && data.original.integrity) {
originalCode = originalCode.replace(data.integrity, data.original.integrity);
}
if (data.downlevel && data.downlevel.integrity) {
downlevelCode = downlevelCode.replace(data.integrity, data.downlevel.integrity);
}
}
}
// Adjust lazy loaded scripts to point to the proper variant
// Extra spacing is intentional to align source line positions
downlevelCode = downlevelCode.replace(/"\-(es20\d{2}|esnext)\./, ' "-es5.');
return {
original: await processBundle({
...options,
code: originalCode,
isOriginal: true,
}),
downlevel: await processBundle({
...options,
code: downlevelCode,
filename: options.filename.replace(/\-(es20\d{2}|esnext)/, '-es5'),
isOriginal: false,
}),
};
}
function createReplacePlugin(replacements) {
return {
visitor: {
StringLiteral(path) {
for (const replacement of replacements) {
if (path.node.value === replacement[0]) {
path.node.value = replacement[1];
}
}
},
},
};
}
const USE_LOCALIZE_PLUGINS = false;
async function createI18nPlugins(locale, translation, missingTranslation, localeDataContent) {
const plugins = [];
// tslint:disable-next-line: no-implicit-dependencies
const localizeDiag = await Promise.resolve().then(() => require('@angular/localize/src/tools/src/diagnostics'));
const diagnostics = new localizeDiag.Diagnostics();
const es2015 = await Promise.resolve().then(() => require(
// tslint:disable-next-line: trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/source_files/es2015_translate_plugin'));
plugins.push(
// tslint:disable-next-line: no-any
es2015.makeEs2015TranslatePlugin(diagnostics, (translation || {}), {
missingTranslation: translation === undefined ? 'ignore' : missingTranslation,
}));
const es5 = await Promise.resolve().then(() => require(
// tslint:disable-next-line: trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/source_files/es5_translate_plugin'));
plugins.push(
// tslint:disable-next-line: no-any
es5.makeEs5TranslatePlugin(diagnostics, (translation || {}), {
missingTranslation: translation === undefined ? 'ignore' : missingTranslation,
}));
const inlineLocale = await Promise.resolve().then(() => require(
// tslint:disable-next-line: trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/source_files/locale_plugin'));
plugins.push(inlineLocale.makeLocalePlugin(locale));
if (localeDataContent) {
plugins.push({
visitor: {
Program(path) {
path.unshiftContainer('body', template_1.default.ast(localeDataContent));
},
},
});
}
return { diagnostics, plugins };
}
const localizeName = '$localize';
async function inlineLocales(options) {
var _a;
if (!i18n || i18n.inlineLocales.size === 0) {
return { file: options.filename, diagnostics: [], count: 0 };
}
if (i18n.flatOutput && i18n.inlineLocales.size > 1) {
throw new Error('Flat output is only supported when inlining one locale.');
}
const hasLocalizeName = options.code.includes(localizeName);
if (!hasLocalizeName && !options.setLocale) {
return inlineCopyOnly(options);
}
let ast;
try {
ast = core_1.parseSync(options.code, {
babelrc: false,
configFile: false,
sourceType: 'script',
filename: options.filename,
});
}
catch (error) {
if (error.message) {
// Make the error more readable.
// Same errors will contain the full content of the file as the error message
// Which makes it hard to find the actual error message.
const index = error.message.indexOf(')\n');
const msg = index !== -1 ? error.message.substr(0, index + 1) : error.message;
throw new Error(`${msg}\nAn error occurred inlining file "${options.filename}"`);
}
}
if (!ast) {
throw new Error(`Unknown error occurred inlining file "${options.filename}"`);
}
if (!USE_LOCALIZE_PLUGINS) {
return inlineLocalesDirect(ast, options);
}
const diagnostics = [];
const inputMap = options.map && JSON.parse(options.map);
for (const locale of i18n.inlineLocales) {
const isSourceLocale = locale === i18n.sourceLocale;
// tslint:disable-next-line: no-any
const translations = isSourceLocale ? {} : i18n.locales[locale].translation || {};
let localeDataContent;
if (options.setLocale) {
// If locale data is provided, load it and prepend to file
const localeDataPath = (_a = i18n.locales[locale]) === null || _a === void 0 ? void 0 : _a.dataPath;
if (localeDataPath) {
localeDataContent = await loadLocaleData(localeDataPath, true, options.es5);
}
}
const { diagnostics: localeDiagnostics, plugins } = await createI18nPlugins(locale, translations, isSourceLocale ? 'ignore' : options.missingTranslation || 'warning', localeDataContent);
const transformResult = await core_1.transformFromAstSync(ast, options.code, {
filename: options.filename,
// using false ensures that babel will NOT search and process sourcemap comments (large memory usage)
// The types do not include the false option even though it is valid
// tslint:disable-next-line: no-any
inputSourceMap: false,
babelrc: false,
configFile: false,
plugins,
compact: !environment_options_1.shouldBeautify,
sourceMaps: !!inputMap,
});
diagnostics.push(...localeDiagnostics.messages);
if (!transformResult || !transformResult.code) {
throw new Error(`Unknown error occurred processing bundle for "${options.filename}".`);
}
const outputPath = path.join(options.outputPath, i18n.flatOutput ? '' : locale, options.filename);
fs.writeFileSync(outputPath, transformResult.code);
if (inputMap && transformResult.map) {
const outputMap = await mergeSourceMaps(options.code, inputMap, transformResult.code, transformResult.map, options.filename, options.code.length > FAST_SOURCEMAP_THRESHOLD);
fs.writeFileSync(outputPath + '.map', JSON.stringify(outputMap));
}
}
return { file: options.filename, diagnostics };
}
exports.inlineLocales = inlineLocales;
async function inlineLocalesDirect(ast, options) {
if (!i18n || i18n.inlineLocales.size === 0) {
return { file: options.filename, diagnostics: [], count: 0 };
}
const { default: generate } = await Promise.resolve().then(() => require('@babel/generator'));
const utils = await Promise.resolve().then(() => require(
// tslint:disable-next-line: trailing-comma no-implicit-dependencies
'@angular/localize/src/tools/src/translate/source_files/source_file_utils'));
// tslint:disable-next-line: no-implicit-dependencies
const localizeDiag = await Promise.resolve().then(() => require('@angular/localize/src/tools/src/diagnostics'));
const diagnostics = new localizeDiag.Diagnostics();
const positions = findLocalizePositions(ast, options, utils);
if (positions.length === 0 && !options.setLocale) {
return inlineCopyOnly(options);
}
const inputMap = options.map && JSON.parse(options.map);
// Cleanup source root otherwise it will be added to each source entry
const mapSourceRoot = inputMap && inputMap.sourceRoot;
if (inputMap) {
delete inputMap.sourceRoot;
}
for (const locale of i18n.inlineLocales) {
const content = new webpack_sources_1.ReplaceSource(inputMap
? // tslint:disable-next-line: no-any
new webpack_sources_1.SourceMapSource(options.code, options.filename, inputMap)
: new webpack_sources_1.OriginalSource(options.code, options.filename));
const isSourceLocale = locale === i18n.sourceLocale;
// tslint:disable-next-line: no-any
const translations = isSourceLocale ? {} : i18n.locales[locale].translation || {};
for (const position of positions) {
const translated = utils.translate(diagnostics, translations, position.messageParts, position.expressions, isSourceLocale ? 'ignore' : options.missingTranslation || 'warning');
const expression = utils.buildLocalizeReplacement(translated[0], translated[1]);
const { code } = generate(expression);
content.replace(position.start, position.end - 1, code);
}
let outputSource = content;
if (options.setLocale) {
const setLocaleText = `var $localize=Object.assign(void 0===$localize?{}:$localize,{locale:"${locale}"});\n`;
// If locale data is provided, load it and prepend to file
let localeDataSource = null;
const localeDataPath = i18n.locales[locale] && i18n.locales[locale].dataPath;
if (localeDataPath) {
const localeDataContent = await loadLocaleData(localeDataPath, true, options.es5);
localeDataSource = new webpack_sources_1.OriginalSource(localeDataContent, path.basename(localeDataPath));
}
outputSource = localeDataSource
// The semicolon ensures that there is no syntax error between statements
? new webpack_sources_1.ConcatSource(setLocaleText, localeDataSource, ';\n', content)
: new webpack_sources_1.ConcatSource(setLocaleText, content);
}
const { source: outputCode, map: outputMap } = outputSource.sourceAndMap();
const outputPath = path.join(options.outputPath, i18n.flatOutput ? '' : locale, options.filename);
fs.writeFileSync(outputPath, outputCode);
if (inputMap && outputMap) {
outputMap.file = options.filename;
if (mapSourceRoot) {
outputMap.sourceRoot = mapSourceRoot;
}
fs.writeFileSync(outputPath + '.map', JSON.stringify(outputMap));
}
}
return { file: options.filename, diagnostics: diagnostics.messages, count: positions.length };
}
function inlineCopyOnly(options) {
if (!i18n) {
throw new Error('i18n options are missing');
}
for (const locale of i18n.inlineLocales) {
const outputPath = path.join(options.outputPath, i18n.flatOutput ? '' : locale, options.filename);
fs.writeFileSync(outputPath, options.code);
if (options.map) {
fs.writeFileSync(outputPath + '.map', options.map);
}
}
return { file: options.filename, diagnostics: [], count: 0 };
}
function findLocalizePositions(ast, options,
// tslint:disable-next-line: no-implicit-dependencies
utils) {
const positions = [];
if (options.es5) {
core_1.traverse(ast, {
CallExpression(path) {
const callee = path.get('callee');
if (callee.isIdentifier() &&
callee.node.name === localizeName &&
utils.isGlobalIdentifier(callee)) {
const messageParts = utils.unwrapMessagePartsFromLocalizeCall(path);
const expressions = utils.unwrapSubstitutionsFromLocalizeCall(path.node);
positions.push({
// tslint:disable-next-line: no-non-null-assertion
start: path.node.start,
// tslint:disable-next-line: no-non-null-assertion
end: path.node.end,
messageParts,
expressions,
});
}
},
});
}
else {
const traverseFast = core_1.types.traverseFast;
traverseFast(ast, node => {
if (node.type === 'TaggedTemplateExpression' &&
core_1.types.isIdentifier(node.tag) &&
node.tag.name === localizeName) {
const messageParts = utils.unwrapMessagePartsFromTemplateLiteral(node.quasi.quasis);
positions.push({
// tslint:disable-next-line: no-non-null-assertion
start: node.start,
// tslint:disable-next-line: no-non-null-assertion
end: node.end,
messageParts,
expressions: node.quasi.expressions,
});
}
});
}
return positions;
}
async function loadLocaleData(path, optimize, es5) {
// The path is validated during option processing before the build starts
const content = fs.readFileSync(path, 'utf8');
// Downlevel and optimize the data
const transformResult = await core_1.transformAsync(content, {
filename: path,
// The types do not include the false option even though it is valid
// tslint:disable-next-line: no-any
inputSourceMap: false,
babelrc: false,
configFile: false,
presets: [
[
require.resolve('@babel/preset-env'),
{
bugfixes: true,
// IE 9 is the oldest supported browser
targets: es5 ? { ie: '9' } : { esmodules: true },
},
],
],
minified: environment_options_1.allowMinify && optimize,
compact: !environment_options_1.shouldBeautify && optimize,
comments: !optimize,
});
if (!transformResult || !transformResult.code) {
throw new Error(`Unknown error occurred processing bundle for "${path}".`);
}
return transformResult.code;
}
/**
* @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 { BuilderOutput } from '@angular-devkit/architect';
import { Observable } from 'rxjs';
export declare function runModuleAsObservableFork(cwd: string, modulePath: string, exportName: string | undefined, args: any[]): Observable<BuilderOutput>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const path_1 = require("path");
const rxjs_1 = require("rxjs");
const treeKill = require('tree-kill');
function runModuleAsObservableFork(cwd, modulePath, exportName,
// tslint:disable-next-line:no-any
args) {
return new rxjs_1.Observable(obs => {
const workerPath = path_1.resolve(__dirname, './run-module-worker.js');
const debugArgRegex = /--inspect(?:-brk|-port)?|--debug(?:-brk|-port)/;
const execArgv = process.execArgv.filter((arg) => {
// Remove debug args.
// Workaround for https://github.com/nodejs/node/issues/9435
return !debugArgRegex.test(arg);
});
const forkOptions = {
cwd,
execArgv,
};
// TODO: support passing in a logger to use as stdio streams
// if (logger) {
// (forkOptions as any).stdio = [
// 'ignore',
// logger.info, // make it a stream
// logger.error, // make it a stream
// ];
// }
const forkedProcess = child_process_1.fork(workerPath, undefined, forkOptions);
// Cleanup.
const killForkedProcess = () => {
if (forkedProcess && forkedProcess.pid) {
treeKill(forkedProcess.pid, 'SIGTERM');
}
};
// Handle child process exit.
const handleChildProcessExit = (code) => {
killForkedProcess();
if (code && code !== 0) {
obs.error();
}
obs.next({ success: true });
obs.complete();
};
forkedProcess.once('exit', handleChildProcessExit);
forkedProcess.once('SIGINT', handleChildProcessExit);
forkedProcess.once('uncaughtException', handleChildProcessExit);
// Handle parent process exit.
const handleParentProcessExit = () => {
killForkedProcess();
};
process.once('exit', handleParentProcessExit);
process.once('SIGINT', handleParentProcessExit);
process.once('uncaughtException', handleParentProcessExit);
// Run module.
forkedProcess.send({
hash: '5d4b9a5c0a4e0f9977598437b0e85bcc',
modulePath,
exportName,
args,
});
// Teardown logic. When unsubscribing, kill the forked process.
return killForkedProcess;
});
}
exports.runModuleAsObservableFork = runModuleAsObservableFork;
/**
* @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
*/
process.on('message', (message) => {
// Only process messages with the hash in 'run-module-as-observable-fork.ts'.
if (message.hash === '5d4b9a5c0a4e0f9977598437b0e85bcc') {
const requiredModule = require(message.modulePath);
if (message.exportName) {
requiredModule[message.exportName](...message.args);
} else {
requiredModule(...message.args);
}
}
});
/**
* @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
*/
export declare function urlJoin(...parts: string[]): string;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
function urlJoin(...parts) {
const [p, ...rest] = parts;
// Remove trailing slash from first part
// Join all parts with `/`
// Dedupe double slashes from path names
return p.replace(/\/$/, '') + ('/' + rest.join('/')).replace(/\/\/+/g, '/');
}
exports.urlJoin = urlJoin;
/**
* @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 { logging } from '@angular-devkit/core';
export declare function assertCompatibleAngularVersion(projectRoot: string, logger: logging.LoggerApi): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 core_1 = require("@angular-devkit/core");
const semver_1 = require("semver");
function assertCompatibleAngularVersion(projectRoot, logger) {
let angularCliPkgJson;
let angularPkgJson;
let rxjsPkgJson;
const resolveOptions = { paths: [projectRoot] };
try {
const angularPackagePath = require.resolve('@angular/core/package.json', resolveOptions);
const rxjsPackagePath = require.resolve('rxjs/package.json', resolveOptions);
angularPkgJson = require(angularPackagePath);
rxjsPkgJson = require(rxjsPackagePath);
}
catch (_a) {
logger.error(core_1.tags.stripIndents `
You seem to not be depending on "@angular/core" and/or "rxjs". This is an error.
`);
process.exit(2);
}
if (!(angularPkgJson && angularPkgJson['version'] && rxjsPkgJson && rxjsPkgJson['version'])) {
logger.error(core_1.tags.stripIndents `
Cannot determine versions of "@angular/core" and/or "rxjs".
This likely means your local installation is broken. Please reinstall your packages.
`);
process.exit(2);
}
try {
const angularCliPkgPath = require.resolve('@angular/cli/package.json', resolveOptions);
angularCliPkgJson = require(angularCliPkgPath);
if (!(angularCliPkgJson && angularCliPkgJson['version'])) {
throw new Error();
}
}
catch (_b) {
logger.error(core_1.tags.stripIndents `
Cannot determine versions of "@angular/cli".
This likely means your local installation is broken. Please reinstall your packages.
`);
process.exit(2);
}
if (angularCliPkgJson['version'] === '0.0.0') {
// Internal testing version
return;
}
const cliMajor = new semver_1.SemVer(angularCliPkgJson['version']).major;
// e.g. CLI 8.0 supports '>=8.0.0 <9.0.0', including pre-releases (betas, rcs, snapshots)
// of both 8 and 9. Also allow version "0.0.0" for integration testing in the angular/angular
// repository with the generated development @angular/core npm package which is versioned "0.0.0".
const supportedAngularSemver = `0.0.0 || ^${cliMajor}.0.0-beta || ` + `>=${cliMajor}.0.0 <${cliMajor + 1}.0.0`;
const angularVersion = new semver_1.SemVer(angularPkgJson['version']);
const rxjsVersion = new semver_1.SemVer(rxjsPkgJson['version']);
if (!semver_1.satisfies(angularVersion, supportedAngularSemver, { includePrerelease: true })) {
logger.error(core_1.tags.stripIndents `
This version of CLI is only compatible with Angular versions ${supportedAngularSemver},
but Angular version ${angularVersion} was found instead.
Please visit the link below to find instructions on how to update Angular.
https://update.angular.io/
` + '\n');
process.exit(3);
}
else if (semver_1.gte(angularVersion, '6.0.0-rc.0') &&
!semver_1.gte(rxjsVersion, '5.6.0-forward-compat.0') &&
!semver_1.gte(rxjsVersion, '6.0.0-beta.0')) {
logger.error(core_1.tags.stripIndents `
This project uses version ${rxjsVersion} of RxJs, which is not supported by Angular v6+.
The official RxJs version that is supported is 5.6.0-forward-compat.0 and greater.
Please visit the link below to find instructions on how to update RxJs.
https://docs.google.com/document/d/12nlLt71VLKb-z3YaSGzUfx6mJbc34nsMXtByPUN35cg/edit#
` + '\n');
process.exit(3);
}
else if (semver_1.gte(angularVersion, '6.0.0-rc.0') && !semver_1.gte(rxjsVersion, '6.0.0-beta.0')) {
logger.warn(core_1.tags.stripIndents `
This project uses a temporary compatibility version of RxJs (${rxjsVersion}).
Please visit the link below to find instructions on how to update RxJs.
https://docs.google.com/document/d/12nlLt71VLKb-z3YaSGzUfx6mJbc34nsMXtByPUN35cg/edit#
` + '\n');
}
}
exports.assertCompatibleAngularVersion = assertCompatibleAngularVersion;
/// <reference types="node" />
/**
* @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 { BuilderContext } from '@angular-devkit/architect';
import { logging, virtualFs } from '@angular-devkit/core';
import * as fs from 'fs';
import * as webpack from 'webpack';
import { WebpackConfigOptions } from '../angular-cli-files/models/build-options';
import { Schema as BrowserBuilderSchema } from '../browser/schema';
import { NormalizedBrowserBuilderSchema } from '../utils';
import { I18nOptions } from './i18n-options';
export declare type BrowserWebpackConfigOptions = WebpackConfigOptions<NormalizedBrowserBuilderSchema>;
export declare function generateWebpackConfig(context: BuilderContext, workspaceRoot: string, projectRoot: string, sourceRoot: string | undefined, options: NormalizedBrowserBuilderSchema, webpackPartialGenerator: (wco: BrowserWebpackConfigOptions) => webpack.Configuration[], logger: logging.LoggerApi): Promise<webpack.Configuration>;
export declare function generateI18nBrowserWebpackConfigFromContext(options: BrowserBuilderSchema, context: BuilderContext, webpackPartialGenerator: (wco: BrowserWebpackConfigOptions) => webpack.Configuration[], host?: virtualFs.Host<fs.Stats>): Promise<{
config: webpack.Configuration;
projectRoot: string;
projectSourceRoot?: string;
i18n: I18nOptions;
}>;
export declare function generateBrowserWebpackConfigFromContext(options: BrowserBuilderSchema, context: BuilderContext, webpackPartialGenerator: (wco: BrowserWebpackConfigOptions) => webpack.Configuration[], host?: virtualFs.Host<fs.Stats>): Promise<{
config: webpack.Configuration;
projectRoot: string;
projectSourceRoot?: string;
}>;
export declare function getIndexOutputFile(options: BrowserBuilderSchema): string;
export declare function getIndexInputFile(options: BrowserBuilderSchema): string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@angular-devkit/core");
const node_1 = require("@angular-devkit/core/node");
const path = require("path");
const webpack_configs_1 = require("../angular-cli-files/models/webpack-configs");
const read_tsconfig_1 = require("../angular-cli-files/utilities/read-tsconfig");
const utils_1 = require("../utils");
const build_browser_features_1 = require("./build-browser-features");
const i18n_options_1 = require("./i18n-options");
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
const webpackMerge = require('webpack-merge');
async function generateWebpackConfig(context, workspaceRoot, projectRoot, sourceRoot, options, webpackPartialGenerator, logger) {
// Ensure Build Optimizer is only used with AOT.
if (options.buildOptimizer && !options.aot) {
throw new Error(`The 'buildOptimizer' option cannot be used without 'aot'.`);
}
// Ensure Rollup Concatenation is only used with compatible options.
if (options.experimentalRollupPass) {
if (!options.aot) {
throw new Error(`The 'experimentalRollupPass' option cannot be used without 'aot'.`);
}
if (options.vendorChunk || options.commonChunk || options.namedChunks) {
throw new Error(`The 'experimentalRollupPass' option cannot be used with the`
+ `'vendorChunk', 'commonChunk', 'namedChunks' options set to true.`);
}
}
const tsConfigPath = path.resolve(workspaceRoot, options.tsConfig);
const tsConfig = read_tsconfig_1.readTsconfig(tsConfigPath);
// tslint:disable-next-line:no-implicit-dependencies
const ts = await Promise.resolve().then(() => require('typescript'));
// At the moment, only the browser builder supports differential loading
// However this config generation is used by multiple builders such as dev-server
const scriptTarget = tsConfig.options.target || ts.ScriptTarget.ES5;
const buildBrowserFeatures = new build_browser_features_1.BuildBrowserFeatures(projectRoot, scriptTarget);
const differentialLoading = context.builder.builderName === 'browser' &&
!options.watch &&
buildBrowserFeatures.isDifferentialLoadingNeeded();
let buildOptions = { ...options };
if (differentialLoading) {
buildOptions = {
...options,
// Under downlevel differential loading we copy the assets outside of webpack.
assets: [],
esVersionInFileName: true,
es5BrowserSupport: undefined,
};
}
const supportES2015 = scriptTarget !== ts.ScriptTarget.JSON && scriptTarget > ts.ScriptTarget.ES5;
const wco = {
root: workspaceRoot,
logger: logger.createChild('webpackConfigOptions'),
projectRoot,
sourceRoot,
buildOptions,
tsConfig,
tsConfigPath,
supportES2015,
differentialLoadingMode: differentialLoading,
};
wco.buildOptions.progress = utils_1.defaultProgress(wco.buildOptions.progress);
const partials = webpackPartialGenerator(wco);
const webpackConfig = webpackMerge(partials);
if (supportES2015) {
if (!webpackConfig.resolve) {
webpackConfig.resolve = {};
}
if (!webpackConfig.resolve.alias) {
webpackConfig.resolve.alias = {};
}
webpackConfig.resolve.alias['zone.js/dist/zone'] = 'zone.js/dist/zone-evergreen';
}
if (options.profile || process.env['NG_BUILD_PROFILING']) {
const esVersionInFileName = webpack_configs_1.getEsVersionForFileName(tsConfig.options.target, wco.buildOptions.esVersionInFileName);
const smp = new SpeedMeasurePlugin({
outputFormat: 'json',
outputTarget: path.resolve(workspaceRoot, `speed-measure-plugin${esVersionInFileName}.json`),
});
return smp.wrap(webpackConfig);
}
return webpackConfig;
}
exports.generateWebpackConfig = generateWebpackConfig;
async function generateI18nBrowserWebpackConfigFromContext(options, context, webpackPartialGenerator, host = new node_1.NodeJsSyncHost()) {
const { buildOptions, i18n } = await i18n_options_1.configureI18nBuild(context, options);
const result = await generateBrowserWebpackConfigFromContext(buildOptions, context, webpackPartialGenerator, host);
const config = result.config;
if (i18n.shouldInline) {
// Remove localize "polyfill" if in AOT mode
if (buildOptions.aot) {
if (!config.resolve) {
config.resolve = {};
}
if (!config.resolve.alias) {
config.resolve.alias = {};
}
config.resolve.alias['@angular/localize/init'] = require.resolve('./empty.js');
}
// Update file hashes to include translation file content
const i18nHash = Object.values(i18n.locales).reduce((data, locale) => data + (locale.integrity || ''), '');
if (!config.plugins) {
config.plugins = [];
}
config.plugins.push({
apply(compiler) {
compiler.hooks.compilation.tap('build-angular', compilation => {
// Webpack typings do not contain template hashForChunk hook
// tslint:disable-next-line: no-any
compilation.mainTemplate.hooks.hashForChunk.tap('build-angular', (hash) => {
hash.update('$localize' + i18nHash);
});
// Webpack typings do not contain hooks property
// tslint:disable-next-line: no-any
compilation.chunkTemplate.hooks.hashForChunk.tap('build-angular', (hash) => {
hash.update('$localize' + i18nHash);
});
});
},
});
}
return { ...result, i18n };
}
exports.generateI18nBrowserWebpackConfigFromContext = generateI18nBrowserWebpackConfigFromContext;
async function generateBrowserWebpackConfigFromContext(options, context, webpackPartialGenerator, host = new node_1.NodeJsSyncHost()) {
const projectName = context.target && context.target.project;
if (!projectName) {
throw new Error('The builder requires a target.');
}
const workspaceRoot = core_1.normalize(context.workspaceRoot);
const projectMetadata = await context.getProjectMetadata(projectName);
const projectRoot = core_1.resolve(workspaceRoot, core_1.normalize(projectMetadata.root || ''));
const projectSourceRoot = projectMetadata.sourceRoot;
const sourceRoot = projectSourceRoot
? core_1.resolve(workspaceRoot, core_1.normalize(projectSourceRoot))
: undefined;
const normalizedOptions = utils_1.normalizeBrowserSchema(host, workspaceRoot, projectRoot, sourceRoot, options);
const config = await generateWebpackConfig(context, core_1.getSystemPath(workspaceRoot), core_1.getSystemPath(projectRoot), sourceRoot && core_1.getSystemPath(sourceRoot), normalizedOptions, webpackPartialGenerator, context.logger);
return {
config,
projectRoot: core_1.getSystemPath(projectRoot),
projectSourceRoot: sourceRoot && core_1.getSystemPath(sourceRoot),
};
}
exports.generateBrowserWebpackConfigFromContext = generateBrowserWebpackConfigFromContext;
function getIndexOutputFile(options) {
if (typeof options.index === 'string') {
return path.basename(options.index);
}
else {
return options.index.output || 'index.html';
}
}
exports.getIndexOutputFile = getIndexOutputFile;
function getIndexInputFile(options) {
if (typeof options.index === 'string') {
return options.index;
}
else {
return options.index.input;
}
}
exports.getIndexInputFile = getIndexInputFile;
/**
* @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
*/
/**
* Use CPU count -1 with limit to 7 for workers not to clog the system.
* Some environments, like CircleCI which use Docker report a number of CPUs by the host and not the count of available.
* This cause `Error: Call retries were exceeded` errors when trying to use them.
*
* See:
*
* https://github.com/nodejs/node/issues/28762
*
* https://github.com/webpack-contrib/terser-webpack-plugin/issues/143
*
* https://github.com/angular/angular-cli/issues/16860#issuecomment-588828079
*
*/
export declare const maxWorkers: number;
"use strict";
/**
* @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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const os_1 = require("os");
/**
* Use CPU count -1 with limit to 7 for workers not to clog the system.
* Some environments, like CircleCI which use Docker report a number of CPUs by the host and not the count of available.
* This cause `Error: Call retries were exceeded` errors when trying to use them.
*
* See:
*
* https://github.com/nodejs/node/issues/28762
*
* https://github.com/webpack-contrib/terser-webpack-plugin/issues/143
*
* https://github.com/angular/angular-cli/issues/16860#issuecomment-588828079
*
*/
exports.maxWorkers = Math.max(Math.min(os_1.cpus().length, 8) - 1, 1);
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@angular-devkit/core");
const express = require("express"); // tslint:disable-line:no-implicit-dependencies
const utils_1 = require("../utils");
// This test is excluded by default and will need to be run explicitly.
// This is because App-Shell builder uses zone.js which patched the global Promise
// Currently there is no clean way to unload zone.js which causes tests that run after
// this to be extremly flaky.
// To run this test use:
// yarn test-large --full --glob packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large_disabled.ts
describe('AppShell Builder', () => {
const target = { project: 'app', target: 'app-shell' };
let architect;
beforeEach(async () => {
await utils_1.host.initialize().toPromise();
architect = (await utils_1.createArchitect(utils_1.host.root())).architect;
});
afterEach(async () => utils_1.host.restore().toPromise());
const appShellRouteFiles = {
'src/app/app-shell/app-shell.component.html': `
<p>
app-shell works!
</p>
`,
'src/app/app-shell/app-shell.component.ts': `
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-app-shell',
templateUrl: './app-shell.component.html',
})
export class AppShellComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
`,
'src/app/app.module.ts': `
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { environment } from '../environments/environment';
import { RouterModule } from '@angular/router';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
AppRoutingModule,
RouterModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
`,
'src/app/app.server.module.ts': `
import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { Routes, RouterModule } from '@angular/router';
import { AppShellComponent } from './app-shell/app-shell.component';
const routes: Routes = [ { path: 'shell', component: AppShellComponent }];
@NgModule({
imports: [
AppModule,
ServerModule,
RouterModule.forRoot(routes),
],
bootstrap: [AppComponent],
declarations: [AppShellComponent],
})
export class AppServerModule {}
`,
'src/main.ts': `
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
});
`,
'src/app/app-routing.module.ts': `
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
`,
'src/app/app.component.html': `
<router-outlet></router-outlet>
`,
};
it('works (basic)', async () => {
utils_1.host.replaceInFile('src/app/app.module.ts', / BrowserModule/, `
BrowserModule.withServerTransition({ appId: 'some-app' })
`);
const run = await architect.scheduleTarget(target);
const output = await run.result;
await run.stop();
expect(output.success).toBe(true);
const fileName = 'dist/index.html';
const content = core_1.virtualFs.fileBufferToString(utils_1.host.scopedSync().read(core_1.normalize(fileName)));
expect(content).toMatch(/Welcome to app!/);
});
it('works with route', async () => {
utils_1.host.writeMultipleFiles(appShellRouteFiles);
const overrides = { route: 'shell' };
const run = await architect.scheduleTarget(target, overrides);
const output = await run.result;
await run.stop();
expect(output.success).toBe(true);
const fileName = 'dist/index.html';
const content = core_1.virtualFs.fileBufferToString(utils_1.host.scopedSync().read(core_1.normalize(fileName)));
expect(content).toContain('app-shell works!');
});
it('works with route and service-worker', async () => {
utils_1.host.writeMultipleFiles(appShellRouteFiles);
utils_1.host.writeMultipleFiles({
'src/ngsw-config.json': `
{
"index": "/index.html",
"assetGroups": [{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/*.css",
"/*.js"
]
}
}, {
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**"
]
}
}]
}
`,
'src/app/app.module.ts': `
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { RouterModule } from '@angular/router';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
AppRoutingModule,
ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }),
RouterModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
`,
'e2e/app.e2e-spec.ts': `
import { browser, by, element } from 'protractor';
it('should have ngsw in normal state', () => {
browser.get('/');
// Wait for service worker to load.
browser.sleep(2000);
browser.waitForAngularEnabled(false);
browser.get('/ngsw/state');
// Should have updated, and be in normal state.
expect(element(by.css('pre')).getText()).not.toContain('Last update check: never');
expect(element(by.css('pre')).getText()).toContain('Driver state: NORMAL');
});
`,
});
// This should match the browser target prod config.
utils_1.host.replaceInFile('angular.json', '"buildOptimizer": true', '"buildOptimizer": true, "serviceWorker": true');
// We're changing the workspace file so we need to recreate the Architect instance.
architect = (await utils_1.createArchitect(utils_1.host.root())).architect;
const overrides = { route: 'shell' };
const run = await architect.scheduleTarget({ ...target, configuration: 'production' }, overrides);
const output = await run.result;
await run.stop();
expect(output.success).toBe(true);
// Make sure the index is pre-rendering the route.
const fileName = 'dist/index.html';
const content = core_1.virtualFs.fileBufferToString(utils_1.host.scopedSync().read(core_1.normalize(fileName)));
expect(content).toContain('app-shell works!');
// Serve the app using a simple static server.
const app = express();
app.use('/', express.static(core_1.getSystemPath(core_1.join(utils_1.host.root(), 'dist')) + '/'));
const server = app.listen(4200);
// Load app in protractor, then check service worker status.
const protractorRun = await architect.scheduleTarget({ project: 'app-e2e', target: 'e2e' }, { devServerTarget: undefined });
const protractorOutput = await protractorRun.result;
await protractorRun.stop();
expect(protractorOutput.success).toBe(true);
// Close the express server.
server.close();
});
});
/**
* @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 { Architect, BuilderOutput, ScheduleOptions, Target } from '@angular-devkit/architect';
import { TestProjectHost, TestingArchitectHost } from '@angular-devkit/architect/testing';
import { Path, json, virtualFs, workspaces } from '@angular-devkit/core';
export declare const veEnabled: boolean;
export declare const workspaceRoot: Path;
export declare const host: TestProjectHost;
export declare const outputPath: Path;
export declare const browserTargetSpec: {
project: string;
target: string;
};
export declare const devServerTargetSpec: {
project: string;
target: string;
};
export declare const extractI18nTargetSpec: {
project: string;
target: string;
};
export declare const karmaTargetSpec: {
project: string;
target: string;
};
export declare const tslintTargetSpec: {
project: string;
target: string;
};
export declare const protractorTargetSpec: {
project: string;
target: string;
};
export declare function createArchitect(workspaceRoot: Path): Promise<{
workspace: workspaces.WorkspaceDefinition;
architectHost: TestingArchitectHost;
architect: Architect;
}>;
export interface BrowserBuildOutput {
output: BuilderOutput;
files: {
[file: string]: Promise<string>;
};
}
export declare function browserBuild(architect: Architect, host: virtualFs.Host, target: Target, overrides?: json.JsonObject, scheduleOptions?: ScheduleOptions): Promise<BrowserBuildOutput>;
export declare const lazyModuleFiles: {
[path: string]: string;
};
export declare const lazyModuleStringImport: {
[path: string]: string;
};
export declare const lazyModuleFnImport: {
[path: string]: string;
};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @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 architect_1 = require("@angular-devkit/architect");
const node_1 = require("@angular-devkit/architect/node");
const testing_1 = require("@angular-devkit/architect/testing");
const core_1 = require("@angular-devkit/core");
exports.veEnabled = process.argv.includes('--ve');
const devkitRoot = core_1.normalize(global._DevKitRoot); // tslint:disable-line:no-any
exports.workspaceRoot = core_1.join(devkitRoot, `tests/angular_devkit/build_angular/hello-world-app${exports.veEnabled ? '-ve' : ''}/`);
exports.host = new testing_1.TestProjectHost(exports.workspaceRoot);
exports.outputPath = core_1.normalize('dist');
exports.browserTargetSpec = { project: 'app', target: 'build' };
exports.devServerTargetSpec = { project: 'app', target: 'serve' };
exports.extractI18nTargetSpec = { project: 'app', target: 'extract-i18n' };
exports.karmaTargetSpec = { project: 'app', target: 'test' };
exports.tslintTargetSpec = { project: 'app', target: 'lint' };
exports.protractorTargetSpec = { project: 'app-e2e', target: 'e2e' };
async function createArchitect(workspaceRoot) {
const registry = new core_1.schema.CoreSchemaRegistry();
registry.addPostTransform(core_1.schema.transforms.addUndefinedDefaults);
const workspaceSysPath = core_1.getSystemPath(workspaceRoot);
const { workspace } = await core_1.workspaces.readWorkspace(workspaceSysPath, core_1.workspaces.createWorkspaceHost(exports.host));
const architectHost = new testing_1.TestingArchitectHost(workspaceSysPath, workspaceSysPath, new node_1.WorkspaceNodeModulesArchitectHost(workspace, workspaceSysPath));
const architect = new architect_1.Architect(architectHost, registry);
return {
workspace,
architectHost,
architect,
};
}
exports.createArchitect = createArchitect;
async function browserBuild(architect, host, target, overrides, scheduleOptions) {
const run = await architect.scheduleTarget(target, overrides, scheduleOptions);
const output = (await run.result);
expect(output.success).toBe(true);
expect(output.outputPaths[0]).not.toBeUndefined();
const outputPath = core_1.normalize(output.outputPaths[0]);
const fileNames = await host.list(outputPath).toPromise();
const files = fileNames.reduce((acc, path) => {
let cache = null;
Object.defineProperty(acc, path, {
enumerable: true,
get() {
if (cache) {
return cache;
}
if (!fileNames.includes(path)) {
return Promise.reject('No file named ' + path);
}
cache = host
.read(core_1.join(outputPath, path))
.toPromise()
.then(content => core_1.virtualFs.fileBufferToString(content));
return cache;
},
});
return acc;
}, {});
await run.stop();
return {
output,
files,
};
}
exports.browserBuild = browserBuild;
exports.lazyModuleFiles = {
'src/app/lazy/lazy-routing.module.ts': `
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class LazyRoutingModule { }
`,
'src/app/lazy/lazy.module.ts': `
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LazyRoutingModule } from './lazy-routing.module';
@NgModule({
imports: [
CommonModule,
LazyRoutingModule
],
declarations: []
})
export class LazyModule { }
`,
};
exports.lazyModuleStringImport = {
'src/app/app.module.ts': `
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { RouterModule } from '@angular/router';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
RouterModule.forRoot([
{ path: 'lazy', loadChildren: './lazy/lazy.module#LazyModule' }
])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
`,
};
exports.lazyModuleFnImport = {
'src/app/app.module.ts': exports.lazyModuleStringImport['src/app/app.module.ts'].replace(`loadChildren: './lazy/lazy.module#LazyModule'`, `loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)`),
};
Mon Aug 23 2021 10:51:00 GMT+0000 (Coordinated Universal Time)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment