From 7458e9af61f35cb639453b66e13c926365f793e5 Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Thu, 10 May 2018 19:22:19 +0100 Subject: [PATCH 1/9] feat(@angular-devkit/build-webpack): add package --- .monorepo.json | 10 ++ README.md | 1 + package-lock.json | 39 +++++ package.json | 1 + .../angular_devkit/build_webpack/README.md | 3 + .../build_webpack/builders.json | 15 ++ .../angular_devkit/build_webpack/package.json | 20 +++ .../angular_devkit/build_webpack/src/index.ts | 10 ++ .../src/webpack-dev-server/index.ts | 78 ++++++++++ .../src/webpack-dev-server/schema.d.ts | 13 ++ .../src/webpack-dev-server/schema.json | 15 ++ .../build_webpack/src/webpack/index.ts | 79 ++++++++++ .../build_webpack/src/webpack/schema.d.ts | 13 ++ .../build_webpack/src/webpack/schema.json | 14 ++ .../build_webpack/test/utils/index.ts | 13 ++ .../build_webpack/test/utils/request.ts | 54 +++++++ .../test/utils/run-target-spec.ts | 36 +++++ .../build_webpack/test/utils/test-logger.ts | 30 ++++ .../test/utils/test-project-host.ts | 140 ++++++++++++++++++ .../webpack-dev-server/works_spec_large.ts | 28 ++++ .../test/webpack/works_spec_large.ts | 29 ++++ .../hello-world-app/karma.conf.js | 40 ----- .../build_webpack/webpack-app/.gitignore | 42 ++++++ .../build_webpack/webpack-app/angular.json | 30 ++++ .../build_webpack/webpack-app/src/main.js | 1 + .../webpack-app/webpack.config.js | 10 ++ 26 files changed, 724 insertions(+), 40 deletions(-) create mode 100644 packages/angular_devkit/build_webpack/README.md create mode 100644 packages/angular_devkit/build_webpack/builders.json create mode 100644 packages/angular_devkit/build_webpack/package.json create mode 100644 packages/angular_devkit/build_webpack/src/index.ts create mode 100644 packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts create mode 100644 packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.d.ts create mode 100644 packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.json create mode 100644 packages/angular_devkit/build_webpack/src/webpack/index.ts create mode 100644 packages/angular_devkit/build_webpack/src/webpack/schema.d.ts create mode 100644 packages/angular_devkit/build_webpack/src/webpack/schema.json create mode 100644 packages/angular_devkit/build_webpack/test/utils/index.ts create mode 100644 packages/angular_devkit/build_webpack/test/utils/request.ts create mode 100644 packages/angular_devkit/build_webpack/test/utils/run-target-spec.ts create mode 100644 packages/angular_devkit/build_webpack/test/utils/test-logger.ts create mode 100644 packages/angular_devkit/build_webpack/test/utils/test-project-host.ts create mode 100644 packages/angular_devkit/build_webpack/test/webpack-dev-server/works_spec_large.ts create mode 100644 packages/angular_devkit/build_webpack/test/webpack/works_spec_large.ts delete mode 100644 tests/@angular_devkit/build_webpack/hello-world-app/karma.conf.js create mode 100644 tests/@angular_devkit/build_webpack/webpack-app/.gitignore create mode 100644 tests/@angular_devkit/build_webpack/webpack-app/angular.json create mode 100644 tests/@angular_devkit/build_webpack/webpack-app/src/main.js create mode 100644 tests/@angular_devkit/build_webpack/webpack-app/webpack.config.js diff --git a/.monorepo.json b/.monorepo.json index bbcc1437f1..6c55fcbc84 100644 --- a/.monorepo.json +++ b/.monorepo.json @@ -110,6 +110,16 @@ "hash": "5d33c1706ab096941e491d9faaed8485", "snapshotRepo": "angular/angular-devkit-build-angular-builds" }, + "@angular-devkit/build-webpack": { + "name": "Build Webpack", + "links": [ + { + "label": "README", + "url": "https://github.com/angular/devkit/blob/master/packages/angular_devkit/build_webpack/README.md" + } + ], + "version": "0.0.0" + }, "@angular-devkit/core": { "name": "Core", "links": [ diff --git a/README.md b/README.md index 4b7737e7ef..73f024369b 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ This is a monorepo which contains many packages: **Build Angular** | [`@angular-devkit/build-angular`](https://npmjs.com/package/@angular-devkit/build-angular) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fbuild-angular/latest.svg)](https://npmjs.com/package/@angular-devkit/build-angular) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/devkit/blob/master/packages/angular_devkit/build_angular/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-build-angular-builds) **Build NgPackagr** | [`@angular-devkit/build-ng-packagr`](https://npmjs.com/package/@angular-devkit/build-ng-packagr) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fbuild-ng-packagr/latest.svg)](https://npmjs.com/package/@angular-devkit/build-ng-packagr) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/devkit/blob/master/packages/angular_devkit/build_ng_packagr/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-build-ng-packagr-builds) **Build Optimizer** | [`@angular-devkit/build-optimizer`](https://npmjs.com/package/@angular-devkit/build-optimizer) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fbuild-optimizer/latest.svg)](https://npmjs.com/package/@angular-devkit/build-optimizer) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/devkit/blob/master/packages/angular_devkit/build_optimizer/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-build-optimizer-builds) +**Build Webpack** | [`@angular-devkit/build-webpack`](https://npmjs.com/package/@angular-devkit/build-webpack) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fbuild-webpack/latest.svg)](https://npmjs.com/package/@angular-devkit/build-webpack) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/devkit/blob/master/packages/angular_devkit/build_webpack/README.md) **Core** | [`@angular-devkit/core`](https://npmjs.com/package/@angular-devkit/core) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fcore/latest.svg)](https://npmjs.com/package/@angular-devkit/core) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/devkit/blob/master/packages/angular_devkit/core/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-core-builds) **Schematics** | [`@angular-devkit/schematics`](https://npmjs.com/package/@angular-devkit/schematics) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fschematics/latest.svg)](https://npmjs.com/package/@angular-devkit/schematics) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/devkit/blob/master/packages/angular_devkit/schematics/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-schematics-builds) **Schematics CLI** | [`@angular-devkit/schematics-cli`](https://npmjs.com/package/@angular-devkit/schematics-cli) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fschematics-cli/latest.svg)](https://npmjs.com/package/@angular-devkit/schematics-cli) | [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-schematics-cli-builds) diff --git a/package-lock.json b/package-lock.json index 6f40df66e3..da25cbc3f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -228,6 +228,25 @@ "@types/node": "8.10.10" } }, + "@types/http-proxy": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.16.1.tgz", + "integrity": "sha512-UYesqKxEJDjMu59BJeWG2YTRyEj2dIvyRKze5C/jftTLsivZ36CzZjvy1h2EFJsCN2bcutF5tAeJz7BteyKD+Q==", + "requires": { + "@types/events": "1.2.0", + "@types/node": "8.10.10" + } + }, + "@types/http-proxy-middleware": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", + "integrity": "sha512-EWy/2c9onzs9PHPr3oWKnPJuMi6Mk9DUBOF8NLcdCVpDKIqb+qiMtUIKvRXZYWfh4ls1NYsdyOEoaPpp/s6o9g==", + "requires": { + "@types/connect": "3.4.32", + "@types/http-proxy": "1.16.1", + "@types/node": "8.10.10" + } + }, "@types/istanbul": { "version": "0.4.30", "resolved": "https://registry.npmjs.org/@types/istanbul/-/istanbul-0.4.30.tgz", @@ -312,6 +331,14 @@ "resolved": "https://registry.npmjs.org/@types/source-map/-/source-map-0.5.2.tgz", "integrity": "sha512-++w4WmMbk3dS3UeHGzAG+xJOSz5Xqtjys/TBkqG3qp3SeWE7Wwezqe5eB7B51cxUyh4PW7bwVotpsLdBK0D8cw==" }, + "@types/spdy": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/@types/spdy/-/spdy-3.4.4.tgz", + "integrity": "sha512-N9LBlbVRRYq6HgYpPkqQc3a9HJ/iEtVZToW6xlTtJiMhmRJ7jJdV7TaZQJw/Ve/1ePUsQiCTDc4JMuzzag94GA==", + "requires": { + "@types/node": "8.10.10" + } + }, "@types/tapable": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.2.tgz", @@ -355,6 +382,18 @@ } } }, + "@types/webpack-dev-server": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@types/webpack-dev-server/-/webpack-dev-server-2.9.4.tgz", + "integrity": "sha512-dNYwmw6l1ro8Jo8Ft1BM0ZgwMDhJn9sKRNed1cq73PE9tEY2H2onWRT4EIre2Ht6WGqb3eHjX+mGoJqj1SBINw==", + "requires": { + "@types/express-serve-static-core": "4.11.1", + "@types/http-proxy-middleware": "0.17.4", + "@types/serve-static": "1.13.1", + "@types/spdy": "3.4.4", + "@types/webpack": "4.1.4" + } + }, "@types/webpack-sources": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.4.tgz", diff --git a/package.json b/package.json index b2182eec87..f17202cb4b 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "@types/semver": "^5.3.30", "@types/source-map": "0.5.2", "@types/webpack": "^4.1.3", + "@types/webpack-dev-server": "^2.9.4", "@types/webpack-sources": "^0.1.4", "ajv": "~6.4.0", "autoprefixer": "^8.4.1", diff --git a/packages/angular_devkit/build_webpack/README.md b/packages/angular_devkit/build_webpack/README.md new file mode 100644 index 0000000000..9f77bd4ab4 --- /dev/null +++ b/packages/angular_devkit/build_webpack/README.md @@ -0,0 +1,3 @@ +# Webpack Builder for Architect + +WIP \ No newline at end of file diff --git a/packages/angular_devkit/build_webpack/builders.json b/packages/angular_devkit/build_webpack/builders.json new file mode 100644 index 0000000000..fe3bbee0c9 --- /dev/null +++ b/packages/angular_devkit/build_webpack/builders.json @@ -0,0 +1,15 @@ +{ + "$schema": "../architect/src/builders-schema.json", + "builders": { + "webpack": { + "class": "./src/webpack", + "schema": "./src/webpack/schema.json", + "description": "Build a webpack app." + }, + "webpack-dev-server": { + "class": "./src/webpack-dev-server", + "schema": "./src/webpack-dev-server/schema.json", + "description": "Serve a webpack app." + } + } +} diff --git a/packages/angular_devkit/build_webpack/package.json b/packages/angular_devkit/build_webpack/package.json new file mode 100644 index 0000000000..9ff27bd494 --- /dev/null +++ b/packages/angular_devkit/build_webpack/package.json @@ -0,0 +1,20 @@ +{ + "name": "@angular-devkit/build-webpack", + "version": "0.0.0", + "description": "Webpack Builder for Architect", + "main": "src/index.js", + "typings": "src/index.d.ts", + "builders": "builders.json", + "scripts": { + "preinstall": "echo DO NOT INSTALL THIS PROJECT, ONLY THE ROOT PROJECT. && exit 1" + }, + "dependencies": { + "@angular-devkit/architect": "0.0.0", + "@angular-devkit/core": "0.0.0", + "rxjs": "^6.0.0" + }, + "peerDependencies": { + "webpack": "~4.6.0", + "webpack-dev-server": "^3.1.4" + } +} \ No newline at end of file diff --git a/packages/angular_devkit/build_webpack/src/index.ts b/packages/angular_devkit/build_webpack/src/index.ts new file mode 100644 index 0000000000..e73ba09edf --- /dev/null +++ b/packages/angular_devkit/build_webpack/src/index.ts @@ -0,0 +1,10 @@ +/** + * @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 './webpack'; +export * from './webpack-dev-server'; diff --git a/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts new file mode 100644 index 0000000000..d70c76a91a --- /dev/null +++ b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts @@ -0,0 +1,78 @@ +/** + * @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 { + BuildEvent, + Builder, + BuilderConfiguration, + BuilderContext, +} from '@angular-devkit/architect'; +import { Path, getSystemPath, normalize, resolve } from '@angular-devkit/core'; +import { Observable } from 'rxjs'; +import * as webpack from 'webpack'; +import * as WebpackDevServer from 'webpack-dev-server'; +import { WebpackDevServerBuilderSchema } from './schema'; + + +export class DevServerBuilder implements Builder { + + constructor(public context: BuilderContext) { } + + run(builderConfig: BuilderConfiguration): Observable { + const root = this.context.workspace.root; + + const configPath = resolve(root, normalize(builderConfig.options.webpackConfig)); + const config = this.loadWebpackConfig(getSystemPath(configPath)); + + return this.runWebpackDevServer(config); + } + + public loadWebpackConfig(webpackConfigPath: string): webpack.Configuration { + return require(webpackConfigPath) as webpack.Configuration; + } + + public runWebpackDevServer( + webpackConfig: webpack.Configuration, + devServerCfg?: WebpackDevServer.Configuration, + ): Observable { + return new Observable(obs => { + const devServerConfig = devServerCfg || webpackConfig.devServer || {}; + devServerConfig.host = devServerConfig.host || 'localhost'; + devServerConfig.port = devServerConfig.port || 8080; + + const statsConfig = devServerConfig.stats || webpackConfig.stats; + // Disable stats reporting by the devserver, we have our own logger. + devServerConfig.stats = false; + + const webpackCompiler = webpack(webpackConfig); + const server = new WebpackDevServer(webpackCompiler, devServerConfig); + + webpackCompiler.hooks.done.tap('build-webpack', (stats: webpack.Stats) => { + this.context.logger.info(stats.toString(statsConfig)); + + obs.next({ success: !stats.hasErrors() }); + }); + + server.listen( + devServerConfig.port, + devServerConfig.host, + (err) => { + if (err) { + obs.error(err); + } + }, + ); + + // Teardown logic. Close the server when unsubscribed from. + return () => server.close(); + }); + } +} + + +export default DevServerBuilder; diff --git a/packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.d.ts b/packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.d.ts new file mode 100644 index 0000000000..e9a8036076 --- /dev/null +++ b/packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.d.ts @@ -0,0 +1,13 @@ +/** + * @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 interface WebpackDevServerBuilderSchema { + /** + * The path to the Webpack configuration file. + */ + webpackConfig: string; +} diff --git a/packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.json b/packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.json new file mode 100644 index 0000000000..f61d0fa9b6 --- /dev/null +++ b/packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.json @@ -0,0 +1,15 @@ +{ + "title": "Webpack Dev-Server Builder", + "description": "Webpack Dev-Server Builder schema for Architect.", + "type": "object", + "properties": { + "webpackConfig": { + "type": "string", + "description": "The path to the Webpack configuration file." + } + }, + "additionalProperties": false, + "required": [ + "webpackConfig" + ] +} \ No newline at end of file diff --git a/packages/angular_devkit/build_webpack/src/webpack/index.ts b/packages/angular_devkit/build_webpack/src/webpack/index.ts new file mode 100644 index 0000000000..e12771fe6a --- /dev/null +++ b/packages/angular_devkit/build_webpack/src/webpack/index.ts @@ -0,0 +1,79 @@ +/** + * @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 { + BuildEvent, + Builder, + BuilderConfiguration, + BuilderContext, +} from '@angular-devkit/architect'; +import { Path, getSystemPath, normalize, resolve } from '@angular-devkit/core'; +import { Observable } from 'rxjs'; +import * as webpack from 'webpack'; +import { WebpackBuilderSchema } from './schema'; + +export class BrowserBuilder implements Builder { + + constructor(public context: BuilderContext) { } + + run(builderConfig: BuilderConfiguration): Observable { + const root = this.context.workspace.root; + + const configPath = resolve(root, normalize(builderConfig.options.webpackConfig)); + const config = this.loadWebpackConfig(getSystemPath(configPath)); + + return this.runWebpack(config); + } + + public loadWebpackConfig(webpackConfigPath: string): webpack.Configuration { + return require(webpackConfigPath) as webpack.Configuration; + } + + public runWebpack(config: webpack.Configuration): Observable { + return new Observable(obs => { + const webpackCompiler = webpack(config); + + const callback: webpack.compiler.CompilerCallback = (err, stats) => { + if (err) { + return obs.error(err); + } + + this.context.logger.info(stats.toString(config.stats)); + + if (config.watch) { + obs.next({ success: !stats.hasErrors() }); + + // Never complete on watch mode. + return; + } else { + obs.next({ success: !stats.hasErrors() }); + obs.complete(); + } + }; + + try { + if (config.watch) { + const watchOptions = config.watchOptions || {}; + const watching = webpackCompiler.watch(watchOptions, callback); + + // Teardown logic. Close the watcher when unsubscribed from. + return () => watching.close(() => { }); + } else { + webpackCompiler.run(callback); + } + } catch (err) { + if (err) { + this.context.logger.error( + '\nAn error occured during the build:\n' + ((err && err.stack) || err)); + } + throw err; + } + }); + } +} + +export default BrowserBuilder; diff --git a/packages/angular_devkit/build_webpack/src/webpack/schema.d.ts b/packages/angular_devkit/build_webpack/src/webpack/schema.d.ts new file mode 100644 index 0000000000..46839407ee --- /dev/null +++ b/packages/angular_devkit/build_webpack/src/webpack/schema.d.ts @@ -0,0 +1,13 @@ +/** + * @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 interface WebpackBuilderSchema { + /** + * The path to the Webpack configuration file. + */ + webpackConfig: string; +} diff --git a/packages/angular_devkit/build_webpack/src/webpack/schema.json b/packages/angular_devkit/build_webpack/src/webpack/schema.json new file mode 100644 index 0000000000..bd29228a59 --- /dev/null +++ b/packages/angular_devkit/build_webpack/src/webpack/schema.json @@ -0,0 +1,14 @@ +{ + "title": "Webpack Builder.", + "description": "Webpack Builder schema for Architect.", + "properties": { + "webpackConfig": { + "type": "string", + "description": "The path to the Webpack configuration file." + } + }, + "additionalProperties": false, + "required": [ + "webpackConfig" + ] +} \ No newline at end of file diff --git a/packages/angular_devkit/build_webpack/test/utils/index.ts b/packages/angular_devkit/build_webpack/test/utils/index.ts new file mode 100644 index 0000000000..cc36609570 --- /dev/null +++ b/packages/angular_devkit/build_webpack/test/utils/index.ts @@ -0,0 +1,13 @@ +/** + * @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 + */ + +// TODO: move these into @angular-devkit/architect/test +export * from './request'; +export * from './test-project-host'; +export * from './test-logger'; +export * from './run-target-spec'; diff --git a/packages/angular_devkit/build_webpack/test/utils/request.ts b/packages/angular_devkit/build_webpack/test/utils/request.ts new file mode 100644 index 0000000000..6e3450a63b --- /dev/null +++ b/packages/angular_devkit/build_webpack/test/utils/request.ts @@ -0,0 +1,54 @@ +/** + * @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 http from 'http'; +import * as https from 'https'; +import * as Url from 'url'; + +export function request(url: string, headers = {}): Promise { + return new Promise((resolve, reject) => { + const u = Url.parse(url); + const options: http.RequestOptions = { + hostname: u.hostname, + protocol: u.protocol, + host: u.host, + port: u.port, + path: u.path, + headers: { 'Accept': 'text/html', ...headers }, + }; + + function _callback(res: http.IncomingMessage) { + if (!res.statusCode || res.statusCode >= 400) { + // Consume the rest of the data to free memory. + res.resume(); + reject(new Error(`Requesting "${url}" returned status code ${res.statusCode}.`)); + } else { + res.setEncoding('utf8'); + let data = ''; + res.on('data', chunk => { + data += chunk; + }); + res.on('end', () => { + try { + resolve(data); + } catch (err) { + reject(err); + } + }); + } + } + + if (u.protocol == 'https:') { + options.agent = new https.Agent({ rejectUnauthorized: false }); + https.get(options, _callback); + } else if (u.protocol == 'http:') { + http.get(options, _callback); + } else { + throw new Error(`Unknown protocol: ${JSON.stringify(u.protocol)}.`); + } + }); +} diff --git a/packages/angular_devkit/build_webpack/test/utils/run-target-spec.ts b/packages/angular_devkit/build_webpack/test/utils/run-target-spec.ts new file mode 100644 index 0000000000..dde6eb9fea --- /dev/null +++ b/packages/angular_devkit/build_webpack/test/utils/run-target-spec.ts @@ -0,0 +1,36 @@ +/** + * @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, BuildEvent, TargetSpecifier } from '@angular-devkit/architect'; +import { experimental, join, logging, normalize } from '@angular-devkit/core'; +import { Observable } from 'rxjs'; +import { concatMap } from 'rxjs/operators'; +import { TestProjectHost } from '../utils/test-project-host'; + + +const workspaceFile = normalize('angular.json'); +const devkitRoot = normalize((global as any)._DevKitRoot); // tslint:disable-line:no-any + +export const workspaceRoot = join(devkitRoot, + 'tests/@angular_devkit/build_webpack/webpack-app/'); +export const host = new TestProjectHost(workspaceRoot); + +export function runTargetSpec( + host: TestProjectHost, + targetSpec: TargetSpecifier, + overrides = {}, + logger: logging.Logger = new logging.NullLogger(), +): Observable { + targetSpec = { ...targetSpec, overrides }; + const workspace = new experimental.workspace.Workspace(workspaceRoot, host); + + return workspace.loadWorkspaceFromHost(workspaceFile).pipe( + concatMap(ws => new Architect(ws).loadArchitect()), + concatMap(arch => arch.run(arch.getBuilderConfiguration(targetSpec), { logger })), + ); +} diff --git a/packages/angular_devkit/build_webpack/test/utils/test-logger.ts b/packages/angular_devkit/build_webpack/test/utils/test-logger.ts new file mode 100644 index 0000000000..cda17fad25 --- /dev/null +++ b/packages/angular_devkit/build_webpack/test/utils/test-logger.ts @@ -0,0 +1,30 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import { logging } from '@angular-devkit/core'; + + +export class TestLogger extends logging.Logger { + private _latestEntries: logging.LogEntry[] = []; + constructor(name: string, parent: logging.Logger | null = null) { + super(name, parent); + this.subscribe((entry) => this._latestEntries.push(entry)); + } + + clear() { + this._latestEntries = []; + } + + includes(message: string) { + return this._latestEntries.some((entry) => entry.message.includes(message)); + } + + test(re: RegExp) { + return this._latestEntries.some((entry) => re.test(entry.message)); + } +} diff --git a/packages/angular_devkit/build_webpack/test/utils/test-project-host.ts b/packages/angular_devkit/build_webpack/test/utils/test-project-host.ts new file mode 100644 index 0000000000..87a84704ed --- /dev/null +++ b/packages/angular_devkit/build_webpack/test/utils/test-project-host.ts @@ -0,0 +1,140 @@ +/** + * @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, + getSystemPath, + normalize, + virtualFs, +} from '@angular-devkit/core'; +import { NodeJsSyncHost } from '@angular-devkit/core/node'; +import { SpawnOptions, spawn } from 'child_process'; +import { Stats } from 'fs'; +import { EMPTY, Observable } from 'rxjs'; +import { concatMap, map } from 'rxjs/operators'; + + +interface ProcessOutput { + stdout: string; + stderr: string; +} + +export class TestProjectHost extends NodeJsSyncHost { + private _scopedSyncHost: virtualFs.SyncDelegateHost; + + constructor(protected _root: Path) { + super(); + this._scopedSyncHost = new virtualFs.SyncDelegateHost(new virtualFs.ScopedHost(this, _root)); + } + + scopedSync() { + return this._scopedSyncHost; + } + + initialize(): Observable { + return this.exists(normalize('.git')).pipe( + concatMap(exists => !exists ? this._gitInit() : EMPTY), + ); + } + + restore(): Observable { + return this._gitClean(); + } + + private _gitClean(): Observable { + return this._exec('git', ['clean', '-fd']).pipe( + concatMap(() => this._exec('git', ['checkout', '.'])), + map(() => { }), + ); + } + + private _gitInit(): Observable { + return this._exec('git', ['init']).pipe( + concatMap(() => this._exec('git', ['config', 'user.email', 'angular-core+e2e@google.com'])), + concatMap(() => this._exec('git', ['config', 'user.name', 'Angular DevKit Tests'])), + concatMap(() => this._exec('git', ['add', '--all'])), + concatMap(() => this._exec('git', ['commit', '-am', '"Initial commit"'])), + map(() => { }), + ); + } + + private _exec(cmd: string, args: string[]): Observable { + return new Observable(obs => { + args = args.filter(x => x !== undefined); + let stdout = ''; + let stderr = ''; + + const spawnOptions: SpawnOptions = { cwd: getSystemPath(this._root) }; + + if (process.platform.startsWith('win')) { + args.unshift('/c', cmd); + cmd = 'cmd.exe'; + spawnOptions['stdio'] = 'pipe'; + } + + const childProcess = spawn(cmd, args, spawnOptions); + childProcess.stdout.on('data', (data: Buffer) => stdout += data.toString('utf-8')); + childProcess.stderr.on('data', (data: Buffer) => stderr += data.toString('utf-8')); + + // Create the error here so the stack shows who called this function. + const err = new Error(`Running "${cmd} ${args.join(' ')}" returned error code `); + + childProcess.on('exit', (code) => { + if (!code) { + obs.next({ stdout, stderr }); + } else { + err.message += `${code}.\n\nSTDOUT:\n${stdout}\n\nSTDERR:\n${stderr}\n`; + obs.error(err); + } + obs.complete(); + }); + }); + } + + writeMultipleFiles(files: { [path: string]: string | ArrayBufferLike | Buffer }): void { + Object.keys(files).map(fileName => { + let content = files[fileName]; + if (typeof content == 'string') { + content = virtualFs.stringToFileBuffer(content); + } else if (content instanceof Buffer) { + content = content.buffer.slice( + content.byteOffset, + content.byteOffset + content.byteLength, + ); + } + + this.scopedSync().write( + normalize(fileName), + content, + ); + }); + } + + replaceInFile(path: string, match: RegExp | string, replacement: string) { + const content = virtualFs.fileBufferToString(this.scopedSync().read(normalize(path))); + this.scopedSync().write(normalize(path), + virtualFs.stringToFileBuffer(content.replace(match, replacement))); + } + + appendToFile(path: string, str: string) { + const content = virtualFs.fileBufferToString(this.scopedSync().read(normalize(path))); + this.scopedSync().write(normalize(path), + virtualFs.stringToFileBuffer(content.concat(str))); + } + + fileMatchExists(dir: string, regex: RegExp) { + const [fileName] = this.scopedSync().list(normalize(dir)).filter(name => name.match(regex)); + + return fileName || undefined; + } + + copyFile(from: string, to: string) { + const content = this.scopedSync().read(normalize(from)); + this.scopedSync().write(normalize(to), content); + } +} diff --git a/packages/angular_devkit/build_webpack/test/webpack-dev-server/works_spec_large.ts b/packages/angular_devkit/build_webpack/test/webpack-dev-server/works_spec_large.ts new file mode 100644 index 0000000000..41873f7948 --- /dev/null +++ b/packages/angular_devkit/build_webpack/test/webpack-dev-server/works_spec_large.ts @@ -0,0 +1,28 @@ +/** + * @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 { from } from 'rxjs'; +import { concatMap, take, tap } from 'rxjs/operators'; +import { host, request, runTargetSpec } from '../utils'; + + +describe('Dev Server Builder', () => { + const webpackTargetSpec = { project: 'app', target: 'serve' }; + + beforeEach(done => host.initialize().subscribe(undefined, done.fail, done)); + afterEach(done => host.restore().subscribe(undefined, done.fail, done)); + + it('works', (done) => { + runTargetSpec(host, webpackTargetSpec).pipe( + tap((buildEvent) => expect(buildEvent.success).toBe(true)), + concatMap(() => from(request('http://localhost:8080/bundle.js'))), + tap(response => expect(response).toContain(`console.log('hello world')`)), + take(1), + ).subscribe(undefined, done.fail, done); + }, 30000); +}); diff --git a/packages/angular_devkit/build_webpack/test/webpack/works_spec_large.ts b/packages/angular_devkit/build_webpack/test/webpack/works_spec_large.ts new file mode 100644 index 0000000000..70fd914340 --- /dev/null +++ b/packages/angular_devkit/build_webpack/test/webpack/works_spec_large.ts @@ -0,0 +1,29 @@ +/** + * @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 { join, normalize } from '@angular-devkit/core'; +import { tap } from 'rxjs/operators'; +import { host, runTargetSpec } from '../utils'; + + +describe('Webpack Builder basic test', () => { + const outputPath = normalize('dist'); + const webpackTargetSpec = { project: 'app', target: 'build' }; + + beforeEach(done => host.initialize().subscribe(undefined, done.fail, done)); + afterEach(done => host.restore().subscribe(undefined, done.fail, done)); + + it('works', (done) => { + runTargetSpec(host, webpackTargetSpec).pipe( + tap((buildEvent) => expect(buildEvent.success).toBe(true)), + tap(() => { + expect(host.scopedSync().exists(join(outputPath, 'bundle.js'))).toBe(true); + }), + ).subscribe(undefined, done.fail, done); + }, 30000); +}); diff --git a/tests/@angular_devkit/build_webpack/hello-world-app/karma.conf.js b/tests/@angular_devkit/build_webpack/hello-world-app/karma.conf.js deleted file mode 100644 index deec58129c..0000000000 --- a/tests/@angular_devkit/build_webpack/hello-world-app/karma.conf.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -const path = require('path'); - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), - require('@angular-devkit/build-angular/plugins/karma') - ], - client:{ - clearContext: false // leave Jasmine Spec Runner output visible in browser - }, - coverageIstanbulReporter: { - dir: path.join(__dirname, 'coverage'), - reports: [ 'html', 'lcovonly' ], - fixWebpackSourcePaths: true - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false - }); -}; diff --git a/tests/@angular_devkit/build_webpack/webpack-app/.gitignore b/tests/@angular_devkit/build_webpack/webpack-app/.gitignore new file mode 100644 index 0000000000..54bfd2001e --- /dev/null +++ b/tests/@angular_devkit/build_webpack/webpack-app/.gitignore @@ -0,0 +1,42 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +testem.log +/typings + +# e2e +/e2e/*.js +/e2e/*.map + +# System Files +.DS_Store +Thumbs.db diff --git a/tests/@angular_devkit/build_webpack/webpack-app/angular.json b/tests/@angular_devkit/build_webpack/webpack-app/angular.json new file mode 100644 index 0000000000..0e357bdc7d --- /dev/null +++ b/tests/@angular_devkit/build_webpack/webpack-app/angular.json @@ -0,0 +1,30 @@ +{ + "$schema": "../../../../packages/angular_devkit/core/src/workspace/workspace-schema.json", + "version": 1, + "newProjectRoot": "./projects", + "cli": {}, + "schematics": {}, + "architect": {}, + "projects": { + "app": { + "root": "src", + "sourceRoot": "src", + "projectType": "application", + "schematics": {}, + "architect": { + "build": { + "builder": "../../../../packages/angular_devkit/build_webpack:webpack", + "options": { + "webpackConfig": "webpack.config.js" + } + }, + "serve": { + "builder": "../../../../packages/angular_devkit/build_webpack:webpack-dev-server", + "options": { + "webpackConfig": "webpack.config.js" + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/@angular_devkit/build_webpack/webpack-app/src/main.js b/tests/@angular_devkit/build_webpack/webpack-app/src/main.js new file mode 100644 index 0000000000..5893f9d0d5 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/webpack-app/src/main.js @@ -0,0 +1 @@ +console.log('hello world'); \ No newline at end of file diff --git a/tests/@angular_devkit/build_webpack/webpack-app/webpack.config.js b/tests/@angular_devkit/build_webpack/webpack-app/webpack.config.js new file mode 100644 index 0000000000..f107cc39f3 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/webpack-app/webpack.config.js @@ -0,0 +1,10 @@ +const path = require('path'); + +module.exports = { + mode: 'development', + entry: path.resolve(__dirname, './src/main.js'), + output: { + path: path.resolve(__dirname, './dist'), + filename: 'bundle.js' + } +}; From d4f097c3edb3a15e8d3ebce7aeca894816afe82b Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Fri, 11 May 2018 13:58:15 +0100 Subject: [PATCH 2/9] test: move architect test utils into architect/testing --- .../test/utils => architect/testing}/index.ts | 1 - .../utils => architect/testing}/request.ts | 0 .../testing}/run-target-spec.ts | 15 +- .../testing}/test-logger.ts | 0 .../testing}/test-project-host.ts | 0 .../test/app-shell/app-shell_spec_large.ts | 5 +- .../test/browser/allow-js_spec_large.ts | 7 +- .../test/browser/aot_spec_large.ts | 5 +- .../test/browser/assets_spec_large.ts | 13 +- .../test/browser/base-href_spec_large.ts | 5 +- .../browser/build-optimizer_spec_large.ts | 5 +- .../test/browser/bundle-budgets_spec_large.ts | 9 +- .../browser/circular-dependency_spec_large.ts | 5 +- .../test/browser/deploy-url_spec_large.ts | 9 +- .../test/browser/errors_spec_large.ts | 9 +- .../test/browser/i18n_spec_large.ts | 11 +- .../test/browser/index_spec_large.ts | 3 +- .../test/browser/lazy-module_spec_large.ts | 23 +-- .../browser/license-extraction_spec_large.ts | 5 +- .../browser/no-entry-module_spec_large.ts | 5 +- .../browser/optimization-level_spec_large.ts | 7 +- .../test/browser/output-hashing_spec_large.ts | 25 ++-- .../test/browser/output-path_spec_large.ts | 8 +- .../test/browser/poll_spec_large.ts | 5 +- .../test/browser/rebuild_spec_large.ts | 15 +- .../test/browser/replacements_spec_large.ts | 13 +- .../test/browser/scripts-array_spec_large.ts | 9 +- .../test/browser/service-worker_spec_large.ts | 9 +- .../test/browser/source-map_spec_large.ts | 9 +- .../test/browser/stats-json_spec_large.ts | 5 +- .../test/browser/styles_spec_large.ts | 41 ++--- .../subresource-integrity_spec_large.ts | 5 +- .../test/browser/tsconfig-paths_spec_large.ts | 7 +- .../test/browser/vendor-chunk_spec_large.ts | 5 +- .../test/browser/works_spec_large.ts | 5 +- .../test/dev-server/proxy_spec_large.ts | 7 +- .../test/dev-server/public-host_spec_large.ts | 9 +- .../test/dev-server/serve-path_spec_large.ts | 5 +- .../test/dev-server/ssl_spec_large.ts | 7 +- .../test/dev-server/works_spec_large.ts | 5 +- .../test/extract-i18n/works_spec_large.ts | 15 +- .../test/karma/assets_spec_large.ts | 5 +- .../test/karma/code-coverage_spec_large.ts | 7 +- .../test/karma/rebuilds_spec_large.ts | 7 +- .../test/karma/replacements_spec_large.ts | 5 +- .../test/karma/works_spec_large.ts | 9 +- .../test/protractor/works_spec_large.ts | 11 +- .../test/server/base_spec_large.ts | 5 +- .../test/tslint/works_spec_large.ts | 29 ++-- .../{utils/run-target-spec.ts => utils.ts} | 28 +--- .../build_angular/test/utils/timeouts.ts | 14 -- .../src/build/index_spec_large.ts | 44 +++--- .../build_webpack/src/test-utils.ts | 15 ++ .../webpack-dev-server/index_spec_large.ts} | 5 +- .../webpack/index_spec_large.ts} | 5 +- .../build_webpack/test/utils/index.ts | 13 -- .../build_webpack/test/utils/request.ts | 54 ------- .../build_webpack/test/utils/test-logger.ts | 30 ---- .../test/utils/test-project-host.ts | 140 ------------------ .../{.angular.json => angular.json} | 0 tsconfig.json | 1 + 61 files changed, 285 insertions(+), 493 deletions(-) rename packages/angular_devkit/{build_angular/test/utils => architect/testing}/index.ts (92%) rename packages/angular_devkit/{build_angular/test/utils => architect/testing}/request.ts (100%) rename packages/angular_devkit/{build_webpack/test/utils => architect/testing}/run-target-spec.ts (61%) rename packages/angular_devkit/{build_angular/test/utils => architect/testing}/test-logger.ts (100%) rename packages/angular_devkit/{build_angular/test/utils => architect/testing}/test-project-host.ts (100%) rename packages/angular_devkit/build_angular/test/{utils/run-target-spec.ts => utils.ts} (51%) delete mode 100644 packages/angular_devkit/build_angular/test/utils/timeouts.ts create mode 100644 packages/angular_devkit/build_webpack/src/test-utils.ts rename packages/angular_devkit/build_webpack/{test/webpack-dev-server/works_spec_large.ts => src/webpack-dev-server/index_spec_large.ts} (81%) rename packages/angular_devkit/build_webpack/{test/webpack/works_spec_large.ts => src/webpack/index_spec_large.ts} (82%) delete mode 100644 packages/angular_devkit/build_webpack/test/utils/index.ts delete mode 100644 packages/angular_devkit/build_webpack/test/utils/request.ts delete mode 100644 packages/angular_devkit/build_webpack/test/utils/test-logger.ts delete mode 100644 packages/angular_devkit/build_webpack/test/utils/test-project-host.ts rename tests/@angular_devkit/build_angular/hello-world-app/{.angular.json => angular.json} (100%) diff --git a/packages/angular_devkit/build_angular/test/utils/index.ts b/packages/angular_devkit/architect/testing/index.ts similarity index 92% rename from packages/angular_devkit/build_angular/test/utils/index.ts rename to packages/angular_devkit/architect/testing/index.ts index 807bf9c281..5b60c5339f 100644 --- a/packages/angular_devkit/build_angular/test/utils/index.ts +++ b/packages/angular_devkit/architect/testing/index.ts @@ -9,5 +9,4 @@ export * from './request'; export * from './test-project-host'; export * from './test-logger'; -export * from './timeouts'; export * from './run-target-spec'; diff --git a/packages/angular_devkit/build_angular/test/utils/request.ts b/packages/angular_devkit/architect/testing/request.ts similarity index 100% rename from packages/angular_devkit/build_angular/test/utils/request.ts rename to packages/angular_devkit/architect/testing/request.ts diff --git a/packages/angular_devkit/build_webpack/test/utils/run-target-spec.ts b/packages/angular_devkit/architect/testing/run-target-spec.ts similarity index 61% rename from packages/angular_devkit/build_webpack/test/utils/run-target-spec.ts rename to packages/angular_devkit/architect/testing/run-target-spec.ts index dde6eb9fea..9ad81ff5ca 100644 --- a/packages/angular_devkit/build_webpack/test/utils/run-target-spec.ts +++ b/packages/angular_devkit/architect/testing/run-target-spec.ts @@ -6,27 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ -import { Architect, BuildEvent, TargetSpecifier } from '@angular-devkit/architect'; -import { experimental, join, logging, normalize } from '@angular-devkit/core'; +import { Path, experimental, logging, normalize } from '@angular-devkit/core'; import { Observable } from 'rxjs'; import { concatMap } from 'rxjs/operators'; -import { TestProjectHost } from '../utils/test-project-host'; +import { Architect, BuildEvent, TargetSpecifier } from '../src'; +import { TestProjectHost } from './test-project-host'; -const workspaceFile = normalize('angular.json'); -const devkitRoot = normalize((global as any)._DevKitRoot); // tslint:disable-line:no-any - -export const workspaceRoot = join(devkitRoot, - 'tests/@angular_devkit/build_webpack/webpack-app/'); -export const host = new TestProjectHost(workspaceRoot); - export function runTargetSpec( + workspaceRoot: Path, host: TestProjectHost, targetSpec: TargetSpecifier, overrides = {}, logger: logging.Logger = new logging.NullLogger(), ): Observable { targetSpec = { ...targetSpec, overrides }; + const workspaceFile = normalize('angular.json'); const workspace = new experimental.workspace.Workspace(workspaceRoot, host); return workspace.loadWorkspaceFromHost(workspaceFile).pipe( diff --git a/packages/angular_devkit/build_angular/test/utils/test-logger.ts b/packages/angular_devkit/architect/testing/test-logger.ts similarity index 100% rename from packages/angular_devkit/build_angular/test/utils/test-logger.ts rename to packages/angular_devkit/architect/testing/test-logger.ts diff --git a/packages/angular_devkit/build_angular/test/utils/test-project-host.ts b/packages/angular_devkit/architect/testing/test-project-host.ts similarity index 100% rename from packages/angular_devkit/build_angular/test/utils/test-project-host.ts rename to packages/angular_devkit/architect/testing/test-project-host.ts diff --git a/packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts b/packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts index b179c54e08..7d854690f1 100644 --- a/packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts @@ -5,9 +5,10 @@ * 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 { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, host, runTargetSpec } from '../utils'; +import { Timeout, host, workspaceRoot } from '../utils'; describe('AppShell Builder', () => { @@ -37,7 +38,7 @@ describe('AppShell Builder', () => { `, }); - runTargetSpec(host, { project: 'app', target: 'app-shell' }).pipe( + runTargetSpec(workspaceRoot, host, { project: 'app', target: 'app-shell' }).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = 'dist/index.html'; diff --git a/packages/angular_devkit/build_angular/test/browser/allow-js_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/allow-js_spec_large.ts index b7852103e2..227eb51568 100644 --- a/packages/angular_devkit/build_angular/test/browser/allow-js_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/allow-js_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder allow js', () => { @@ -23,7 +24,7 @@ describe('Browser Builder allow js', () => { // TODO: this test originally edited tsconfig to have `"allowJs": true` but works without it. // Investigate. - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -36,7 +37,7 @@ describe('Browser Builder allow js', () => { const overrides = { aot: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); diff --git a/packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts index 856f519eb9..62350c3fef 100644 --- a/packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder AOT', () => { @@ -20,7 +21,7 @@ describe('Browser Builder AOT', () => { it('works', (done) => { const overrides = { aot: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/assets_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/assets_spec_large.ts index dbcc4dbe2f..a40e405be6 100644 --- a/packages/angular_devkit/build_angular/test/browser/assets_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/assets_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { tap, toArray } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder assets', () => { @@ -44,7 +45,7 @@ describe('Browser Builder assets', () => { ], }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { // Assets we expect should be there. @@ -69,7 +70,8 @@ describe('Browser Builder assets', () => { }], }; - runTargetSpec(host, browserTargetSpec, overrides).subscribe(undefined, () => done(), done.fail); + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + .subscribe(undefined, () => done(), done.fail); // The node_modules folder must be deleted, otherwise code that tries to find the // node_modules folder will hit this one and can fail. @@ -85,7 +87,8 @@ describe('Browser Builder assets', () => { assets: ['not-source-root/file.txt'], }; - runTargetSpec(host, browserTargetSpec, overrides).subscribe(undefined, () => done(), done.fail); + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + .subscribe(undefined, () => done(), done.fail); // The node_modules folder must be deleted, otherwise code that tries to find the // node_modules folder will hit this one and can fail. @@ -97,7 +100,7 @@ describe('Browser Builder assets', () => { assets: [], }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( toArray(), tap((buildEvents) => expect(buildEvents.length).toBe(1)), ).subscribe(undefined, done.fail, done); diff --git a/packages/angular_devkit/build_angular/test/browser/base-href_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/base-href_spec_large.ts index 34f457108e..b9e1f6b0fd 100644 --- a/packages/angular_devkit/build_angular/test/browser/base-href_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/base-href_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder base href', () => { @@ -25,7 +26,7 @@ describe('Browser Builder base href', () => { const overrides = { baseHref: '/myUrl' }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'index.html'); diff --git a/packages/angular_devkit/build_angular/test/browser/build-optimizer_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/build-optimizer_spec_large.ts index 1a1d84d862..20b49eb210 100644 --- a/packages/angular_devkit/build_angular/test/browser/build-optimizer_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/build-optimizer_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder build optimizer', () => { @@ -19,7 +20,7 @@ describe('Browser Builder build optimizer', () => { it('works', (done) => { const overrides = { aot: true, buildOptimizer: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/bundle-budgets_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/bundle-budgets_spec_large.ts index 88ba690752..70a92e700d 100644 --- a/packages/angular_devkit/build_angular/test/browser/bundle-budgets_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/bundle-budgets_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { TestLogger, Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder bundle budgets', () => { @@ -23,7 +24,7 @@ describe('Browser Builder bundle budgets', () => { const logger = new TestLogger('rebuild-type-errors'); - runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(logger.includes('WARNING')).toBe(false)), ).subscribe(undefined, done.fail, done); @@ -35,7 +36,7 @@ describe('Browser Builder bundle budgets', () => { budgets: [{ type: 'all', maximumError: '100b' }], }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), ).subscribe(undefined, done.fail, done); }, Timeout.Complex); @@ -48,7 +49,7 @@ describe('Browser Builder bundle budgets', () => { const logger = new TestLogger('rebuild-type-errors'); - runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(logger.includes('WARNING')).toBe(true)), ).subscribe(undefined, done.fail, done); diff --git a/packages/angular_devkit/build_angular/test/browser/circular-dependency_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/circular-dependency_spec_large.ts index f5b85c90ff..8ed7b0be6a 100644 --- a/packages/angular_devkit/build_angular/test/browser/circular-dependency_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/circular-dependency_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { TestLogger, Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder circular dependency detection', () => { @@ -21,7 +22,7 @@ describe('Browser Builder circular dependency detection', () => { const overrides = { baseHref: '/myUrl' }; const logger = new TestLogger('circular-dependencies'); - runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(logger.includes('Circular dependency detected')).toBe(true)), ).subscribe(undefined, done.fail, done); diff --git a/packages/angular_devkit/build_angular/test/browser/deploy-url_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/deploy-url_spec_large.ts index 060a0cfbac..7dc8499aa8 100644 --- a/packages/angular_devkit/build_angular/test/browser/deploy-url_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/deploy-url_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { concatMap, tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder deploy url', () => { @@ -20,14 +21,14 @@ describe('Browser Builder deploy url', () => { it('uses deploy url for bundles urls', (done) => { const overrides = { deployUrl: 'deployUrl/' }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'index.html'); const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName))); expect(content).toContain('deployUrl/main.js'); }), - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { deployUrl: 'http://example.com/some/path/' })), tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { @@ -41,7 +42,7 @@ describe('Browser Builder deploy url', () => { it('uses deploy url for in webpack runtime', (done) => { const overrides = { deployUrl: 'deployUrl/' }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'runtime.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/errors_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/errors_spec_large.ts index 6a7941e29d..4c77c417de 100644 --- a/packages/angular_devkit/build_angular/test/browser/errors_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/errors_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { TestLogger, Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder errors', () => { @@ -21,7 +22,7 @@ describe('Browser Builder errors', () => { `); const logger = new TestLogger('errors-compilation'); - runTargetSpec(host, browserTargetSpec, undefined, logger).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, undefined, logger).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); expect(logger.includes('polyfills.ts is missing from the TypeScript')).toBe(true); @@ -33,7 +34,7 @@ describe('Browser Builder errors', () => { host.appendToFile('src/app/app.component.ts', ']]]'); const logger = new TestLogger('errors-syntax'); - runTargetSpec(host, browserTargetSpec, undefined, logger).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, undefined, logger).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); expect(logger.includes('Declaration or statement expected.')).toBe(true); @@ -45,7 +46,7 @@ describe('Browser Builder errors', () => { host.replaceInFile('src/app/app.component.ts', `'app-root'`, `(() => 'app-root')()`); const logger = new TestLogger('errors-static'); - runTargetSpec(host, browserTargetSpec, { aot: true }, logger).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, { aot: true }, logger).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); expect(logger.includes('Function expressions are not supported in')).toBe(true); diff --git a/packages/angular_devkit/build_angular/test/browser/i18n_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/i18n_spec_large.ts index db1a61efe1..25b62134de 100644 --- a/packages/angular_devkit/build_angular/test/browser/i18n_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/i18n_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder i18n', () => { @@ -53,7 +54,7 @@ describe('Browser Builder i18n', () => { i18nLocale: 'fr', }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -75,7 +76,7 @@ describe('Browser Builder i18n', () => { host.writeMultipleFiles({ 'src/locale/messages.fr.xlf': emptyTranslationFile }); host.appendToFile('src/app/app.component.html', '

Other content

'); - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -97,7 +98,7 @@ describe('Browser Builder i18n', () => { host.writeMultipleFiles({ 'src/locale/messages.fr.xlf': emptyTranslationFile }); host.appendToFile('src/app/app.component.html', '

Other content

'); - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -105,7 +106,7 @@ describe('Browser Builder i18n', () => { it('register locales', (done) => { const overrides = { aot: true, i18nLocale: 'fr_FR' }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/index_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/index_spec_large.ts index 78377fb533..de2a4bd074 100644 --- a/packages/angular_devkit/build_angular/test/browser/index_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/index_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, tags, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder works with BOM index.html', () => { diff --git a/packages/angular_devkit/build_angular/test/browser/lazy-module_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/lazy-module_spec_large.ts index 1583ea44a3..c431ba1ece 100644 --- a/packages/angular_devkit/build_angular/test/browser/lazy-module_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/lazy-module_spec_large.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; import { BrowserBuilderSchema } from '../../src'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; export const lazyModuleFiles: { [path: string]: string } = { @@ -80,7 +81,7 @@ describe('Browser Builder lazy modules', () => { host.writeMultipleFiles(lazyModuleFiles); host.writeMultipleFiles(lazyModuleImport); - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(join(outputPath, 'lazy-lazy-module.js'))).toBe(true); @@ -92,7 +93,7 @@ describe('Browser Builder lazy modules', () => { host.writeMultipleFiles(lazyModuleFiles); host.writeMultipleFiles(lazyModuleImport); - runTargetSpec(host, browserTargetSpec, { aot: true }).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, { aot: true }).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync() @@ -109,7 +110,7 @@ describe('Browser Builder lazy modules', () => { // Using `import()` in TS require targetting `esnext` modules. host.replaceInFile('src/tsconfig.app.json', `"module": "es2015"`, `"module": "esnext"`); - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), ).subscribe(undefined, done.fail, done); @@ -125,7 +126,7 @@ describe('Browser Builder lazy modules', () => { }); host.replaceInFile('src/tsconfig.app.json', `"module": "es2015"`, `"module": "esnext"`); - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, 'lazy-module.js'))).toBe(true)), ).subscribe(undefined, done.fail, done); @@ -137,7 +138,7 @@ describe('Browser Builder lazy modules', () => { 'src/main.ts': `declare var System: any; System.import('./lazy-module');`, }); - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), ).subscribe(undefined, done.fail, done); @@ -152,7 +153,7 @@ describe('Browser Builder lazy modules', () => { const overrides: Partial = { namedChunks: false }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), ).subscribe(undefined, done.fail, done); @@ -166,7 +167,7 @@ describe('Browser Builder lazy modules', () => { }); host.replaceInFile('src/tsconfig.app.json', `"module": "es2015"`, `"module": "esnext"`); - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '1.js'))).toBe(true)), @@ -185,7 +186,7 @@ describe('Browser Builder lazy modules', () => { const overrides: Partial = { commonChunk: false }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '1.js'))).toBe(true)), @@ -217,7 +218,7 @@ describe('Browser Builder lazy modules', () => { const overrides: Partial = { lazyModules: ['src/app/lazy/lazy.module'] }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, 'src-app-lazy-lazy-module.js'))) .toBe(true)), @@ -252,7 +253,7 @@ describe('Browser Builder lazy modules', () => { optimization: true, }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync() .exists(join(outputPath, 'src-app-lazy-lazy-module-ngfactory.js'))) diff --git a/packages/angular_devkit/build_angular/test/browser/license-extraction_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/license-extraction_spec_large.ts index aea18cb623..3d5c4fb3d0 100644 --- a/packages/angular_devkit/build_angular/test/browser/license-extraction_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/license-extraction_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder license extraction', () => { @@ -23,7 +24,7 @@ describe('Browser Builder license extraction', () => { // TODO: make license extraction independent from optimization level. const overrides = { extractLicenses: true, optimization: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, '3rdpartylicenses.txt'); diff --git a/packages/angular_devkit/build_angular/test/browser/no-entry-module_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/no-entry-module_spec_large.ts index 8eb0fce414..aae0ba9fea 100644 --- a/packages/angular_devkit/build_angular/test/browser/no-entry-module_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/no-entry-module_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder no entry module', () => { @@ -21,7 +22,7 @@ describe('Browser Builder no entry module', () => { const overrides = { baseHref: '/myUrl' }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); diff --git a/packages/angular_devkit/build_angular/test/browser/optimization-level_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/optimization-level_spec_large.ts index e9c8c9502c..d8358a216a 100644 --- a/packages/angular_devkit/build_angular/test/browser/optimization-level_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/optimization-level_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder optimization level', () => { @@ -20,7 +21,7 @@ describe('Browser Builder optimization level', () => { it('works', (done) => { const overrides = { optimization: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -36,7 +37,7 @@ describe('Browser Builder optimization level', () => { const overrides = { optimization: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'vendor.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/output-hashing_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/output-hashing_spec_large.ts index ae577e8aeb..4f3555cb4e 100644 --- a/packages/angular_devkit/build_angular/test/browser/output-hashing_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/output-hashing_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize } from '@angular-devkit/core'; import { concatMap, tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; import { lazyModuleFiles, lazyModuleImport } from './lazy-module_spec_large'; @@ -60,7 +61,7 @@ describe('Browser Builder output hashing', () => { // We must do several builds instead of a single one in watch mode, so that the output // path is deleted on each run and only contains the most recent files. - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap(() => { // Save the current hashes. oldHashes = generateFileHashMap(); @@ -68,7 +69,7 @@ describe('Browser Builder output hashing', () => { host.writeMultipleFiles(lazyModuleImport); }), // Lazy chunk hash should have changed without modifying main bundle. - concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, []); @@ -76,7 +77,7 @@ describe('Browser Builder output hashing', () => { host.writeMultipleFiles({ 'src/styles.css': 'body { background: blue; }' }); }), // Style hash should change. - concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, ['styles']); @@ -84,7 +85,7 @@ describe('Browser Builder output hashing', () => { host.writeMultipleFiles({ 'src/app/app.component.css': 'h1 { margin: 10px; }' }); }), // Main hash should change, since inline styles go in the main bundle. - concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, ['main']); @@ -92,7 +93,7 @@ describe('Browser Builder output hashing', () => { host.appendToFile('src/app/lazy/lazy.module.ts', `console.log(1);`); }), // Lazy loaded bundle should change, and so should inline. - concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, ['lazy.module']); @@ -100,7 +101,7 @@ describe('Browser Builder output hashing', () => { host.appendToFile('src/main.ts', ''); }), // Nothing should have changed. - concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, []); @@ -116,7 +117,9 @@ describe('Browser Builder output hashing', () => { // We must do several builds instead of a single one in watch mode, so that the output // path is deleted on each run and only contains the most recent files. // 'all' should hash everything. - runTargetSpec(host, browserTargetSpec, { outputHashing: 'all', extractCss: true }).pipe( + runTargetSpec( + workspaceRoot, host, browserTargetSpec, { outputHashing: 'all', extractCss: true }, + ).pipe( tap(() => { expect(host.fileMatchExists('dist', /runtime\.[0-9a-f]{20}\.js/)).toBeTruthy(); expect(host.fileMatchExists('dist', /main\.[0-9a-f]{20}\.js/)).toBeTruthy(); @@ -126,7 +129,7 @@ describe('Browser Builder output hashing', () => { expect(host.fileMatchExists('dist', /spectrum\.[0-9a-f]{20}\.png/)).toBeTruthy(); }), // 'none' should hash nothing. - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { outputHashing: 'none', extractCss: true })), tap(() => { expect(host.fileMatchExists('dist', /runtime\.[0-9a-f]{20}\.js/)).toBeFalsy(); @@ -137,7 +140,7 @@ describe('Browser Builder output hashing', () => { expect(host.fileMatchExists('dist', /spectrum\.[0-9a-f]{20}\.png/)).toBeFalsy(); }), // 'media' should hash css resources only. - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { outputHashing: 'media', extractCss: true })), tap(() => { expect(host.fileMatchExists('dist', /runtime\.[0-9a-f]{20}\.js/)).toBeFalsy(); @@ -148,7 +151,7 @@ describe('Browser Builder output hashing', () => { expect(host.fileMatchExists('dist', /spectrum\.[0-9a-f]{20}\.png/)).toBeTruthy(); }), // 'bundles' should hash bundles only. - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { outputHashing: 'bundles', extractCss: true })), tap(() => { expect(host.fileMatchExists('dist', /runtime\.[0-9a-f]{20}\.js/)).toBeTruthy(); diff --git a/packages/angular_devkit/build_angular/test/browser/output-path_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/output-path_spec_large.ts index dd5a62c191..9c2e20b640 100644 --- a/packages/angular_devkit/build_angular/test/browser/output-path_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/output-path_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder output path', () => { @@ -26,7 +27,7 @@ describe('Browser Builder output path', () => { error: done.fail, }); - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); expect(host.scopedSync().exists(outputPath)).toBe(false); @@ -37,6 +38,7 @@ describe('Browser Builder output path', () => { it('does not allow output path to be project root', (done) => { const overrides = { outputPath: './' }; - runTargetSpec(host, browserTargetSpec, overrides).subscribe(undefined, () => done(), done.fail); + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + .subscribe(undefined, () => done(), done.fail); }, Timeout.Basic); }); diff --git a/packages/angular_devkit/build_angular/test/browser/poll_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/poll_spec_large.ts index 61b524c937..de800bca19 100644 --- a/packages/angular_devkit/build_angular/test/browser/poll_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/poll_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { debounceTime, take, tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder poll', () => { @@ -18,7 +19,7 @@ describe('Browser Builder poll', () => { const overrides = { watch: true, poll: 1000 }; let msAvg = 1000; let lastTime: number; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( // Debounce 1s, otherwise changes are too close together and polling doesn't work. debounceTime(1000), tap((buildEvent) => expect(buildEvent.success).toBe(true)), diff --git a/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts index c9b36fcf02..a34a273c47 100644 --- a/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { debounceTime, take, tap } from 'rxjs/operators'; -import { TestLogger, Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; import { lazyModuleFiles, lazyModuleImport } from './lazy-module_spec_large'; @@ -78,7 +79,7 @@ describe('Browser Builder rebuilds', () => { let buildNumber = 0; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( // We must debounce on watch mode because file watchers are not very accurate. // Changes from just before a process runs can be picked up and cause rebuilds. // In this case, cleanup from the test right before this one causes a few rebuilds. @@ -126,7 +127,7 @@ describe('Browser Builder rebuilds', () => { it('rebuilds on CSS changes', (done) => { const overrides = { watch: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( debounceTime(500), tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => host.appendToFile('src/app/app.component.css', ':host { color: blue; }')), @@ -149,7 +150,7 @@ describe('Browser Builder rebuilds', () => { const typeError = `is not assignable to parameter of type 'number'`; let buildNumber = 0; - runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( debounceTime(1000), tap((buildEvent) => { buildNumber += 1; @@ -199,7 +200,7 @@ describe('Browser Builder rebuilds', () => { const overrides = { watch: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( debounceTime(1000), tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => host.writeMultipleFiles({ 'src/type.ts': `export type MyType = string;` })), @@ -221,7 +222,7 @@ describe('Browser Builder rebuilds', () => { const syntaxError = 'Declaration or statement expected.'; let buildNumber = 0; - runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( debounceTime(1000), tap((buildEvent) => { buildNumber += 1; @@ -283,7 +284,7 @@ describe('Browser Builder rebuilds', () => { const overrides = { watch: true, aot: true, forkTypeChecker: false }; let buildNumber = 0; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( debounceTime(1000), tap((buildEvent) => { buildNumber += 1; diff --git a/packages/angular_devkit/build_angular/test/browser/replacements_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/replacements_spec_large.ts index 9bed4da0bf..91d9068092 100644 --- a/packages/angular_devkit/build_angular/test/browser/replacements_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/replacements_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder file replacements', () => { @@ -38,7 +39,7 @@ describe('Browser Builder file replacements', () => { ], }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -60,7 +61,7 @@ describe('Browser Builder file replacements', () => { ], }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -82,7 +83,8 @@ describe('Browser Builder file replacements', () => { ], }; - runTargetSpec(host, browserTargetSpec, overrides).subscribe(undefined, () => done(), done.fail); + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + .subscribe(undefined, () => done(), done.fail); }, Timeout.Basic); it(`fails compilation with missing 'with' file`, (done) => { @@ -95,6 +97,7 @@ describe('Browser Builder file replacements', () => { ], }; - runTargetSpec(host, browserTargetSpec, overrides).subscribe(undefined, () => done(), done.fail); + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + .subscribe(undefined, () => done(), done.fail); }, Timeout.Basic); }); diff --git a/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts index 391b260bae..658a5fcca9 100644 --- a/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { PathFragment, join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder scripts array', () => { @@ -66,7 +67,7 @@ describe('Browser Builder scripts array', () => { scripts: getScriptsOption(), }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => Object.keys(matches).forEach(fileName => { const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName))); @@ -85,7 +86,7 @@ describe('Browser Builder scripts array', () => { scripts: getScriptsOption(), }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const scriptsBundle = host.fileMatchExists(outputPath, /scripts\.[0-9a-f]{20}\.js/); @@ -114,7 +115,7 @@ describe('Browser Builder scripts array', () => { const overrides = { scripts: getScriptsOption() }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const re = new RegExp( diff --git a/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts index 5d2d5eae3b..a81c8641e0 100644 --- a/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder', () => { @@ -44,7 +45,7 @@ describe('Browser Builder', () => { it('errors if no ngsw-config.json is present', (done) => { const overrides = { serviceWorker: true }; - runTargetSpec(host, browserTargetSpec, overrides) + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) .subscribe(event => { expect(event.success).toBe(false); }, () => done(), done.fail); @@ -57,7 +58,7 @@ describe('Browser Builder', () => { }); const overrides = { serviceWorker: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap(buildEvent => { expect(buildEvent.success).toBe(true); expect(host.scopedSync().exists(normalize('dist/ngsw.json'))); @@ -112,7 +113,7 @@ describe('Browser Builder', () => { }); const overrides = { serviceWorker: true, baseHref: '/foo/bar' }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap(buildEvent => { expect(buildEvent.success).toBe(true); expect(host.scopedSync().exists(normalize('dist/ngsw.json'))); diff --git a/packages/angular_devkit/build_angular/test/browser/source-map_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/source-map_spec_large.ts index 305f6bb0a9..e9aa783127 100644 --- a/packages/angular_devkit/build_angular/test/browser/source-map_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/source-map_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder source map', () => { @@ -20,7 +21,7 @@ describe('Browser Builder source map', () => { it('works', (done) => { const overrides = { sourceMap: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js.map'); @@ -32,7 +33,7 @@ describe('Browser Builder source map', () => { it('does not output source map when disabled', (done) => { const overrides = { sourceMap: false }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js.map'); @@ -44,7 +45,7 @@ describe('Browser Builder source map', () => { it('supports eval source map', (done) => { const overrides = { sourceMap: true, evalSourceMap: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(join(outputPath, 'main.js.map'))).toBe(false); diff --git a/packages/angular_devkit/build_angular/test/browser/stats-json_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/stats-json_spec_large.ts index f881eeb37e..e853a74f94 100644 --- a/packages/angular_devkit/build_angular/test/browser/stats-json_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/stats-json_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder stats json', () => { @@ -20,7 +21,7 @@ describe('Browser Builder stats json', () => { it('works', (done) => { const overrides = { statsJson: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'stats.json'); diff --git a/packages/angular_devkit/build_angular/test/browser/styles_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/styles_spec_large.ts index f88d007ef3..36d5082207 100644 --- a/packages/angular_devkit/build_angular/test/browser/styles_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/styles_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, tags, virtualFs } from '@angular-devkit/core'; import { concatMap, tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder styles', () => { @@ -66,7 +67,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true, styles: getStylesOption() }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), // Check css files were created. tap(() => Object.keys(cssMatches).forEach(fileName => { @@ -83,7 +84,7 @@ describe('Browser Builder styles', () => { expect(content).toMatch(cssIndexMatches[fileName]); })), // Also test with extractCss false. - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { extractCss: false, styles: getStylesOption() })), // TODO: figure out why adding this tap breaks typings. // This also happens in the output-hashing spec. @@ -123,7 +124,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -172,7 +173,7 @@ describe('Browser Builder styles', () => { host.replaceInFile('src/app/app.component.ts', './app.component.css', `./app.component.${ext}`); - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => Object.keys(matches).forEach(fileName => { const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName))); @@ -202,7 +203,7 @@ describe('Browser Builder styles', () => { styles: [{ input: `src/styles.${ext}` }], }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -217,7 +218,7 @@ describe('Browser Builder styles', () => { ], }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Complex); @@ -266,7 +267,7 @@ describe('Browser Builder styles', () => { }, }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => Object.keys(matches).forEach(fileName => { const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName))); @@ -299,7 +300,7 @@ describe('Browser Builder styles', () => { styles: [`src/styles.scss`], }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = 'dist/styles.css'; @@ -342,7 +343,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true, styles: [`src/styles.scss`] }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -357,7 +358,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true, optimization: false }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = 'dist/styles.css'; @@ -380,7 +381,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true, optimization: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = 'dist/styles.css'; @@ -415,7 +416,7 @@ describe('Browser Builder styles', () => { const mainBundle = 'dist/main.js'; // Check base paths are correctly generated. - runTargetSpec(host, browserTargetSpec, { aot: true, extractCss: true }).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, { aot: true, extractCss: true }).pipe( tap(() => { const styles = virtualFs.fileBufferToString( host.scopedSync().read(normalize(stylesBundle)), @@ -435,7 +436,7 @@ describe('Browser Builder styles', () => { .toBe(true); }), // Check urls with deploy-url scheme are used as is. - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { extractCss: true, baseHref: '/base/', deployUrl: 'http://deploy.url/' }, )), tap(() => { @@ -449,7 +450,7 @@ describe('Browser Builder styles', () => { .toContain(`url('http://deploy.url/assets/component-img-absolute.svg')`); }), // Check urls with base-href scheme are used as is (with deploy-url). - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { extractCss: true, baseHref: 'http://base.url/', deployUrl: 'deploy/' }, )), tap(() => { @@ -463,7 +464,7 @@ describe('Browser Builder styles', () => { .toContain(`url('http://base.url/deploy/assets/component-img-absolute.svg')`); }), // Check urls with deploy-url and base-href scheme only use deploy-url. - concatMap(() => runTargetSpec(host, browserTargetSpec, { + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { extractCss: true, baseHref: 'http://base.url/', deployUrl: 'http://deploy.url/', @@ -478,7 +479,7 @@ describe('Browser Builder styles', () => { expect(main).toContain(`url('http://deploy.url/assets/component-img-absolute.svg')`); }), // Check with schemeless base-href and deploy-url flags. - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { extractCss: true, baseHref: '/base/', deployUrl: 'deploy/' }, )), tap(() => { @@ -490,7 +491,7 @@ describe('Browser Builder styles', () => { expect(main).toContain(`url('/base/deploy/assets/component-img-absolute.svg')`); }), // Check with identical base-href and deploy-url flags. - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { extractCss: true, baseHref: '/base/', deployUrl: '/base/' }, )), tap(() => { @@ -502,7 +503,7 @@ describe('Browser Builder styles', () => { expect(main).toContain(`url('/base/assets/component-img-absolute.svg')`); }), // Check with only base-href flag. - concatMap(() => runTargetSpec(host, browserTargetSpec, + concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { extractCss: true, baseHref: '/base/' }, )), tap(() => { @@ -523,7 +524,7 @@ describe('Browser Builder styles', () => { scripts: ['../../../../node_modules/bootstrap/dist/js/bootstrap.js'], }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); diff --git a/packages/angular_devkit/build_angular/test/browser/subresource-integrity_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/subresource-integrity_spec_large.ts index 1539eddef6..9b47d87c28 100644 --- a/packages/angular_devkit/build_angular/test/browser/subresource-integrity_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/subresource-integrity_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder subresource integrity', () => { @@ -25,7 +26,7 @@ describe('Browser Builder subresource integrity', () => { const overrides = { subresourceIntegrity: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'index.html'); diff --git a/packages/angular_devkit/build_angular/test/browser/tsconfig-paths_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/tsconfig-paths_spec_large.ts index 0ebfdd91bd..ee565f6368 100644 --- a/packages/angular_devkit/build_angular/test/browser/tsconfig-paths_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/tsconfig-paths_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder tsconfig paths', () => { @@ -25,7 +26,7 @@ describe('Browser Builder tsconfig paths', () => { }, `); - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -67,7 +68,7 @@ describe('Browser Builder tsconfig paths', () => { console.log(meaning5) `); - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); diff --git a/packages/angular_devkit/build_angular/test/browser/vendor-chunk_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/vendor-chunk_spec_large.ts index 63862b161d..8f852678ee 100644 --- a/packages/angular_devkit/build_angular/test/browser/vendor-chunk_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/vendor-chunk_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder vendor chunk', () => { @@ -20,7 +21,7 @@ describe('Browser Builder vendor chunk', () => { it('works', (done) => { const overrides = { vendorChunk: true }; - runTargetSpec(host, browserTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'vendor.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/works_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/works_spec_large.ts index c7e20a5de8..af589d74d9 100644 --- a/packages/angular_devkit/build_angular/test/browser/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/works_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, runTargetSpec } from '../utils'; +import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; describe('Browser Builder basic test', () => { @@ -18,7 +19,7 @@ describe('Browser Builder basic test', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(host, browserTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { // Default files should be in outputPath. diff --git a/packages/angular_devkit/build_angular/test/dev-server/proxy_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/proxy_spec_large.ts index 65853bd87d..79011b20c8 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/proxy_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/proxy_spec_large.ts @@ -6,12 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ +import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import * as express from 'express'; // tslint:disable-line:no-implicit-dependencies import * as http from 'http'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; import { DevServerBuilderOptions } from '../../src'; -import { devServerTargetSpec, host, request, runTargetSpec } from '../utils'; +import { devServerTargetSpec, host, workspaceRoot } from '../utils'; describe('Dev Server Builder proxy', () => { @@ -39,7 +40,7 @@ describe('Dev Server Builder proxy', () => { const overrides: Partial = { proxyConfig: 'proxy.config.json' }; - runTargetSpec(host, devServerTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/api/test'))), tap(response => { @@ -53,7 +54,7 @@ describe('Dev Server Builder proxy', () => { it('errors out with a missing proxy file', (done) => { const overrides: Partial = { proxyConfig: '../proxy.config.json' }; - runTargetSpec(host, devServerTargetSpec, overrides) + runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides) .subscribe(undefined, () => done(), done.fail); }, 30000); }); diff --git a/packages/angular_devkit/build_angular/test/dev-server/public-host_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/public-host_spec_large.ts index 3d1b3eaa5a..7e8d82ca7d 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/public-host_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/public-host_spec_large.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ +import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; import { DevServerBuilderOptions } from '../../src'; -import { devServerTargetSpec, host, request, runTargetSpec } from '../utils'; +import { devServerTargetSpec, host, workspaceRoot } from '../utils'; describe('Dev Server Builder public host', () => { @@ -21,7 +22,7 @@ describe('Dev Server Builder public host', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(host, devServerTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, devServerTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/', headers))), tap(response => expect(response).toContain('Invalid Host header')), @@ -32,7 +33,7 @@ describe('Dev Server Builder public host', () => { it('works', (done) => { const overrides: Partial = { publicHost: headers.host }; - runTargetSpec(host, devServerTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/', headers))), tap(response => expect(response).toContain('HelloWorldApp')), @@ -43,7 +44,7 @@ describe('Dev Server Builder public host', () => { it('works', (done) => { const overrides: Partial = { disableHostCheck: true }; - runTargetSpec(host, devServerTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/', headers))), tap(response => expect(response).toContain('HelloWorldApp')), diff --git a/packages/angular_devkit/build_angular/test/dev-server/serve-path_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/serve-path_spec_large.ts index f0e16dbf8c..efcb8a322f 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/serve-path_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/serve-path_spec_large.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ +import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; import { DevServerBuilderOptions } from '../../src'; -import { devServerTargetSpec, host, request, runTargetSpec } from '../utils'; +import { devServerTargetSpec, host, workspaceRoot } from '../utils'; describe('Dev Server Builder serve path', () => { @@ -20,7 +21,7 @@ describe('Dev Server Builder serve path', () => { it('works', (done) => { const overrides: Partial = { servePath: 'test/' }; - runTargetSpec(host, devServerTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/test/'))), tap(response => expect(response).toContain('HelloWorldApp')), diff --git a/packages/angular_devkit/build_angular/test/dev-server/ssl_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/ssl_spec_large.ts index cbc7e82817..718c930974 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/ssl_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/ssl_spec_large.ts @@ -6,11 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ +import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import { tags } from '@angular-devkit/core'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; import { DevServerBuilderOptions } from '../../src'; -import { devServerTargetSpec, host, request, runTargetSpec } from '../utils'; +import { devServerTargetSpec, host, workspaceRoot } from '../utils'; describe('Dev Server Builder ssl', () => { @@ -20,7 +21,7 @@ describe('Dev Server Builder ssl', () => { it('works', (done) => { const overrides: Partial = { ssl: true }; - runTargetSpec(host, devServerTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('https://localhost:4200/index.html'))), tap(response => expect(response).toContain('HelloWorldApp')), @@ -92,7 +93,7 @@ describe('Dev Server Builder ssl', () => { sslCert: '../ssl/server.crt', }; - runTargetSpec(host, devServerTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('https://localhost:4200/index.html'))), tap(response => expect(response).toContain('HelloWorldApp')), diff --git a/packages/angular_devkit/build_angular/test/dev-server/works_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/works_spec_large.ts index da5e4bc0ec..9f141db9bb 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/works_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; -import { devServerTargetSpec, host, request, runTargetSpec } from '../utils'; +import { devServerTargetSpec, host, workspaceRoot } from '../utils'; describe('Dev Server Builder', () => { @@ -16,7 +17,7 @@ describe('Dev Server Builder', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(host, devServerTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, devServerTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/index.html'))), tap(response => expect(response).toContain('HelloWorldApp')), diff --git a/packages/angular_devkit/build_angular/test/extract-i18n/works_spec_large.ts b/packages/angular_devkit/build_angular/test/extract-i18n/works_spec_large.ts index 6d35a786bb..bd2ef62582 100644 --- a/packages/angular_devkit/build_angular/test/extract-i18n/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/extract-i18n/works_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { TestLogger, extractI18nTargetSpec, host, runTargetSpec } from '../utils'; +import { extractI18nTargetSpec, host, workspaceRoot } from '../utils'; describe('Extract i18n Target', () => { @@ -20,7 +21,7 @@ describe('Extract i18n Target', () => { it('works', (done) => { host.appendToFile('src/app/app.component.html', '

i18n test

'); - runTargetSpec(host, extractI18nTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, extractI18nTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists((extractionFile))).toBe(true); @@ -35,7 +36,7 @@ describe('Extract i18n Target', () => { host.appendToFile('src/app/app.component.html', '

Hello world inner

'); - runTargetSpec(host, extractI18nTargetSpec, {}, logger).pipe( + runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, {}, logger).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); const msg = 'Could not mark an element as translatable inside a translatable section'; @@ -48,7 +49,7 @@ describe('Extract i18n Target', () => { host.appendToFile('src/app/app.component.html', '

i18n test

'); const overrides = { i18nLocale: 'fr' }; - runTargetSpec(host, extractI18nTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists((extractionFile))).toBe(true); @@ -64,7 +65,7 @@ describe('Extract i18n Target', () => { const extractionFile = join(normalize('src'), outFile); const overrides = { outFile }; - runTargetSpec(host, extractI18nTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(extractionFile)).toBe(true); @@ -81,7 +82,7 @@ describe('Extract i18n Target', () => { const extractionFile = join(normalize('src'), outputPath, 'messages.xlf'); const overrides = { outputPath }; - runTargetSpec(host, extractI18nTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(extractionFile)).toBe(true); @@ -96,7 +97,7 @@ describe('Extract i18n Target', () => { const extractionFile = join(normalize('src'), 'messages.xmb'); const overrides = { i18nFormat: 'xmb' }; - runTargetSpec(host, extractI18nTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(extractionFile)).toBe(true); diff --git a/packages/angular_devkit/build_angular/test/karma/assets_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/assets_spec_large.ts index 992e9b8962..a7ee0e920b 100644 --- a/packages/angular_devkit/build_angular/test/karma/assets_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/assets_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { host, karmaTargetSpec, runTargetSpec } from '../utils'; +import { host, karmaTargetSpec, workspaceRoot } from '../utils'; describe('Karma Builder assets', () => { @@ -99,7 +100,7 @@ describe('Karma Builder assets', () => { ], }; - runTargetSpec(host, karmaTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( tap(buildEvent => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 45000); diff --git a/packages/angular_devkit/build_angular/test/karma/code-coverage_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/code-coverage_spec_large.ts index 5fd535c83c..67aef82541 100644 --- a/packages/angular_devkit/build_angular/test/karma/code-coverage_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/code-coverage_spec_large.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { debounceTime, tap } from 'rxjs/operators'; import { NormalizedKarmaBuilderSchema } from '../../src'; -import { host, karmaTargetSpec, runTargetSpec } from '../utils'; +import { host, karmaTargetSpec, workspaceRoot } from '../utils'; describe('Karma Builder code coverage', () => { @@ -21,7 +22,7 @@ describe('Karma Builder code coverage', () => { it('works', (done) => { const overrides: Partial = { codeCoverage: true }; - runTargetSpec(host, karmaTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( // It seems like the coverage files take a while being written to disk, so we wait 500ms here. debounceTime(500), tap(buildEvent => { @@ -43,7 +44,7 @@ describe('Karma Builder code coverage', () => { ], }; - runTargetSpec(host, karmaTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( // It seems like the coverage files take a while being written to disk, so we wait 500ms here. debounceTime(500), tap(buildEvent => { diff --git a/packages/angular_devkit/build_angular/test/karma/rebuilds_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/rebuilds_spec_large.ts index 71f8acd518..33d652d339 100644 --- a/packages/angular_devkit/build_angular/test/karma/rebuilds_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/rebuilds_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { debounceTime, take, tap } from 'rxjs/operators'; -import { host, karmaTargetSpec, runTargetSpec } from '../utils'; +import { host, karmaTargetSpec, workspaceRoot } from '../utils'; // Karma watch mode is currently bugged: @@ -20,7 +21,7 @@ xdescribe('Karma Builder watch mode', () => { it('works', (done) => { const overrides = { watch: true }; - runTargetSpec(host, karmaTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( debounceTime(500), tap((buildEvent) => expect(buildEvent.success).toBe(true)), take(1), @@ -31,7 +32,7 @@ xdescribe('Karma Builder watch mode', () => { const overrides = { watch: true }; let buildNumber = 0; - runTargetSpec(host, karmaTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( debounceTime(500), tap((buildEvent) => { buildNumber += 1; diff --git a/packages/angular_devkit/build_angular/test/karma/replacements_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/replacements_spec_large.ts index 584c363f75..47d004a3f9 100644 --- a/packages/angular_devkit/build_angular/test/karma/replacements_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/replacements_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { host, karmaTargetSpec, runTargetSpec } from '../utils'; +import { host, karmaTargetSpec, workspaceRoot } from '../utils'; describe('Karma Builder file replacements', () => { @@ -38,7 +39,7 @@ describe('Karma Builder file replacements', () => { }], }; - runTargetSpec(host, karmaTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); diff --git a/packages/angular_devkit/build_angular/test/karma/works_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/works_spec_large.ts index 2450482c01..d461b6af1c 100644 --- a/packages/angular_devkit/build_angular/test/karma/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/works_spec_large.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { host, karmaTargetSpec, runTargetSpec } from '../utils'; +import { host, karmaTargetSpec, workspaceRoot } from '../utils'; describe('Karma Builder', () => { @@ -15,7 +16,7 @@ describe('Karma Builder', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('runs', (done) => { - runTargetSpec(host, karmaTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, karmaTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -24,14 +25,14 @@ describe('Karma Builder', () => { host.writeMultipleFiles({ 'src/app/app.component.spec.ts': '

definitely not typescript

', }); - runTargetSpec(host, karmaTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, karmaTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), ).subscribe(undefined, done.fail, done); }, 30000); it('supports ES2015 target', (done) => { host.replaceInFile('tsconfig.json', '"target": "es5"', '"target": "es2015"'); - runTargetSpec(host, karmaTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, karmaTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); diff --git a/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts b/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts index e9c1558545..4a9a3c2fc9 100644 --- a/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize } from '@angular-devkit/core'; import { retry } from 'rxjs/operators'; -import { host, protractorTargetSpec, runTargetSpec } from '../utils'; +import { host, protractorTargetSpec, workspaceRoot } from '../utils'; // TODO: replace this with an "it()" macro that's reusable globally. @@ -23,7 +24,7 @@ describe('Protractor Builder', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); linuxOnlyIt('works', (done) => { - runTargetSpec(host, protractorTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, protractorTargetSpec).pipe( retry(3), ).subscribe(undefined, done.fail, done); }, 30000); @@ -31,7 +32,7 @@ describe('Protractor Builder', () => { linuxOnlyIt('works with no devServerTarget', (done) => { const overrides = { devServerTarget: undefined }; - runTargetSpec(host, protractorTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, protractorTargetSpec, overrides).pipe( // This should fail because no server is available for connection. ).subscribe(undefined, () => done(), done.fail); }, 30000); @@ -42,7 +43,7 @@ describe('Protractor Builder', () => { const overrides = { specs: ['./e2e/renamed-app.e2e-spec.ts'] }; - runTargetSpec(host, protractorTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, protractorTargetSpec, overrides).pipe( retry(3), ).subscribe(undefined, done.fail, done); }, 60000); @@ -61,7 +62,7 @@ describe('Protractor Builder', () => { const overrides = { suite: 'app' }; - runTargetSpec(host, protractorTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, protractorTargetSpec, overrides).pipe( retry(3), ).subscribe(undefined, done.fail, done); }, 60000); diff --git a/packages/angular_devkit/build_angular/test/server/base_spec_large.ts b/packages/angular_devkit/build_angular/test/server/base_spec_large.ts index 068d4085dd..b6aa815e9f 100644 --- a/packages/angular_devkit/build_angular/test/server/base_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/server/base_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, host, runTargetSpec } from '../utils'; +import { Timeout, host, workspaceRoot } from '../utils'; describe('Server Builder', () => { @@ -20,7 +21,7 @@ describe('Server Builder', () => { it('works (base)', (done) => { const overrides = { }; - runTargetSpec(host, { project: 'app', target: 'server' }, overrides).pipe( + runTargetSpec(workspaceRoot, host, { project: 'app', target: 'server' }, overrides).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(true); diff --git a/packages/angular_devkit/build_angular/test/tslint/works_spec_large.ts b/packages/angular_devkit/build_angular/test/tslint/works_spec_large.ts index 8999496845..4056c8ecf8 100644 --- a/packages/angular_devkit/build_angular/test/tslint/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/tslint/works_spec_large.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ +import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; import { TslintBuilderOptions } from '../../src'; -import { TestLogger, host, runTargetSpec, tslintTargetSpec } from '../utils'; +import { host, tslintTargetSpec, workspaceRoot } from '../utils'; describe('Tslint Target', () => { @@ -19,7 +20,7 @@ describe('Tslint Target', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(host, tslintTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -28,7 +29,7 @@ describe('Tslint Target', () => { host.writeMultipleFiles(filesWithErrors); const overrides: Partial = { exclude: ['**/foo.ts'] }; - runTargetSpec(host, tslintTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -37,7 +38,7 @@ describe('Tslint Target', () => { host.writeMultipleFiles(filesWithErrors); const overrides: Partial = { fix: true }; - runTargetSpec(host, tslintTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = normalize('src/foo.ts'); @@ -52,7 +53,7 @@ describe('Tslint Target', () => { const logger = new TestLogger('lint-force'); const overrides: Partial = { force: true }; - runTargetSpec(host, tslintTargetSpec, overrides, logger).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(logger.includes(`" should be '`)).toBe(true); @@ -66,7 +67,7 @@ describe('Tslint Target', () => { const logger = new TestLogger('lint-format'); const overrides: Partial = { format: 'stylish' }; - runTargetSpec(host, tslintTargetSpec, overrides, logger).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), tap(() => { expect(logger.includes(`quotemark`)).toBe(true); @@ -90,7 +91,7 @@ describe('Tslint Target', () => { }); const overrides: Partial = { tslintConfig: undefined }; - runTargetSpec(host, tslintTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -111,7 +112,7 @@ describe('Tslint Target', () => { }); const overrides: Partial = { tslintConfig: 'tslint.json' }; - runTargetSpec(host, tslintTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -122,7 +123,7 @@ describe('Tslint Target', () => { files: ['src/app/**/*.ts'], }; - runTargetSpec(host, tslintTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -132,7 +133,7 @@ describe('Tslint Target', () => { tsConfig: 'src/tsconfig.app.json', }; - runTargetSpec(host, tslintTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -142,7 +143,7 @@ describe('Tslint Target', () => { tsConfig: ['src/tsconfig.app.json'], }; - runTargetSpec(host, tslintTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -152,7 +153,7 @@ describe('Tslint Target', () => { tsConfig: ['src/tsconfig.app.json', 'src/tsconfig.spec.json'], }; - runTargetSpec(host, tslintTargetSpec, overrides).pipe( + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -163,7 +164,7 @@ describe('Tslint Target', () => { typeCheck: true, }; - runTargetSpec(host, tslintTargetSpec, overrides).pipe( - ).subscribe(undefined, () => done(), done.fail); + runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides) + .subscribe(undefined, () => done(), done.fail); }, 30000); }); diff --git a/packages/angular_devkit/build_angular/test/utils/run-target-spec.ts b/packages/angular_devkit/build_angular/test/utils.ts similarity index 51% rename from packages/angular_devkit/build_angular/test/utils/run-target-spec.ts rename to packages/angular_devkit/build_angular/test/utils.ts index 4d4197d0d6..ef4f819b84 100644 --- a/packages/angular_devkit/build_angular/test/utils/run-target-spec.ts +++ b/packages/angular_devkit/build_angular/test/utils.ts @@ -6,20 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import { Architect, BuildEvent, TargetSpecifier } from '@angular-devkit/architect'; -import { experimental, join, logging, normalize } from '@angular-devkit/core'; -import { Observable } from 'rxjs'; -import { concatMap } from 'rxjs/operators'; -import { TestProjectHost } from '../utils/test-project-host'; +import { TestProjectHost } from '@angular-devkit/architect/testing'; +import { join, normalize } from '@angular-devkit/core'; -const workspaceFile = normalize('.angular.json'); const devkitRoot = normalize((global as any)._DevKitRoot); // tslint:disable-line:no-any - export const workspaceRoot = join(devkitRoot, 'tests/@angular_devkit/build_angular/hello-world-app/'); export const host = new TestProjectHost(workspaceRoot); export const outputPath = normalize('dist'); + export const browserTargetSpec = { project: 'app', target: 'build' }; export const devServerTargetSpec = { project: 'app', target: 'serve' }; export const extractI18nTargetSpec = { project: 'app', target: 'extract-i18n' }; @@ -27,17 +23,9 @@ export const karmaTargetSpec = { project: 'app', target: 'test' }; export const tslintTargetSpec = { project: 'app', target: 'lint' }; export const protractorTargetSpec = { project: 'app-e2e', target: 'e2e' }; -export function runTargetSpec( - host: TestProjectHost, - targetSpec: TargetSpecifier, - overrides = {}, - logger: logging.Logger = new logging.NullLogger(), -): Observable { - targetSpec = { ...targetSpec, overrides }; - const workspace = new experimental.workspace.Workspace(workspaceRoot, host); - - return workspace.loadWorkspaceFromHost(workspaceFile).pipe( - concatMap(ws => new Architect(ws).loadArchitect()), - concatMap(arch => arch.run(arch.getBuilderConfiguration(targetSpec), { logger })), - ); +export enum Timeout { + Basic = 30000, + Standard = Basic * 1.5, + Complex = Basic * 2, + Massive = Basic * 4, } diff --git a/packages/angular_devkit/build_angular/test/utils/timeouts.ts b/packages/angular_devkit/build_angular/test/utils/timeouts.ts deleted file mode 100644 index 46e0fbfd23..0000000000 --- a/packages/angular_devkit/build_angular/test/utils/timeouts.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -export enum Timeout { - Basic = 30000, - Standard = Basic * 1.5, - Complex = Basic * 2, - Massive = Basic * 4, -} diff --git a/packages/angular_devkit/build_ng_packagr/src/build/index_spec_large.ts b/packages/angular_devkit/build_ng_packagr/src/build/index_spec_large.ts index 5913061465..62db4a7389 100644 --- a/packages/angular_devkit/build_ng_packagr/src/build/index_spec_large.ts +++ b/packages/angular_devkit/build_ng_packagr/src/build/index_spec_large.ts @@ -6,10 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import { Architect, TargetSpecifier } from '@angular-devkit/architect'; -import { experimental, join, normalize } from '@angular-devkit/core'; -import { NodeJsSyncHost } from '@angular-devkit/core/node'; -import { concatMap, tap } from 'rxjs/operators'; +import { TargetSpecifier } from '@angular-devkit/architect'; +import { TestProjectHost, runTargetSpec } from '@angular-devkit/architect/testing'; +import { join, normalize } from '@angular-devkit/core'; +import { tap } from 'rxjs/operators'; // TODO: replace this with an "it()" macro that's reusable globally. @@ -18,45 +18,37 @@ if (process.platform.startsWith('win')) { linuxOnlyIt = xit; } +const devkitRoot = normalize((global as any)._DevKitRoot); // tslint:disable-line:no-any +const workspaceRoot = join(devkitRoot, 'tests/@angular_devkit/build_ng_packagr/ng-packaged/'); +export const host = new TestProjectHost(workspaceRoot); -describe('NgPackagr Builder', () => { - const workspaceFile = normalize('angular.json'); - const devkitRoot = normalize((global as any)._DevKitRoot); // tslint:disable-line:no-any - const workspaceRoot = join(devkitRoot, - 'tests/@angular_devkit/build_ng_packagr/ng-packaged/'); - - // TODO: move TestProjectHost from build-angular to architect, or somewhere else, where it - // can be imported from. - const host = new NodeJsSyncHost(); - const workspace = new experimental.workspace.Workspace(workspaceRoot, host); +export enum Timeout { + Basic = 30000, + Standard = Basic * 1.5, +} +describe('NgPackagr Builder', () => { linuxOnlyIt('works', (done) => { const targetSpec: TargetSpecifier = { project: 'lib', target: 'build' }; - return workspace.loadWorkspaceFromHost(workspaceFile).pipe( - concatMap(ws => new Architect(ws).loadArchitect()), - concatMap(arch => arch.run(arch.getBuilderConfiguration(targetSpec))), + runTargetSpec(workspaceRoot, host, targetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); - }, 30000); + }, Timeout.Basic); linuxOnlyIt('tests works', (done) => { const targetSpec: TargetSpecifier = { project: 'lib', target: 'test' }; - return workspace.loadWorkspaceFromHost(workspaceFile).pipe( - concatMap(ws => new Architect(ws).loadArchitect()), - concatMap(arch => arch.run(arch.getBuilderConfiguration(targetSpec))), + runTargetSpec(workspaceRoot, host, targetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); - }, 45000); + }, Timeout.Standard); it('lint works', (done) => { const targetSpec: TargetSpecifier = { project: 'lib', target: 'lint' }; - return workspace.loadWorkspaceFromHost(workspaceFile).pipe( - concatMap(ws => new Architect(ws).loadArchitect()), - concatMap(arch => arch.run(arch.getBuilderConfiguration(targetSpec))), + runTargetSpec(workspaceRoot, host, targetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); - }, 30000); + }, Timeout.Basic); }); diff --git a/packages/angular_devkit/build_webpack/src/test-utils.ts b/packages/angular_devkit/build_webpack/src/test-utils.ts new file mode 100644 index 0000000000..e7b1ac3371 --- /dev/null +++ b/packages/angular_devkit/build_webpack/src/test-utils.ts @@ -0,0 +1,15 @@ +/** + * @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 { TestProjectHost } from '@angular-devkit/architect/testing'; +import { join, normalize } from '@angular-devkit/core'; + + +const devkitRoot = normalize((global as any)._DevKitRoot); // tslint:disable-line:no-any +export const workspaceRoot = join(devkitRoot, 'tests/@angular_devkit/build_webpack/webpack-app/'); +export const host = new TestProjectHost(workspaceRoot); diff --git a/packages/angular_devkit/build_webpack/test/webpack-dev-server/works_spec_large.ts b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index_spec_large.ts similarity index 81% rename from packages/angular_devkit/build_webpack/test/webpack-dev-server/works_spec_large.ts rename to packages/angular_devkit/build_webpack/src/webpack-dev-server/index_spec_large.ts index 41873f7948..fca1849193 100644 --- a/packages/angular_devkit/build_webpack/test/webpack-dev-server/works_spec_large.ts +++ b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; -import { host, request, runTargetSpec } from '../utils'; +import { host, workspaceRoot } from '../test-utils'; describe('Dev Server Builder', () => { @@ -18,7 +19,7 @@ describe('Dev Server Builder', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(host, webpackTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, webpackTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:8080/bundle.js'))), tap(response => expect(response).toContain(`console.log('hello world')`)), diff --git a/packages/angular_devkit/build_webpack/test/webpack/works_spec_large.ts b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts similarity index 82% rename from packages/angular_devkit/build_webpack/test/webpack/works_spec_large.ts rename to packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts index 70fd914340..e085b3a681 100644 --- a/packages/angular_devkit/build_webpack/test/webpack/works_spec_large.ts +++ b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { host, runTargetSpec } from '../utils'; +import { host, workspaceRoot } from '../test-utils'; describe('Webpack Builder basic test', () => { @@ -19,7 +20,7 @@ describe('Webpack Builder basic test', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(host, webpackTargetSpec).pipe( + runTargetSpec(workspaceRoot, host, webpackTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(join(outputPath, 'bundle.js'))).toBe(true); diff --git a/packages/angular_devkit/build_webpack/test/utils/index.ts b/packages/angular_devkit/build_webpack/test/utils/index.ts deleted file mode 100644 index cc36609570..0000000000 --- a/packages/angular_devkit/build_webpack/test/utils/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// TODO: move these into @angular-devkit/architect/test -export * from './request'; -export * from './test-project-host'; -export * from './test-logger'; -export * from './run-target-spec'; diff --git a/packages/angular_devkit/build_webpack/test/utils/request.ts b/packages/angular_devkit/build_webpack/test/utils/request.ts deleted file mode 100644 index 6e3450a63b..0000000000 --- a/packages/angular_devkit/build_webpack/test/utils/request.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as http from 'http'; -import * as https from 'https'; -import * as Url from 'url'; - -export function request(url: string, headers = {}): Promise { - return new Promise((resolve, reject) => { - const u = Url.parse(url); - const options: http.RequestOptions = { - hostname: u.hostname, - protocol: u.protocol, - host: u.host, - port: u.port, - path: u.path, - headers: { 'Accept': 'text/html', ...headers }, - }; - - function _callback(res: http.IncomingMessage) { - if (!res.statusCode || res.statusCode >= 400) { - // Consume the rest of the data to free memory. - res.resume(); - reject(new Error(`Requesting "${url}" returned status code ${res.statusCode}.`)); - } else { - res.setEncoding('utf8'); - let data = ''; - res.on('data', chunk => { - data += chunk; - }); - res.on('end', () => { - try { - resolve(data); - } catch (err) { - reject(err); - } - }); - } - } - - if (u.protocol == 'https:') { - options.agent = new https.Agent({ rejectUnauthorized: false }); - https.get(options, _callback); - } else if (u.protocol == 'http:') { - http.get(options, _callback); - } else { - throw new Error(`Unknown protocol: ${JSON.stringify(u.protocol)}.`); - } - }); -} diff --git a/packages/angular_devkit/build_webpack/test/utils/test-logger.ts b/packages/angular_devkit/build_webpack/test/utils/test-logger.ts deleted file mode 100644 index cda17fad25..0000000000 --- a/packages/angular_devkit/build_webpack/test/utils/test-logger.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { logging } from '@angular-devkit/core'; - - -export class TestLogger extends logging.Logger { - private _latestEntries: logging.LogEntry[] = []; - constructor(name: string, parent: logging.Logger | null = null) { - super(name, parent); - this.subscribe((entry) => this._latestEntries.push(entry)); - } - - clear() { - this._latestEntries = []; - } - - includes(message: string) { - return this._latestEntries.some((entry) => entry.message.includes(message)); - } - - test(re: RegExp) { - return this._latestEntries.some((entry) => re.test(entry.message)); - } -} diff --git a/packages/angular_devkit/build_webpack/test/utils/test-project-host.ts b/packages/angular_devkit/build_webpack/test/utils/test-project-host.ts deleted file mode 100644 index 87a84704ed..0000000000 --- a/packages/angular_devkit/build_webpack/test/utils/test-project-host.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { - Path, - getSystemPath, - normalize, - virtualFs, -} from '@angular-devkit/core'; -import { NodeJsSyncHost } from '@angular-devkit/core/node'; -import { SpawnOptions, spawn } from 'child_process'; -import { Stats } from 'fs'; -import { EMPTY, Observable } from 'rxjs'; -import { concatMap, map } from 'rxjs/operators'; - - -interface ProcessOutput { - stdout: string; - stderr: string; -} - -export class TestProjectHost extends NodeJsSyncHost { - private _scopedSyncHost: virtualFs.SyncDelegateHost; - - constructor(protected _root: Path) { - super(); - this._scopedSyncHost = new virtualFs.SyncDelegateHost(new virtualFs.ScopedHost(this, _root)); - } - - scopedSync() { - return this._scopedSyncHost; - } - - initialize(): Observable { - return this.exists(normalize('.git')).pipe( - concatMap(exists => !exists ? this._gitInit() : EMPTY), - ); - } - - restore(): Observable { - return this._gitClean(); - } - - private _gitClean(): Observable { - return this._exec('git', ['clean', '-fd']).pipe( - concatMap(() => this._exec('git', ['checkout', '.'])), - map(() => { }), - ); - } - - private _gitInit(): Observable { - return this._exec('git', ['init']).pipe( - concatMap(() => this._exec('git', ['config', 'user.email', 'angular-core+e2e@google.com'])), - concatMap(() => this._exec('git', ['config', 'user.name', 'Angular DevKit Tests'])), - concatMap(() => this._exec('git', ['add', '--all'])), - concatMap(() => this._exec('git', ['commit', '-am', '"Initial commit"'])), - map(() => { }), - ); - } - - private _exec(cmd: string, args: string[]): Observable { - return new Observable(obs => { - args = args.filter(x => x !== undefined); - let stdout = ''; - let stderr = ''; - - const spawnOptions: SpawnOptions = { cwd: getSystemPath(this._root) }; - - if (process.platform.startsWith('win')) { - args.unshift('/c', cmd); - cmd = 'cmd.exe'; - spawnOptions['stdio'] = 'pipe'; - } - - const childProcess = spawn(cmd, args, spawnOptions); - childProcess.stdout.on('data', (data: Buffer) => stdout += data.toString('utf-8')); - childProcess.stderr.on('data', (data: Buffer) => stderr += data.toString('utf-8')); - - // Create the error here so the stack shows who called this function. - const err = new Error(`Running "${cmd} ${args.join(' ')}" returned error code `); - - childProcess.on('exit', (code) => { - if (!code) { - obs.next({ stdout, stderr }); - } else { - err.message += `${code}.\n\nSTDOUT:\n${stdout}\n\nSTDERR:\n${stderr}\n`; - obs.error(err); - } - obs.complete(); - }); - }); - } - - writeMultipleFiles(files: { [path: string]: string | ArrayBufferLike | Buffer }): void { - Object.keys(files).map(fileName => { - let content = files[fileName]; - if (typeof content == 'string') { - content = virtualFs.stringToFileBuffer(content); - } else if (content instanceof Buffer) { - content = content.buffer.slice( - content.byteOffset, - content.byteOffset + content.byteLength, - ); - } - - this.scopedSync().write( - normalize(fileName), - content, - ); - }); - } - - replaceInFile(path: string, match: RegExp | string, replacement: string) { - const content = virtualFs.fileBufferToString(this.scopedSync().read(normalize(path))); - this.scopedSync().write(normalize(path), - virtualFs.stringToFileBuffer(content.replace(match, replacement))); - } - - appendToFile(path: string, str: string) { - const content = virtualFs.fileBufferToString(this.scopedSync().read(normalize(path))); - this.scopedSync().write(normalize(path), - virtualFs.stringToFileBuffer(content.concat(str))); - } - - fileMatchExists(dir: string, regex: RegExp) { - const [fileName] = this.scopedSync().list(normalize(dir)).filter(name => name.match(regex)); - - return fileName || undefined; - } - - copyFile(from: string, to: string) { - const content = this.scopedSync().read(normalize(from)); - this.scopedSync().write(normalize(to), content); - } -} diff --git a/tests/@angular_devkit/build_angular/hello-world-app/.angular.json b/tests/@angular_devkit/build_angular/hello-world-app/angular.json similarity index 100% rename from tests/@angular_devkit/build_angular/hello-world-app/.angular.json rename to tests/@angular_devkit/build_angular/hello-world-app/angular.json diff --git a/tsconfig.json b/tsconfig.json index cfcdce05f5..bf96b492b4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -46,6 +46,7 @@ "@angular-devkit/schematics/testing": [ "./packages/angular_devkit/schematics/testing/index" ], "@angular-devkit/build-optimizer": [ "./packages/angular_devkit/build_optimizer/src/index" ], "@angular-devkit/architect": [ "./packages/angular_devkit/architect/src/index" ], + "@angular-devkit/architect/testing": [ "./packages/angular_devkit/architect/testing/index" ], "@ngtools/webpack": [ "./packages/ngtools/webpack/src/index" ], "@ngtools/webpack/*": [ "./packages/ngtools/webpack/*" ], "@schematics/angular": [ "./packages/schematics/angular/index" ] From f1cfbf6db081e1aace524898807a50ff80f588dd Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Fri, 11 May 2018 16:15:13 +0100 Subject: [PATCH 3/9] refactor(@angular-devkit/build-angular): use devkit/build-webpack --- package.json | 1 - .../angular_devkit/build_angular/package.json | 2 +- .../models/webpack-configs/common.ts | 4 + .../models/webpack-configs/index.ts | 1 + .../models/webpack-configs/stats.ts | 48 +++++++ .../models/webpack-configs/utils.ts | 33 ----- .../build_angular/src/browser/index.ts | 124 +++++++----------- .../build_angular/src/dev-server/index.ts | 123 +++++------------ .../build_angular/src/extract-i18n/index.ts | 66 +++++----- .../build_angular/src/server/index.ts | 54 ++------ .../build_angular/src/server/schema.d.ts | 2 +- .../test/browser/service-worker_spec_large.ts | 2 +- .../src/webpack-dev-server/index.ts | 26 +++- .../build_webpack/src/webpack/index.ts | 29 ++-- tsconfig.json | 1 + 15 files changed, 216 insertions(+), 300 deletions(-) create mode 100644 packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/stats.ts diff --git a/package.json b/package.json index f17202cb4b..0e5b25ded2 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,6 @@ "loader-utils": "^1.1.0", "lodash": "^4.17.4", "material-design-icons": "^3.0.1", - "memory-fs": "^0.4.1", "mini-css-extract-plugin": "~0.4.0", "minimatch": "^3.0.4", "minimist": "^1.2.0", diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index 363bcad652..88006680c9 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -11,6 +11,7 @@ "dependencies": { "@angular-devkit/architect": "0.0.0", "@angular-devkit/build-optimizer": "0.0.0", + "@angular-devkit/build-webpack": "0.0.0", "@angular-devkit/core": "0.0.0", "@ngtools/webpack": "0.0.0", "ajv": "~6.4.0", @@ -30,7 +31,6 @@ "less-loader": "^4.1.0", "license-webpack-plugin": "^1.3.1", "lodash": "^4.17.4", - "memory-fs": "^0.4.1", "mini-css-extract-plugin": "~0.4.0", "minimatch": "^3.0.4", "parse5": "^4.0.0", diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts index 76b4709277..dbfe542b03 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts @@ -255,6 +255,10 @@ export function getCommonConfig(wco: WebpackConfigOptions) { publicPath: buildOptions.deployUrl, filename: `[name]${hashFormat.chunk}.js`, }, + watch: buildOptions.watch, + watchOptions: { + poll: buildOptions.poll + }, performance: { hints: false, }, diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/index.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/index.ts index 54ed2cb9ab..bbcc83372f 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/index.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/index.ts @@ -15,3 +15,4 @@ export * from './styles'; export * from './test'; export * from './typescript'; export * from './utils'; +export * from './stats'; diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/stats.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/stats.ts new file mode 100644 index 0000000000..5e3d46953d --- /dev/null +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/stats.ts @@ -0,0 +1,48 @@ +/** + * @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'; + +const webpackOutputOptions = { + colors: true, + hash: true, // required by custom stat output + timings: true, // required by custom stat output + chunks: true, // required by custom stat output + chunkModules: false, + children: false, // listing all children is very noisy in AOT and hides warnings/errors + modules: false, + reasons: false, + warnings: true, + errors: true, + assets: true, // required by custom stat output + version: false, + errorDetails: false, + moduleTrace: false, +}; + +const verboseWebpackOutputOptions = { + children: true, + assets: true, + version: true, + reasons: true, + chunkModules: false, // TODO: set to true when console to file output is fixed + errorDetails: true, + moduleTrace: true, +}; + +export function getWebpackStatsConfig(verbose = false) { + return verbose + ? Object.assign(webpackOutputOptions, verboseWebpackOutputOptions) + : webpackOutputOptions; +} + +export function getStatsConfig(wco: WebpackConfigOptions) { + const verbose = !!wco.buildOptions.verbose; + + return { stats: getWebpackStatsConfig(verbose) }; +} diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/utils.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/utils.ts index 3bd7e39779..f32f3f8afa 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/utils.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/utils.ts @@ -16,39 +16,6 @@ export const ngAppResolve = (resolvePath: string): string => { return path.resolve(process.cwd(), resolvePath); }; -const webpackOutputOptions = { - colors: true, - hash: true, // required by custom stat output - timings: true, // required by custom stat output - chunks: true, // required by custom stat output - chunkModules: false, - children: false, // listing all children is very noisy in AOT and hides warnings/errors - modules: false, - reasons: false, - warnings: true, - errors: true, - assets: true, // required by custom stat output - version: false, - errorDetails: false, - moduleTrace: false, -}; - -const verboseWebpackOutputOptions = { - children: true, - assets: true, - version: true, - reasons: true, - chunkModules: false, // TODO: set to true when console to file output is fixed - errorDetails: true, - moduleTrace: true, -}; - -export function getWebpackStatsConfig(verbose = false) { - return verbose - ? Object.assign(webpackOutputOptions, verboseWebpackOutputOptions) - : webpackOutputOptions; -} - export interface HashFormat { chunk: string; extract: string; diff --git a/packages/angular_devkit/build_angular/src/browser/index.ts b/packages/angular_devkit/build_angular/src/browser/index.ts index d43fecc4dd..8f991ddc55 100644 --- a/packages/angular_devkit/build_angular/src/browser/index.ts +++ b/packages/angular_devkit/build_angular/src/browser/index.ts @@ -11,21 +11,21 @@ import { BuilderConfiguration, BuilderContext, } from '@angular-devkit/architect'; +import { LoggingCb, WebpackBuilder } from '@angular-devkit/build-webpack'; import { Path, getSystemPath, normalize, resolve, virtualFs } from '@angular-devkit/core'; import * as fs from 'fs'; -import { Observable, concat, of } from 'rxjs'; +import { Observable, concat, of, throwError } from 'rxjs'; import { concatMap, last, tap } from 'rxjs/operators'; import * as ts from 'typescript'; // tslint:disable-line:no-implicit-dependencies -import * as webpack from 'webpack'; import { WebpackConfigOptions } from '../angular-cli-files/models/build-options'; import { getAotConfig, getBrowserConfig, getCommonConfig, getNonAotConfig, + getStatsConfig, getStylesConfig, } from '../angular-cli-files/models/webpack-configs'; -import { getWebpackStatsConfig } from '../angular-cli-files/models/webpack-configs/utils'; import { readTsconfig } from '../angular-cli-files/utilities/read-tsconfig'; import { requireProjectModule } from '../angular-cli-files/utilities/require-project-module'; import { augmentAppWithServiceWorker } from '../angular-cli-files/utilities/service-worker'; @@ -58,6 +58,7 @@ export class BrowserBuilder implements Builder { const root = this.context.workspace.root; const projectRoot = resolve(root, builderConfig.root); const host = new virtualFs.AliasHost(this.context.host as virtualFs.Host); + const webpackBuilder = new WebpackBuilder({ ...this.context, host }); return of(null).pipe( concatMap(() => options.deleteOutputPath @@ -68,7 +69,7 @@ export class BrowserBuilder implements Builder { options.assets, host, root, projectRoot, builderConfig.sourceRoot)), // Replace the assets in options with the normalized version. tap((assetPatternObjects => options.assets = assetPatternObjects)), - concatMap(() => new Observable(obs => { + concatMap(() => { // Ensure Build Optimizer is only used with AOT. if (options.buildOptimizer && !options.aot) { throw new Error('The `--build-optimizer` option cannot be used without `--aot`.'); @@ -79,80 +80,35 @@ export class BrowserBuilder implements Builder { webpackConfig = this.buildWebpackConfig(root, projectRoot, host, options as NormalizedBrowserBuilderSchema); } catch (e) { - obs.error(e); - - return; + return throwError(e); } - const webpackCompiler = webpack(webpackConfig); - const statsConfig = getWebpackStatsConfig(options.verbose); - - const callback: webpack.compiler.CompilerCallback = (err, stats) => { - if (err) { - return obs.error(err); - } - - const json = stats.toJson(statsConfig); - if (options.verbose) { - this.context.logger.info(stats.toString(statsConfig)); - } else { - this.context.logger.info(statsToString(json, statsConfig)); - } - - if (stats.hasWarnings()) { - this.context.logger.warn(statsWarningsToString(json, statsConfig)); - } - if (stats.hasErrors()) { - this.context.logger.error(statsErrorsToString(json, statsConfig)); - } - - if (options.watch) { - obs.next({ success: !stats.hasErrors() }); - - // Never complete on watch mode. - return; - } else { - if (builderConfig.options.serviceWorker) { - augmentAppWithServiceWorker( - this.context.host, - root, - projectRoot, - resolve(root, normalize(options.outputPath)), - options.baseHref || '/', - options.ngswConfigPath, - ).then( - () => { - obs.next({ success: !stats.hasErrors() }); - obs.complete(); - }, - (err: Error) => { - // We error out here because we're not in watch mode anyway (see above). - obs.error(err); - }, - ); - } else { - obs.next({ success: !stats.hasErrors() }); - obs.complete(); - } - } - }; - try { - if (options.watch) { - const watching = webpackCompiler.watch({ poll: options.poll }, callback); - - // Teardown logic. Close the watcher when unsubscribed from. - return () => watching.close(() => { }); - } else { - webpackCompiler.run(callback); - } - } catch (err) { - if (err) { - this.context.logger.error( - '\nAn error occured during the build:\n' + ((err && err.stack) || err)); - } - throw err; + return webpackBuilder.runWebpack(webpackConfig, getBrowserLoggingCb(options.verbose)); + }), + concatMap(buildEvent => { + if (buildEvent.success && !options.watch && options.serviceWorker) { + return new Observable(obs => { + augmentAppWithServiceWorker( + this.context.host, + root, + projectRoot, + resolve(root, normalize(options.outputPath)), + options.baseHref || '/', + options.ngswConfigPath, + ).then( + () => { + obs.next({ success: true }); + obs.complete(); + }, + (err: Error) => { + obs.error(err); + }, + ); + }); + } else { + return of(buildEvent); } - })), + }), ); } @@ -185,6 +141,7 @@ export class BrowserBuilder implements Builder { getCommonConfig(wco), getBrowserConfig(wco), getStylesConfig(wco), + getStatsConfig(wco), ]; if (wco.buildOptions.main || wco.buildOptions.polyfills) { @@ -213,4 +170,21 @@ export class BrowserBuilder implements Builder { } } +export const getBrowserLoggingCb = (verbose: boolean): LoggingCb => (stats, config, logger) => { + // 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(statsToString(json, config.stats)); + } + + if (stats.hasWarnings()) { + logger.warn(statsWarningsToString(json, config.stats)); + } + if (stats.hasErrors()) { + logger.error(statsErrorsToString(json, config.stats)); + } +}; + export default BrowserBuilder; diff --git a/packages/angular_devkit/build_angular/src/dev-server/index.ts b/packages/angular_devkit/build_angular/src/dev-server/index.ts index 09d19da281..b23214496e 100644 --- a/packages/angular_devkit/build_angular/src/dev-server/index.ts +++ b/packages/angular_devkit/build_angular/src/dev-server/index.ts @@ -12,26 +12,21 @@ import { BuilderConfiguration, BuilderContext, } from '@angular-devkit/architect'; +import { WebpackDevServerBuilder } from '@angular-devkit/build-webpack'; import { Path, getSystemPath, resolve, tags, virtualFs } from '@angular-devkit/core'; import { existsSync, readFileSync } from 'fs'; import * as fs from 'fs'; import * as path from 'path'; -import { Observable } from 'rxjs'; +import { Observable, throwError } from 'rxjs'; import { concatMap, map, tap } from 'rxjs/operators'; import * as url from 'url'; import * as webpack from 'webpack'; -import { getWebpackStatsConfig } from '../angular-cli-files/models/webpack-configs/utils'; +import * as WebpackDevServer from 'webpack-dev-server'; import { checkPort } from '../angular-cli-files/utilities/check-port'; -import { - statsErrorsToString, - statsToString, - statsWarningsToString, -} from '../angular-cli-files/utilities/stats'; -import { BrowserBuilder, NormalizedBrowserBuilderSchema } from '../browser/'; +import { BrowserBuilder, NormalizedBrowserBuilderSchema, getBrowserLoggingCb } from '../browser/'; import { BrowserBuilderSchema } from '../browser/schema'; import { addFileReplacements, normalizeAssetPatterns } from '../utils'; const opn = require('opn'); -const WebpackDevServer = require('webpack-dev-server'); export interface DevServerBuilderOptions { @@ -64,31 +59,6 @@ export interface DevServerBuilderOptions { poll?: number; } -interface WebpackDevServerConfigurationOptions { - contentBase?: boolean | string | string[]; - hot?: boolean; - historyApiFallback?: { [key: string]: any } | boolean; // tslint:disable-line:no-any - compress?: boolean; - proxy?: { [key: string]: string }; - staticOptions?: any; // tslint:disable-line:no-any - quiet?: boolean; - noInfo?: boolean; - lazy?: boolean; - filename?: string; - watchOptions?: { - aggregateTimeout?: number; - poll?: number; - }; - publicPath?: string; - headers?: { [key: string]: string }; - stats?: { [key: string]: boolean } | string | boolean; - https?: boolean; - key?: string; - cert?: string; - overlay?: boolean | { errors: boolean, warnings: boolean }; - public?: string; - disableHostCheck?: boolean; -} export class DevServerBuilder implements Builder { @@ -99,7 +69,10 @@ export class DevServerBuilder implements Builder { const root = this.context.workspace.root; const projectRoot = resolve(root, builderConfig.root); const host = new virtualFs.AliasHost(this.context.host as virtualFs.Host); + const webpackDevServerBuilder = new WebpackDevServerBuilder({ ...this.context, host }); let browserOptions: BrowserBuilderSchema; + let first = true; + let opnAddress: string; return checkPort(options.port, options.host).pipe( tap((port) => options.port = port), @@ -110,20 +83,17 @@ export class DevServerBuilder implements Builder { browserOptions.assets, host, root, projectRoot, builderConfig.sourceRoot)), // Replace the assets in options with the normalized version. tap((assetPatternObjects => browserOptions.assets = assetPatternObjects)), - concatMap(() => new Observable(obs => { + concatMap(() => { const browserBuilder = new BrowserBuilder(this.context); const webpackConfig = browserBuilder.buildWebpackConfig( root, projectRoot, host, browserOptions as NormalizedBrowserBuilderSchema); - const statsConfig = getWebpackStatsConfig(browserOptions.verbose); - let webpackDevServerConfig: WebpackDevServerConfigurationOptions; + let webpackDevServerConfig: WebpackDevServer.Configuration; try { webpackDevServerConfig = this._buildServerConfig( root, projectRoot, options, browserOptions); } catch (err) { - obs.error(err); - - return; + return throwError(err); } // Resolve public host and client address. @@ -183,54 +153,22 @@ export class DevServerBuilder implements Builder { ** `); - const webpackCompiler = webpack(webpackConfig); - const server = new WebpackDevServer(webpackCompiler, webpackDevServerConfig); - - let first = true; - // tslint:disable-next-line:no-any - (webpackCompiler as any).hooks.done.tap('angular-cli', (stats: webpack.Stats) => { - if (!browserOptions.verbose) { - const json = stats.toJson(statsConfig); - this.context.logger.info(statsToString(json, statsConfig)); - if (stats.hasWarnings()) { - this.context.logger.info(statsWarningsToString(json, statsConfig)); - } - if (stats.hasErrors()) { - this.context.logger.info(statsErrorsToString(json, statsConfig)); - } - } - obs.next({ success: !stats.hasErrors() }); + opnAddress = serverAddress + webpackDevServerConfig.publicPath; + webpackConfig.devServer = webpackDevServerConfig; - if (first && options.open) { - first = false; - opn(serverAddress + webpackDevServerConfig.publicPath); - } - }); - - const httpServer = server.listen( - options.port, - options.host, - (err: any) => { // tslint:disable-line:no-any - if (err) { - obs.error(err); - } - }, + return webpackDevServerBuilder.runWebpackDevServer( + webpackConfig, undefined, getBrowserLoggingCb(browserOptions.verbose), ); - - // Node 8 has a keepAliveTimeout bug which doesn't respect active connections. - // Connections will end after ~5 seconds (arbitrary), often not letting the full download - // of large pieces of content, such as a vendor javascript file. This results in browsers - // throwing a "net::ERR_CONTENT_LENGTH_MISMATCH" error. - // https://github.com/angular/angular-cli/issues/7197 - // https://github.com/nodejs/node/issues/13391 - // https://github.com/nodejs/node/commit/2cb6f2b281eb96a7abe16d58af6ebc9ce23d2e96 - if (/^v8.\d.\d+$/.test(process.version)) { - httpServer.keepAliveTimeout = 30000; // 30 seconds + }), + map(buildEvent => { + if (first && options.open) { + first = false; + opn(opnAddress); } - // Teardown logic. Close the server when unsubscribed from. - return () => server.close(); - }))); + return buildEvent; + }), + ); } private _buildServerConfig( @@ -250,14 +188,16 @@ export class DevServerBuilder implements Builder { const servePath = this._buildServePath(options, browserOptions); - const config: WebpackDevServerConfigurationOptions = { + const config: WebpackDevServer.Configuration = { + host: options.host, + port: options.port, headers: { 'Access-Control-Allow-Origin': '*' }, historyApiFallback: { index: `${servePath}/${path.basename(browserOptions.index)}`, disableDotRule: true, htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'], }, - stats: browserOptions.verbose ? getWebpackStatsConfig(browserOptions.verbose) : false, + stats: false, compress: browserOptions.optimization, watchOptions: { poll: browserOptions.poll, @@ -267,7 +207,6 @@ export class DevServerBuilder implements Builder { errors: !browserOptions.optimization, warnings: false, }, - contentBase: false, public: options.publicHost, disableHostCheck: options.disableHostCheck, publicPath: servePath, @@ -334,7 +273,7 @@ export class DevServerBuilder implements Builder { private _addSslConfig( root: string, options: DevServerBuilderOptions, - config: WebpackDevServerConfigurationOptions, + config: WebpackDevServer.Configuration, ) { let sslKey: string | undefined = undefined; let sslCert: string | undefined = undefined; @@ -353,15 +292,17 @@ export class DevServerBuilder implements Builder { config.https = true; if (sslKey != null && sslCert != null) { - config.key = sslKey; - config.cert = sslCert; + config.https = { + key: sslKey, + cert: sslCert, + }; } } private _addProxyConfig( root: string, options: DevServerBuilderOptions, - config: WebpackDevServerConfigurationOptions, + config: WebpackDevServer.Configuration, ) { let proxyConfig = {}; const proxyPath = path.resolve(root, options.proxyConfig as string); diff --git a/packages/angular_devkit/build_angular/src/extract-i18n/index.ts b/packages/angular_devkit/build_angular/src/extract-i18n/index.ts index 9a8fd2a3c1..ac7fc9c854 100644 --- a/packages/angular_devkit/build_angular/src/extract-i18n/index.ts +++ b/packages/angular_devkit/build_angular/src/extract-i18n/index.ts @@ -11,6 +11,7 @@ import { BuilderConfiguration, BuilderContext, } from '@angular-devkit/architect'; +import { LoggingCb, WebpackBuilder } from '@angular-devkit/build-webpack'; import { Path, getSystemPath, normalize, resolve, virtualFs } from '@angular-devkit/core'; import * as fs from 'fs'; import * as path from 'path'; @@ -21,14 +22,13 @@ import { WebpackConfigOptions } from '../angular-cli-files/models/build-options' import { getAotConfig, getCommonConfig, + getStatsConfig, getStylesConfig, } from '../angular-cli-files/models/webpack-configs'; -import { getWebpackStatsConfig } from '../angular-cli-files/models/webpack-configs/utils'; import { readTsconfig } from '../angular-cli-files/utilities/read-tsconfig'; import { statsErrorsToString, statsWarningsToString } from '../angular-cli-files/utilities/stats'; import { NormalizedBrowserBuilderSchema } from '../browser'; import { BrowserBuilderSchema } from '../browser/schema'; -const MemoryFS = require('memory-fs'); const webpackMerge = require('webpack-merge'); @@ -56,12 +56,24 @@ export class ExtractI18nBuilder implements Builder { const browserTargetSpec = { project, target: targetName, configuration, overrides }; const browserBuilderConfig = architect.getBuilderConfiguration( browserTargetSpec); + const webpackBuilder = new WebpackBuilder(this.context); + + const loggingCb: LoggingCb = (stats, config, logger) => { + const json = stats.toJson(); + if (stats.hasWarnings()) { + this.context.logger.warn(statsWarningsToString(json, config.stats)); + } + + if (stats.hasErrors()) { + this.context.logger.error(statsErrorsToString(json, config.stats)); + } + }; return architect.getBuilderDescription(browserBuilderConfig).pipe( concatMap(browserDescription => architect.validateBuilderOptions(browserBuilderConfig, browserDescription)), map(browserBuilderConfig => browserBuilderConfig.options), - concatMap((validatedBrowserOptions) => new Observable(obs => { + concatMap((validatedBrowserOptions) => { const browserOptions = validatedBrowserOptions; // We need to determine the outFile name so that AngularCompiler can retrieve it. @@ -84,39 +96,8 @@ export class ExtractI18nBuilder implements Builder { styles: [], }); - const webpackCompiler = webpack(webpackConfig); - webpackCompiler.outputFileSystem = new MemoryFS(); - const statsConfig = getWebpackStatsConfig(); - - const callback: webpack.compiler.CompilerCallback = (err, stats) => { - if (err) { - return obs.error(err); - } - - const json = stats.toJson('verbose'); - if (stats.hasWarnings()) { - this.context.logger.warn(statsWarningsToString(json, statsConfig)); - } - - if (stats.hasErrors()) { - this.context.logger.error(statsErrorsToString(json, statsConfig)); - } - - obs.next({ success: !stats.hasErrors() }); - - obs.complete(); - }; - - try { - webpackCompiler.run(callback); - } catch (err) { - if (err) { - this.context.logger.error( - '\nAn error occured during the extraction:\n' + ((err && err.stack) || err)); - } - throw err; - } - })), + return webpackBuilder.runWebpack(webpackConfig, loggingCb); + }), ); } @@ -143,9 +124,12 @@ export class ExtractI18nBuilder implements Builder { }; const webpackConfigs: {}[] = [ + // We don't need to write to disk. + { plugins: [new InMemoryOutputPlugin()] }, getCommonConfig(wco), getAotConfig(wco, host, true), getStylesConfig(wco), + getStatsConfig(wco), ]; return webpackMerge(webpackConfigs); @@ -167,4 +151,14 @@ function getI18nOutfile(format: string) { } } +export class InMemoryOutputPlugin { + constructor() { } + + apply(compiler: webpack.Compiler): void { + // tslint:disable-next-line:no-any + compiler.outputFileSystem = new (webpack as any).MemoryOutputFileSystem(); + } + +} + export default ExtractI18nBuilder; diff --git a/packages/angular_devkit/build_angular/src/server/index.ts b/packages/angular_devkit/build_angular/src/server/index.ts index 5c56717e91..b70f6715f8 100644 --- a/packages/angular_devkit/build_angular/src/server/index.ts +++ b/packages/angular_devkit/build_angular/src/server/index.ts @@ -12,28 +12,24 @@ import { BuilderConfiguration, BuilderContext, } from '@angular-devkit/architect'; +import { WebpackBuilder } from '@angular-devkit/build-webpack'; import { Path, getSystemPath, normalize, resolve, virtualFs } from '@angular-devkit/core'; import { Stats } from 'fs'; import { Observable, concat, of } from 'rxjs'; import { concatMap, last } from 'rxjs/operators'; import * as ts from 'typescript'; // tslint:disable-line:no-implicit-dependencies -import * as webpack from 'webpack'; import { WebpackConfigOptions } from '../angular-cli-files/models/build-options'; import { getAotConfig, getCommonConfig, getNonAotConfig, getServerConfig, + getStatsConfig, getStylesConfig, } from '../angular-cli-files/models/webpack-configs'; -import { getWebpackStatsConfig } from '../angular-cli-files/models/webpack-configs/utils'; import { readTsconfig } from '../angular-cli-files/utilities/read-tsconfig'; import { requireProjectModule } from '../angular-cli-files/utilities/require-project-module'; -import { - statsErrorsToString, - statsToString, - statsWarningsToString, -} from '../angular-cli-files/utilities/stats'; +import { getBrowserLoggingCb } from '../browser'; import { addFileReplacements } from '../utils'; import { BuildWebpackServerSchema } from './schema'; const webpackMerge = require('webpack-merge'); @@ -48,6 +44,7 @@ export class ServerBuilder implements Builder { const root = this.context.workspace.root; const projectRoot = resolve(root, builderConfig.root); const host = new virtualFs.AliasHost(this.context.host as virtualFs.Host); + const webpackBuilder = new WebpackBuilder({ ...this.context, host }); // TODO: verify using of(null) to kickstart things is a pattern. return of(null).pipe( @@ -55,45 +52,11 @@ export class ServerBuilder implements Builder { ? this._deleteOutputDir(root, normalize(options.outputPath), this.context.host) : of(null)), concatMap(() => addFileReplacements(root, host, options.fileReplacements)), - concatMap(() => new Observable(obs => { - // Ensure Build Optimizer is only used with AOT. + concatMap(() => { const webpackConfig = this.buildWebpackConfig(root, projectRoot, host, options); - const webpackCompiler = webpack(webpackConfig); - const statsConfig = getWebpackStatsConfig(options.verbose); - - const callback: webpack.compiler.CompilerCallback = (err, stats) => { - if (err) { - return obs.error(err); - } - - const json = stats.toJson(statsConfig); - if (options.verbose) { - this.context.logger.info(stats.toString(statsConfig)); - } else { - this.context.logger.info(statsToString(json, statsConfig)); - } - - if (stats.hasWarnings()) { - this.context.logger.warn(statsWarningsToString(json, statsConfig)); - } - if (stats.hasErrors()) { - this.context.logger.error(statsErrorsToString(json, statsConfig)); - } - - obs.next({ success: !stats.hasErrors() }); - obs.complete(); - }; - - try { - webpackCompiler.run(callback); - } catch (err) { - if (err) { - this.context.logger.error( - '\nAn error occured during the build:\n' + ((err && err.stack) || err)); - } - throw err; - } - })), + + return webpackBuilder.runWebpack(webpackConfig, getBrowserLoggingCb(options.verbose)); + }), ); } @@ -138,6 +101,7 @@ export class ServerBuilder implements Builder { getCommonConfig(wco), getServerConfig(wco), getStylesConfig(wco), + getStatsConfig(wco), ]; if (wco.buildOptions.main || wco.buildOptions.polyfills) { diff --git a/packages/angular_devkit/build_angular/src/server/schema.d.ts b/packages/angular_devkit/build_angular/src/server/schema.d.ts index 12ec739897..539eab9838 100644 --- a/packages/angular_devkit/build_angular/src/server/schema.d.ts +++ b/packages/angular_devkit/build_angular/src/server/schema.d.ts @@ -17,7 +17,7 @@ export interface BuildWebpackServerSchema { /** * Adds more details to output logging. */ - verbose?: boolean; + verbose: boolean; /** * Use a separate bundle containing code used across multiple bundles. */ diff --git a/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts index a81c8641e0..0eed66f994 100644 --- a/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts @@ -12,7 +12,7 @@ import { tap } from 'rxjs/operators'; import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; -describe('Browser Builder', () => { +describe('Browser Builder service worker', () => { const manifest = { index: '/index.html', assetGroups: [ diff --git a/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts index d70c76a91a..5c73f7e6e6 100644 --- a/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts +++ b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts @@ -16,10 +16,11 @@ import { Path, getSystemPath, normalize, resolve } from '@angular-devkit/core'; import { Observable } from 'rxjs'; import * as webpack from 'webpack'; import * as WebpackDevServer from 'webpack-dev-server'; +import { LoggingCb, defaultLoggingCb } from '../webpack'; import { WebpackDevServerBuilderSchema } from './schema'; -export class DevServerBuilder implements Builder { +export class WebpackDevServerBuilder implements Builder { constructor(public context: BuilderContext) { } @@ -39,13 +40,16 @@ export class DevServerBuilder implements Builder public runWebpackDevServer( webpackConfig: webpack.Configuration, devServerCfg?: WebpackDevServer.Configuration, + loggingCb: LoggingCb = defaultLoggingCb, ): Observable { return new Observable(obs => { const devServerConfig = devServerCfg || webpackConfig.devServer || {}; devServerConfig.host = devServerConfig.host || 'localhost'; devServerConfig.port = devServerConfig.port || 8080; - const statsConfig = devServerConfig.stats || webpackConfig.stats; + if (devServerConfig.stats) { + webpackConfig.stats = devServerConfig.stats; + } // Disable stats reporting by the devserver, we have our own logger. devServerConfig.stats = false; @@ -53,12 +57,13 @@ export class DevServerBuilder implements Builder const server = new WebpackDevServer(webpackCompiler, devServerConfig); webpackCompiler.hooks.done.tap('build-webpack', (stats: webpack.Stats) => { - this.context.logger.info(stats.toString(statsConfig)); + // Log stats. + loggingCb(stats, webpackConfig, this.context.logger); obs.next({ success: !stats.hasErrors() }); }); - server.listen( + const httpServer = server.listen( devServerConfig.port, devServerConfig.host, (err) => { @@ -68,6 +73,17 @@ export class DevServerBuilder implements Builder }, ); + // Node 8 has a keepAliveTimeout bug which doesn't respect active connections. + // Connections will end after ~5 seconds (arbitrary), often not letting the full download + // of large pieces of content, such as a vendor javascript file. This results in browsers + // throwing a "net::ERR_CONTENT_LENGTH_MISMATCH" error. + // https://github.com/angular/angular-cli/issues/7197 + // https://github.com/nodejs/node/issues/13391 + // https://github.com/nodejs/node/commit/2cb6f2b281eb96a7abe16d58af6ebc9ce23d2e96 + if (/^v8.\d.\d+$/.test(process.version)) { + httpServer.keepAliveTimeout = 30000; // 30 seconds + } + // Teardown logic. Close the server when unsubscribed from. return () => server.close(); }); @@ -75,4 +91,4 @@ export class DevServerBuilder implements Builder } -export default DevServerBuilder; +export default WebpackDevServerBuilder; diff --git a/packages/angular_devkit/build_webpack/src/webpack/index.ts b/packages/angular_devkit/build_webpack/src/webpack/index.ts index e12771fe6a..55027804d5 100644 --- a/packages/angular_devkit/build_webpack/src/webpack/index.ts +++ b/packages/angular_devkit/build_webpack/src/webpack/index.ts @@ -11,12 +11,20 @@ import { BuilderConfiguration, BuilderContext, } from '@angular-devkit/architect'; -import { Path, getSystemPath, normalize, resolve } from '@angular-devkit/core'; +import { Path, getSystemPath, logging, normalize, resolve } from '@angular-devkit/core'; import { Observable } from 'rxjs'; import * as webpack from 'webpack'; import { WebpackBuilderSchema } from './schema'; -export class BrowserBuilder implements Builder { + +export interface LoggingCb { + (stats: webpack.Stats, config: webpack.Configuration, logger: logging.Logger): void; +} + +export const defaultLoggingCb: LoggingCb = (stats, config, logger) => + logger.info(stats.toString(config.stats)); + +export class WebpackBuilder implements Builder { constructor(public context: BuilderContext) { } @@ -33,7 +41,9 @@ export class BrowserBuilder implements Builder { return require(webpackConfigPath) as webpack.Configuration; } - public runWebpack(config: webpack.Configuration): Observable { + public runWebpack( + config: webpack.Configuration, loggingCb = defaultLoggingCb, + ): Observable { return new Observable(obs => { const webpackCompiler = webpack(config); @@ -42,15 +52,12 @@ export class BrowserBuilder implements Builder { return obs.error(err); } - this.context.logger.info(stats.toString(config.stats)); + // Log stats. + loggingCb(stats, config, this.context.logger); - if (config.watch) { - obs.next({ success: !stats.hasErrors() }); + obs.next({ success: !stats.hasErrors() }); - // Never complete on watch mode. - return; - } else { - obs.next({ success: !stats.hasErrors() }); + if (!config.watch) { obs.complete(); } }; @@ -76,4 +83,4 @@ export class BrowserBuilder implements Builder { } } -export default BrowserBuilder; +export default WebpackBuilder; diff --git a/tsconfig.json b/tsconfig.json index bf96b492b4..ac88e47f5f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -47,6 +47,7 @@ "@angular-devkit/build-optimizer": [ "./packages/angular_devkit/build_optimizer/src/index" ], "@angular-devkit/architect": [ "./packages/angular_devkit/architect/src/index" ], "@angular-devkit/architect/testing": [ "./packages/angular_devkit/architect/testing/index" ], + "@angular-devkit/build-webpack": [ "./packages/angular_devkit/build_webpack/src/index" ], "@ngtools/webpack": [ "./packages/ngtools/webpack/src/index" ], "@ngtools/webpack/*": [ "./packages/ngtools/webpack/*" ], "@schematics/angular": [ "./packages/schematics/angular/index" ] From fd101a7b8a8a4cce5a668af94dad0e48aa0d8adb Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Mon, 14 May 2018 13:48:59 +0100 Subject: [PATCH 4/9] test: add build-webpack angular app test --- .../build_webpack/src/test-utils.ts | 5 +- .../src/webpack/index_spec_large.ts | 22 +++++- .../{webpack-app => angular-app}/.gitignore | 0 .../{webpack-app => angular-app}/angular.json | 0 .../angular-app/src/app/app.component.css | 0 .../angular-app/src/app/app.component.html | 22 ++++++ .../angular-app/src/app/app.component.spec.ts | 34 +++++++++ .../angular-app/src/app/app.component.ts | 17 +++++ .../angular-app/src/app/app.module.ts | 25 +++++++ .../angular-app/src/app/app.server.module.ts | 21 ++++++ .../angular-app/src/assets/.gitkeep | 0 .../src/environments/environment.prod.ts | 10 +++ .../src/environments/environment.ts | 15 ++++ .../build_webpack/angular-app/src/main.ts | 19 +++++ .../angular-app/src/polyfills.ts | 73 +++++++++++++++++++ .../angular-app/src/src/locale/messages.xlf | 18 +++++ .../build_webpack/angular-app/src/styles.css | 1 + .../angular-app/src/tsconfig.app.json | 12 +++ .../build_webpack/angular-app/tsconfig.json | 20 +++++ .../angular-app/webpack.config.js | 38 ++++++++++ .../build_webpack/basic-app/.gitignore | 42 +++++++++++ .../build_webpack/basic-app/angular.json | 30 ++++++++ .../{webpack-app => basic-app}/src/main.js | 0 .../webpack.config.js | 0 24 files changed, 420 insertions(+), 4 deletions(-) rename tests/@angular_devkit/build_webpack/{webpack-app => angular-app}/.gitignore (100%) rename tests/@angular_devkit/build_webpack/{webpack-app => angular-app}/angular.json (100%) create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.css create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.html create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.spec.ts create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.ts create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/app/app.module.ts create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/app/app.server.module.ts create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/assets/.gitkeep create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/environments/environment.prod.ts create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/environments/environment.ts create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/main.ts create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/polyfills.ts create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/src/locale/messages.xlf create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/styles.css create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/tsconfig.app.json create mode 100644 tests/@angular_devkit/build_webpack/angular-app/tsconfig.json create mode 100644 tests/@angular_devkit/build_webpack/angular-app/webpack.config.js create mode 100644 tests/@angular_devkit/build_webpack/basic-app/.gitignore create mode 100644 tests/@angular_devkit/build_webpack/basic-app/angular.json rename tests/@angular_devkit/build_webpack/{webpack-app => basic-app}/src/main.js (100%) rename tests/@angular_devkit/build_webpack/{webpack-app => basic-app}/webpack.config.js (100%) diff --git a/packages/angular_devkit/build_webpack/src/test-utils.ts b/packages/angular_devkit/build_webpack/src/test-utils.ts index e7b1ac3371..0082101d1c 100644 --- a/packages/angular_devkit/build_webpack/src/test-utils.ts +++ b/packages/angular_devkit/build_webpack/src/test-utils.ts @@ -11,5 +11,8 @@ import { join, normalize } from '@angular-devkit/core'; const devkitRoot = normalize((global as any)._DevKitRoot); // tslint:disable-line:no-any -export const workspaceRoot = join(devkitRoot, 'tests/@angular_devkit/build_webpack/webpack-app/'); +export const basicWorkspaceRoot = join(devkitRoot, + 'tests/@angular_devkit/build_webpack/basic-app/'); +export const basicHost = new TestProjectHost(basicWorkspaceRoot); +export const workspaceRoot = join(devkitRoot, 'tests/@angular_devkit/build_webpack/angular-app/'); export const host = new TestProjectHost(workspaceRoot); diff --git a/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts index e085b3a681..03d842b611 100644 --- a/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts +++ b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { host, workspaceRoot } from '../test-utils'; +import { basicHost, basicWorkspaceRoot, host, workspaceRoot } from '../test-utils'; describe('Webpack Builder basic test', () => { @@ -19,12 +19,28 @@ describe('Webpack Builder basic test', () => { beforeEach(done => host.initialize().subscribe(undefined, done.fail, done)); afterEach(done => host.restore().subscribe(undefined, done.fail, done)); - it('works', (done) => { - runTargetSpec(workspaceRoot, host, webpackTargetSpec).pipe( + it('works with a basic webpack app', (done) => { + runTargetSpec(basicWorkspaceRoot, basicHost, webpackTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(join(outputPath, 'bundle.js'))).toBe(true); }), ).subscribe(undefined, done.fail, done); }, 30000); + + it('works with a Angular app', (done) => { + runTargetSpec(workspaceRoot, host, webpackTargetSpec, {}).pipe( + tap((buildEvent) => expect(buildEvent.success).toBe(true)), + tap(() => { + // Default files should be in outputPath. + // expect(host.scopedSync().exists(join(outputPath, 'runtime.js'))).toBe(true); + expect(host.scopedSync().exists(join(outputPath, 'main.js'))).toBe(true); + expect(host.scopedSync().exists(join(outputPath, 'polyfills.js'))).toBe(true); + // expect(host.scopedSync().exists(join(outputPath, 'styles.js'))).toBe(true); + // expect(host.scopedSync().exists(join(outputPath, 'vendor.js'))).toBe(true); + // expect(host.scopedSync().exists(join(outputPath, 'favicon.ico'))).toBe(true); + // expect(host.scopedSync().exists(join(outputPath, 'index.html'))).toBe(true); + }), + ).subscribe(undefined, done.fail, done); + }, 30000); }); diff --git a/tests/@angular_devkit/build_webpack/webpack-app/.gitignore b/tests/@angular_devkit/build_webpack/angular-app/.gitignore similarity index 100% rename from tests/@angular_devkit/build_webpack/webpack-app/.gitignore rename to tests/@angular_devkit/build_webpack/angular-app/.gitignore diff --git a/tests/@angular_devkit/build_webpack/webpack-app/angular.json b/tests/@angular_devkit/build_webpack/angular-app/angular.json similarity index 100% rename from tests/@angular_devkit/build_webpack/webpack-app/angular.json rename to tests/@angular_devkit/build_webpack/angular-app/angular.json diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.css b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.html b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.html new file mode 100644 index 0000000000..2486321488 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.html @@ -0,0 +1,22 @@ + +
+

+ Welcome to {{ title }}! +

+ Angular Logo +
+

Here are some links to help you start:

+ + +

i18n test

+ diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.spec.ts b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.spec.ts new file mode 100644 index 0000000000..209e3256a9 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.spec.ts @@ -0,0 +1,34 @@ +/** + * @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 { TestBed, async } from '@angular/core/testing'; +import { AppComponent } from './app.component'; +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + it('should create the app', async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + })); + it(`should have as title 'app'`, async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('app'); + })); + it('should render title in a h1 tag', async(() => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); + })); +}); diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.ts b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.ts new file mode 100644 index 0000000000..8366380cf6 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.component.ts @@ -0,0 +1,17 @@ +/** + * @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 { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'app'; +} diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/app/app.module.ts b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.module.ts new file mode 100644 index 0000000000..c61881ebb3 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.module.ts @@ -0,0 +1,25 @@ +/** + * @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 { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + + +import { AppComponent } from './app.component'; + + +@NgModule({ + declarations: [ + AppComponent + ], + imports: [ + BrowserModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/app/app.server.module.ts b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.server.module.ts new file mode 100644 index 0000000000..bb56e2795c --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/app/app.server.module.ts @@ -0,0 +1,21 @@ +/** + * @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 { NgModule } from '@angular/core'; +import { ServerModule } from '@angular/platform-server'; + +import { AppModule } from './app.module'; +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + AppModule, + ServerModule, + ], + bootstrap: [AppComponent], +}) +export class AppServerModule {} diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/assets/.gitkeep b/tests/@angular_devkit/build_webpack/angular-app/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/environments/environment.prod.ts b/tests/@angular_devkit/build_webpack/angular-app/src/environments/environment.prod.ts new file mode 100644 index 0000000000..fac764c6d2 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/environments/environment.prod.ts @@ -0,0 +1,10 @@ +/** + * @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 const environment = { + production: true +}; diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/environments/environment.ts b/tests/@angular_devkit/build_webpack/angular-app/src/environments/environment.ts new file mode 100644 index 0000000000..a3fe55067a --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/environments/environment.ts @@ -0,0 +1,15 @@ +/** + * @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 + */ +// The file contents for the current environment will overwrite these during build. +// The build system defaults to the dev environment which uses `environment.ts`, but if you do +// `ng build --env=prod` then `environment.prod.ts` will be used instead. +// The list of which env maps to which file can be found in `.angular-cli.json`. + +export const environment = { + production: false +}; diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/main.ts b/tests/@angular_devkit/build_webpack/angular-app/src/main.ts new file mode 100644 index 0000000000..3d8f375e6f --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/main.ts @@ -0,0 +1,19 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { 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(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.log(err)); diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/polyfills.ts b/tests/@angular_devkit/build_webpack/angular-app/src/polyfills.ts new file mode 100644 index 0000000000..1e5ba9f031 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/polyfills.ts @@ -0,0 +1,73 @@ +/** + * @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 + */ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/weak-map'; +// import 'core-js/es6/set'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + + +/** Evergreen browsers require these. **/ +// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. +import 'core-js/es7/reflect'; + + +/** + * Required to support Web Animations `@angular/platform-browser/animations`. + * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + + + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/src/locale/messages.xlf b/tests/@angular_devkit/build_webpack/angular-app/src/src/locale/messages.xlf new file mode 100644 index 0000000000..5ba84a9b35 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/src/locale/messages.xlf @@ -0,0 +1,18 @@ + + + + + + i18n test + + app/app.component.ts + 21 + + + app/app.component.ts + 23 + + + + + diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/styles.css b/tests/@angular_devkit/build_webpack/angular-app/src/styles.css new file mode 100644 index 0000000000..90d4ee0072 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/tsconfig.app.json b/tests/@angular_devkit/build_webpack/angular-app/src/tsconfig.app.json new file mode 100644 index 0000000000..b90ffb0148 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "module": "es2015", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts" + ] +} diff --git a/tests/@angular_devkit/build_webpack/angular-app/tsconfig.json b/tests/@angular_devkit/build_webpack/angular-app/tsconfig.json new file mode 100644 index 0000000000..ef44e2862b --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2017", + "dom" + ] + } +} diff --git a/tests/@angular_devkit/build_webpack/angular-app/webpack.config.js b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.js new file mode 100644 index 0000000000..36ba73a2eb --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.js @@ -0,0 +1,38 @@ +const ngToolsWebpack = require('@ngtools/webpack'); +const path = require('path'); + + +const workspaceRoot = path.resolve(__dirname, './'); +const projectRoot = path.resolve(__dirname, './'); + +module.exports = { + mode: 'development', + resolve: { + extensions: ['.ts', '.js'] + }, + entry: { + main: path.resolve(projectRoot, './src/main.ts'), + polyfills: path.resolve(projectRoot, './src/polyfills.ts') + }, + output: { + path: path.resolve(workspaceRoot, './dist'), + filename: `[name].js`, + }, + plugins: [ + new ngToolsWebpack.AngularCompilerPlugin({ + tsConfigPath: path.resolve(projectRoot, './src/tsconfig.app.json') + }) + ], + module: { + rules: [ + { test: /\.scss$/, loaders: ['raw-loader', 'sass-loader'] }, + { test: /\.css$/, loader: 'raw-loader' }, + { test: /\.html$/, loader: 'raw-loader' }, + // require.resolve is required only because of the monorepo structure here. + { test: /\.ts$/, loader: require.resolve('@ngtools/webpack') } + ] + }, + devServer: { + historyApiFallback: true + } +}; diff --git a/tests/@angular_devkit/build_webpack/basic-app/.gitignore b/tests/@angular_devkit/build_webpack/basic-app/.gitignore new file mode 100644 index 0000000000..54bfd2001e --- /dev/null +++ b/tests/@angular_devkit/build_webpack/basic-app/.gitignore @@ -0,0 +1,42 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +testem.log +/typings + +# e2e +/e2e/*.js +/e2e/*.map + +# System Files +.DS_Store +Thumbs.db diff --git a/tests/@angular_devkit/build_webpack/basic-app/angular.json b/tests/@angular_devkit/build_webpack/basic-app/angular.json new file mode 100644 index 0000000000..0e357bdc7d --- /dev/null +++ b/tests/@angular_devkit/build_webpack/basic-app/angular.json @@ -0,0 +1,30 @@ +{ + "$schema": "../../../../packages/angular_devkit/core/src/workspace/workspace-schema.json", + "version": 1, + "newProjectRoot": "./projects", + "cli": {}, + "schematics": {}, + "architect": {}, + "projects": { + "app": { + "root": "src", + "sourceRoot": "src", + "projectType": "application", + "schematics": {}, + "architect": { + "build": { + "builder": "../../../../packages/angular_devkit/build_webpack:webpack", + "options": { + "webpackConfig": "webpack.config.js" + } + }, + "serve": { + "builder": "../../../../packages/angular_devkit/build_webpack:webpack-dev-server", + "options": { + "webpackConfig": "webpack.config.js" + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/@angular_devkit/build_webpack/webpack-app/src/main.js b/tests/@angular_devkit/build_webpack/basic-app/src/main.js similarity index 100% rename from tests/@angular_devkit/build_webpack/webpack-app/src/main.js rename to tests/@angular_devkit/build_webpack/basic-app/src/main.js diff --git a/tests/@angular_devkit/build_webpack/webpack-app/webpack.config.js b/tests/@angular_devkit/build_webpack/basic-app/webpack.config.js similarity index 100% rename from tests/@angular_devkit/build_webpack/webpack-app/webpack.config.js rename to tests/@angular_devkit/build_webpack/basic-app/webpack.config.js From 675468f099bb0846963d5e388f8c92cdd27e3d03 Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Mon, 14 May 2018 15:36:46 +0100 Subject: [PATCH 5/9] feat(@angular-devkit/architect): use temp folder in TestProjectHost Using Git had a nasty tendency to clear changes while testing. --- .gitignore | 1 + .../architect/testing/run-target-spec.ts | 3 +- .../architect/testing/test-project-host.ts | 141 ++++++++++-------- .../test/app-shell/app-shell_spec_large.ts | 4 +- .../test/browser/allow-js_spec_large.ts | 6 +- .../test/browser/aot_spec_large.ts | 4 +- .../test/browser/assets_spec_large.ts | 10 +- .../test/browser/base-href_spec_large.ts | 4 +- .../browser/build-optimizer_spec_large.ts | 4 +- .../test/browser/bundle-budgets_spec_large.ts | 8 +- .../browser/circular-dependency_spec_large.ts | 4 +- .../test/browser/deploy-url_spec_large.ts | 8 +- .../test/browser/errors_spec_large.ts | 8 +- .../test/browser/i18n_spec_large.ts | 10 +- .../test/browser/lazy-module_spec_large.ts | 22 +-- .../browser/license-extraction_spec_large.ts | 4 +- .../browser/no-entry-module_spec_large.ts | 4 +- .../browser/optimization-level_spec_large.ts | 6 +- .../test/browser/output-hashing_spec_large.ts | 24 ++- .../test/browser/output-path_spec_large.ts | 8 +- .../test/browser/poll_spec_large.ts | 4 +- .../test/browser/rebuild_spec_large.ts | 14 +- .../test/browser/replacements_spec_large.ts | 10 +- .../test/browser/scripts-array_spec_large.ts | 8 +- .../test/browser/service-worker_spec_large.ts | 8 +- .../test/browser/source-map_spec_large.ts | 8 +- .../test/browser/stats-json_spec_large.ts | 4 +- .../test/browser/styles_spec_large.ts | 40 ++--- .../subresource-integrity_spec_large.ts | 4 +- .../test/browser/tsconfig-paths_spec_large.ts | 6 +- .../test/browser/vendor-chunk_spec_large.ts | 4 +- .../test/browser/works_spec_large.ts | 4 +- .../test/dev-server/proxy_spec_large.ts | 6 +- .../test/dev-server/public-host_spec_large.ts | 8 +- .../test/dev-server/serve-path_spec_large.ts | 4 +- .../test/dev-server/ssl_spec_large.ts | 6 +- .../test/dev-server/works_spec_large.ts | 4 +- .../test/extract-i18n/works_spec_large.ts | 14 +- .../test/karma/assets_spec_large.ts | 4 +- .../test/karma/code-coverage_spec_large.ts | 6 +- .../test/karma/rebuilds_spec_large.ts | 6 +- .../test/karma/replacements_spec_large.ts | 4 +- .../test/karma/works_spec_large.ts | 8 +- .../test/protractor/works_spec_large.ts | 10 +- .../test/server/base_spec_large.ts | 4 +- .../test/tslint/works_spec_large.ts | 26 ++-- .../build_angular/test/utils.ts | 3 +- .../src/build/index_spec_large.ts | 9 +- .../build_webpack/src/test-utils.ts | 7 +- .../webpack-dev-server/index_spec_large.ts | 8 +- .../src/webpack/index_spec_large.ts | 59 ++++---- 51 files changed, 307 insertions(+), 286 deletions(-) diff --git a/.gitignore b/.gitignore index d46ee5f9af..e6c63302db 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Outputs bazel-* +test-project-host-* dist/ # IDEs diff --git a/packages/angular_devkit/architect/testing/run-target-spec.ts b/packages/angular_devkit/architect/testing/run-target-spec.ts index 9ad81ff5ca..e06a80487d 100644 --- a/packages/angular_devkit/architect/testing/run-target-spec.ts +++ b/packages/angular_devkit/architect/testing/run-target-spec.ts @@ -14,7 +14,6 @@ import { TestProjectHost } from './test-project-host'; export function runTargetSpec( - workspaceRoot: Path, host: TestProjectHost, targetSpec: TargetSpecifier, overrides = {}, @@ -22,7 +21,7 @@ export function runTargetSpec( ): Observable { targetSpec = { ...targetSpec, overrides }; const workspaceFile = normalize('angular.json'); - const workspace = new experimental.workspace.Workspace(workspaceRoot, host); + const workspace = new experimental.workspace.Workspace(host.root(), host); return workspace.loadWorkspaceFromHost(workspaceFile).pipe( concatMap(ws => new Architect(ws).loadArchitect()), diff --git a/packages/angular_devkit/architect/testing/test-project-host.ts b/packages/angular_devkit/architect/testing/test-project-host.ts index 87a84704ed..96e576ee9c 100644 --- a/packages/angular_devkit/architect/testing/test-project-host.ts +++ b/packages/angular_devkit/architect/testing/test-project-host.ts @@ -8,92 +8,96 @@ import { Path, - getSystemPath, + basename, + dirname, + join, normalize, + relative, virtualFs, } from '@angular-devkit/core'; import { NodeJsSyncHost } from '@angular-devkit/core/node'; -import { SpawnOptions, spawn } from 'child_process'; import { Stats } from 'fs'; -import { EMPTY, Observable } from 'rxjs'; -import { concatMap, map } from 'rxjs/operators'; +import { EMPTY, Observable, from, of } from 'rxjs'; +import { concatMap, delay, map, mergeMap, retry, tap } from 'rxjs/operators'; -interface ProcessOutput { - stdout: string; - stderr: string; -} - export class TestProjectHost extends NodeJsSyncHost { - private _scopedSyncHost: virtualFs.SyncDelegateHost; + private _currentRoot: Path | null = null; + private _scopedSyncHost: virtualFs.SyncDelegateHost | null = null; - constructor(protected _root: Path) { + constructor(protected _templateRoot: Path) { super(); - this._scopedSyncHost = new virtualFs.SyncDelegateHost(new virtualFs.ScopedHost(this, _root)); } - scopedSync() { - return this._scopedSyncHost; - } + root(): Path { + if (this._currentRoot === null) { + throw new Error('TestProjectHost must be initialized before being used.'); + } - initialize(): Observable { - return this.exists(normalize('.git')).pipe( - concatMap(exists => !exists ? this._gitInit() : EMPTY), - ); + // tslint:disable-next-line:non-null-operator + return this._currentRoot!; } - restore(): Observable { - return this._gitClean(); + scopedSync(): virtualFs.SyncDelegateHost { + if (this._currentRoot === null || this._scopedSyncHost === null) { + throw new Error('TestProjectHost must be initialized before being used.'); + } + + // tslint:disable-next-line:non-null-operator + return this._scopedSyncHost!; } - private _gitClean(): Observable { - return this._exec('git', ['clean', '-fd']).pipe( - concatMap(() => this._exec('git', ['checkout', '.'])), - map(() => { }), + initialize(): Observable { + const recursiveList = (path: Path): Observable => this.list(path).pipe( + // Emit each fragment individually. + concatMap(fragments => from(fragments)), + // Join the path with fragment. + map(fragment => join(path, fragment)), + // Emit directory content paths instead of the directory path. + mergeMap(path => this.isDirectory(path).pipe( + concatMap(isDir => isDir ? recursiveList(path) : of(path)), + )), ); - } - private _gitInit(): Observable { - return this._exec('git', ['init']).pipe( - concatMap(() => this._exec('git', ['config', 'user.email', 'angular-core+e2e@google.com'])), - concatMap(() => this._exec('git', ['config', 'user.name', 'Angular DevKit Tests'])), - concatMap(() => this._exec('git', ['add', '--all'])), - concatMap(() => this._exec('git', ['commit', '-am', '"Initial commit"'])), + // Find a unique folder that we can write to to use as current root. + return this.findUniqueFolderPath().pipe( + // Save the path and create a scoped host for it. + tap(newFolderPath => { + this._currentRoot = newFolderPath; + this._scopedSyncHost = new virtualFs.SyncDelegateHost( + new virtualFs.ScopedHost(this, this.root())); + }), + // List all files in root. + concatMap(() => recursiveList(this._templateRoot)), + // Copy them over to the current root. + concatMap(from => { + const to = join(this.root(), relative(this._templateRoot, from)); + + return this.read(from).pipe( + concatMap(buffer => this.write(to, buffer)), + ); + }), map(() => { }), ); } - private _exec(cmd: string, args: string[]): Observable { - return new Observable(obs => { - args = args.filter(x => x !== undefined); - let stdout = ''; - let stderr = ''; - - const spawnOptions: SpawnOptions = { cwd: getSystemPath(this._root) }; - - if (process.platform.startsWith('win')) { - args.unshift('/c', cmd); - cmd = 'cmd.exe'; - spawnOptions['stdio'] = 'pipe'; - } - - const childProcess = spawn(cmd, args, spawnOptions); - childProcess.stdout.on('data', (data: Buffer) => stdout += data.toString('utf-8')); - childProcess.stderr.on('data', (data: Buffer) => stderr += data.toString('utf-8')); - - // Create the error here so the stack shows who called this function. - const err = new Error(`Running "${cmd} ${args.join(' ')}" returned error code `); - - childProcess.on('exit', (code) => { - if (!code) { - obs.next({ stdout, stderr }); - } else { - err.message += `${code}.\n\nSTDOUT:\n${stdout}\n\nSTDERR:\n${stderr}\n`; - obs.error(err); - } - obs.complete(); - }); - }); + restore(): Observable { + if (this._currentRoot === null) { + return EMPTY; + } + + // Delete the current root and clear the variables. + // Wait 50ms and retry up to 10 times, to give time for file locks to clear. + return this.exists(this.root()).pipe( + delay(50), + concatMap(exists => exists ? this.delete(this.root()) : of(null)), + retry(10), + tap(() => { + this._currentRoot = null; + this._scopedSyncHost = null; + }), + map(() => { }), + ); } writeMultipleFiles(files: { [path: string]: string | ArrayBufferLike | Buffer }): void { @@ -137,4 +141,15 @@ export class TestProjectHost extends NodeJsSyncHost { const content = this.scopedSync().read(normalize(from)); this.scopedSync().write(normalize(to), content); } + + private findUniqueFolderPath(): Observable { + // 11 character alphanumeric string. + const randomString = Math.random().toString(36).slice(2); + const newFolderName = `test-project-host-${basename(this._templateRoot)}-${randomString}`; + const newFolderPath = join(dirname(this._templateRoot), newFolderName); + + return this.exists(newFolderPath).pipe( + concatMap(exists => exists ? this.findUniqueFolderPath() : of(newFolderPath)), + ); + } } diff --git a/packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts b/packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts index 7d854690f1..6e1ed4df89 100644 --- a/packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/app-shell/app-shell_spec_large.ts @@ -8,7 +8,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, host, workspaceRoot } from '../utils'; +import { Timeout, host } from '../utils'; describe('AppShell Builder', () => { @@ -38,7 +38,7 @@ describe('AppShell Builder', () => { `, }); - runTargetSpec(workspaceRoot, host, { project: 'app', target: 'app-shell' }).pipe( + runTargetSpec(host, { project: 'app', target: 'app-shell' }).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = 'dist/index.html'; diff --git a/packages/angular_devkit/build_angular/test/browser/allow-js_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/allow-js_spec_large.ts index 227eb51568..c3fe75abd5 100644 --- a/packages/angular_devkit/build_angular/test/browser/allow-js_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/allow-js_spec_large.ts @@ -8,7 +8,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder allow js', () => { @@ -24,7 +24,7 @@ describe('Browser Builder allow js', () => { // TODO: this test originally edited tsconfig to have `"allowJs": true` but works without it. // Investigate. - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -37,7 +37,7 @@ describe('Browser Builder allow js', () => { const overrides = { aot: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); diff --git a/packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts index 62350c3fef..549d613584 100644 --- a/packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder AOT', () => { @@ -21,7 +21,7 @@ describe('Browser Builder AOT', () => { it('works', (done) => { const overrides = { aot: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/assets_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/assets_spec_large.ts index a40e405be6..730e2fce2c 100644 --- a/packages/angular_devkit/build_angular/test/browser/assets_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/assets_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { tap, toArray } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder assets', () => { @@ -45,7 +45,7 @@ describe('Browser Builder assets', () => { ], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { // Assets we expect should be there. @@ -70,7 +70,7 @@ describe('Browser Builder assets', () => { }], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + runTargetSpec(host, browserTargetSpec, overrides) .subscribe(undefined, () => done(), done.fail); // The node_modules folder must be deleted, otherwise code that tries to find the @@ -87,7 +87,7 @@ describe('Browser Builder assets', () => { assets: ['not-source-root/file.txt'], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + runTargetSpec(host, browserTargetSpec, overrides) .subscribe(undefined, () => done(), done.fail); // The node_modules folder must be deleted, otherwise code that tries to find the @@ -100,7 +100,7 @@ describe('Browser Builder assets', () => { assets: [], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( toArray(), tap((buildEvents) => expect(buildEvents.length).toBe(1)), ).subscribe(undefined, done.fail, done); diff --git a/packages/angular_devkit/build_angular/test/browser/base-href_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/base-href_spec_large.ts index b9e1f6b0fd..a49fb07873 100644 --- a/packages/angular_devkit/build_angular/test/browser/base-href_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/base-href_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder base href', () => { @@ -26,7 +26,7 @@ describe('Browser Builder base href', () => { const overrides = { baseHref: '/myUrl' }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'index.html'); diff --git a/packages/angular_devkit/build_angular/test/browser/build-optimizer_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/build-optimizer_spec_large.ts index 20b49eb210..b069664fb3 100644 --- a/packages/angular_devkit/build_angular/test/browser/build-optimizer_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/build-optimizer_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder build optimizer', () => { @@ -20,7 +20,7 @@ describe('Browser Builder build optimizer', () => { it('works', (done) => { const overrides = { aot: true, buildOptimizer: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/bundle-budgets_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/bundle-budgets_spec_large.ts index 70a92e700d..d5fbc193b6 100644 --- a/packages/angular_devkit/build_angular/test/browser/bundle-budgets_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/bundle-budgets_spec_large.ts @@ -8,7 +8,7 @@ import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder bundle budgets', () => { @@ -24,7 +24,7 @@ describe('Browser Builder bundle budgets', () => { const logger = new TestLogger('rebuild-type-errors'); - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(logger.includes('WARNING')).toBe(false)), ).subscribe(undefined, done.fail, done); @@ -36,7 +36,7 @@ describe('Browser Builder bundle budgets', () => { budgets: [{ type: 'all', maximumError: '100b' }], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), ).subscribe(undefined, done.fail, done); }, Timeout.Complex); @@ -49,7 +49,7 @@ describe('Browser Builder bundle budgets', () => { const logger = new TestLogger('rebuild-type-errors'); - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(logger.includes('WARNING')).toBe(true)), ).subscribe(undefined, done.fail, done); diff --git a/packages/angular_devkit/build_angular/test/browser/circular-dependency_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/circular-dependency_spec_large.ts index 8ed7b0be6a..f88abee8c1 100644 --- a/packages/angular_devkit/build_angular/test/browser/circular-dependency_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/circular-dependency_spec_large.ts @@ -8,7 +8,7 @@ import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder circular dependency detection', () => { @@ -22,7 +22,7 @@ describe('Browser Builder circular dependency detection', () => { const overrides = { baseHref: '/myUrl' }; const logger = new TestLogger('circular-dependencies'); - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(logger.includes('Circular dependency detected')).toBe(true)), ).subscribe(undefined, done.fail, done); diff --git a/packages/angular_devkit/build_angular/test/browser/deploy-url_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/deploy-url_spec_large.ts index 7dc8499aa8..dfa48a3807 100644 --- a/packages/angular_devkit/build_angular/test/browser/deploy-url_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/deploy-url_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { concatMap, tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder deploy url', () => { @@ -21,14 +21,14 @@ describe('Browser Builder deploy url', () => { it('uses deploy url for bundles urls', (done) => { const overrides = { deployUrl: 'deployUrl/' }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'index.html'); const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName))); expect(content).toContain('deployUrl/main.js'); }), - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { deployUrl: 'http://example.com/some/path/' })), tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { @@ -42,7 +42,7 @@ describe('Browser Builder deploy url', () => { it('uses deploy url for in webpack runtime', (done) => { const overrides = { deployUrl: 'deployUrl/' }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'runtime.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/errors_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/errors_spec_large.ts index 4c77c417de..02f3da146c 100644 --- a/packages/angular_devkit/build_angular/test/browser/errors_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/errors_spec_large.ts @@ -8,7 +8,7 @@ import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder errors', () => { @@ -22,7 +22,7 @@ describe('Browser Builder errors', () => { `); const logger = new TestLogger('errors-compilation'); - runTargetSpec(workspaceRoot, host, browserTargetSpec, undefined, logger).pipe( + runTargetSpec(host, browserTargetSpec, undefined, logger).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); expect(logger.includes('polyfills.ts is missing from the TypeScript')).toBe(true); @@ -34,7 +34,7 @@ describe('Browser Builder errors', () => { host.appendToFile('src/app/app.component.ts', ']]]'); const logger = new TestLogger('errors-syntax'); - runTargetSpec(workspaceRoot, host, browserTargetSpec, undefined, logger).pipe( + runTargetSpec(host, browserTargetSpec, undefined, logger).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); expect(logger.includes('Declaration or statement expected.')).toBe(true); @@ -46,7 +46,7 @@ describe('Browser Builder errors', () => { host.replaceInFile('src/app/app.component.ts', `'app-root'`, `(() => 'app-root')()`); const logger = new TestLogger('errors-static'); - runTargetSpec(workspaceRoot, host, browserTargetSpec, { aot: true }, logger).pipe( + runTargetSpec(host, browserTargetSpec, { aot: true }, logger).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); expect(logger.includes('Function expressions are not supported in')).toBe(true); diff --git a/packages/angular_devkit/build_angular/test/browser/i18n_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/i18n_spec_large.ts index 25b62134de..7f8a58490e 100644 --- a/packages/angular_devkit/build_angular/test/browser/i18n_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/i18n_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder i18n', () => { @@ -54,7 +54,7 @@ describe('Browser Builder i18n', () => { i18nLocale: 'fr', }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -76,7 +76,7 @@ describe('Browser Builder i18n', () => { host.writeMultipleFiles({ 'src/locale/messages.fr.xlf': emptyTranslationFile }); host.appendToFile('src/app/app.component.html', '

Other content

'); - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -98,7 +98,7 @@ describe('Browser Builder i18n', () => { host.writeMultipleFiles({ 'src/locale/messages.fr.xlf': emptyTranslationFile }); host.appendToFile('src/app/app.component.html', '

Other content

'); - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -106,7 +106,7 @@ describe('Browser Builder i18n', () => { it('register locales', (done) => { const overrides = { aot: true, i18nLocale: 'fr_FR' }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/lazy-module_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/lazy-module_spec_large.ts index c431ba1ece..957330bcfd 100644 --- a/packages/angular_devkit/build_angular/test/browser/lazy-module_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/lazy-module_spec_large.ts @@ -10,7 +10,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; import { BrowserBuilderSchema } from '../../src'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; export const lazyModuleFiles: { [path: string]: string } = { @@ -81,7 +81,7 @@ describe('Browser Builder lazy modules', () => { host.writeMultipleFiles(lazyModuleFiles); host.writeMultipleFiles(lazyModuleImport); - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(join(outputPath, 'lazy-lazy-module.js'))).toBe(true); @@ -93,7 +93,7 @@ describe('Browser Builder lazy modules', () => { host.writeMultipleFiles(lazyModuleFiles); host.writeMultipleFiles(lazyModuleImport); - runTargetSpec(workspaceRoot, host, browserTargetSpec, { aot: true }).pipe( + runTargetSpec(host, browserTargetSpec, { aot: true }).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync() @@ -110,7 +110,7 @@ describe('Browser Builder lazy modules', () => { // Using `import()` in TS require targetting `esnext` modules. host.replaceInFile('src/tsconfig.app.json', `"module": "es2015"`, `"module": "esnext"`); - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), ).subscribe(undefined, done.fail, done); @@ -126,7 +126,7 @@ describe('Browser Builder lazy modules', () => { }); host.replaceInFile('src/tsconfig.app.json', `"module": "es2015"`, `"module": "esnext"`); - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, 'lazy-module.js'))).toBe(true)), ).subscribe(undefined, done.fail, done); @@ -138,7 +138,7 @@ describe('Browser Builder lazy modules', () => { 'src/main.ts': `declare var System: any; System.import('./lazy-module');`, }); - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), ).subscribe(undefined, done.fail, done); @@ -153,7 +153,7 @@ describe('Browser Builder lazy modules', () => { const overrides: Partial = { namedChunks: false }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), ).subscribe(undefined, done.fail, done); @@ -167,7 +167,7 @@ describe('Browser Builder lazy modules', () => { }); host.replaceInFile('src/tsconfig.app.json', `"module": "es2015"`, `"module": "esnext"`); - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '1.js'))).toBe(true)), @@ -186,7 +186,7 @@ describe('Browser Builder lazy modules', () => { const overrides: Partial = { commonChunk: false }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '0.js'))).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, '1.js'))).toBe(true)), @@ -218,7 +218,7 @@ describe('Browser Builder lazy modules', () => { const overrides: Partial = { lazyModules: ['src/app/lazy/lazy.module'] }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync().exists(join(outputPath, 'src-app-lazy-lazy-module.js'))) .toBe(true)), @@ -253,7 +253,7 @@ describe('Browser Builder lazy modules', () => { optimization: true, }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => expect(host.scopedSync() .exists(join(outputPath, 'src-app-lazy-lazy-module-ngfactory.js'))) diff --git a/packages/angular_devkit/build_angular/test/browser/license-extraction_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/license-extraction_spec_large.ts index 3d5c4fb3d0..a65cbc1195 100644 --- a/packages/angular_devkit/build_angular/test/browser/license-extraction_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/license-extraction_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder license extraction', () => { @@ -24,7 +24,7 @@ describe('Browser Builder license extraction', () => { // TODO: make license extraction independent from optimization level. const overrides = { extractLicenses: true, optimization: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, '3rdpartylicenses.txt'); diff --git a/packages/angular_devkit/build_angular/test/browser/no-entry-module_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/no-entry-module_spec_large.ts index aae0ba9fea..9b6ff632bf 100644 --- a/packages/angular_devkit/build_angular/test/browser/no-entry-module_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/no-entry-module_spec_large.ts @@ -8,7 +8,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder no entry module', () => { @@ -22,7 +22,7 @@ describe('Browser Builder no entry module', () => { const overrides = { baseHref: '/myUrl' }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); diff --git a/packages/angular_devkit/build_angular/test/browser/optimization-level_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/optimization-level_spec_large.ts index d8358a216a..831bcbbaf1 100644 --- a/packages/angular_devkit/build_angular/test/browser/optimization-level_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/optimization-level_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder optimization level', () => { @@ -21,7 +21,7 @@ describe('Browser Builder optimization level', () => { it('works', (done) => { const overrides = { optimization: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -37,7 +37,7 @@ describe('Browser Builder optimization level', () => { const overrides = { optimization: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'vendor.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/output-hashing_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/output-hashing_spec_large.ts index 4f3555cb4e..2c886e00ce 100644 --- a/packages/angular_devkit/build_angular/test/browser/output-hashing_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/output-hashing_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize } from '@angular-devkit/core'; import { concatMap, tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; import { lazyModuleFiles, lazyModuleImport } from './lazy-module_spec_large'; @@ -61,7 +61,7 @@ describe('Browser Builder output hashing', () => { // We must do several builds instead of a single one in watch mode, so that the output // path is deleted on each run and only contains the most recent files. - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap(() => { // Save the current hashes. oldHashes = generateFileHashMap(); @@ -69,7 +69,7 @@ describe('Browser Builder output hashing', () => { host.writeMultipleFiles(lazyModuleImport); }), // Lazy chunk hash should have changed without modifying main bundle. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, []); @@ -77,7 +77,7 @@ describe('Browser Builder output hashing', () => { host.writeMultipleFiles({ 'src/styles.css': 'body { background: blue; }' }); }), // Style hash should change. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, ['styles']); @@ -85,7 +85,7 @@ describe('Browser Builder output hashing', () => { host.writeMultipleFiles({ 'src/app/app.component.css': 'h1 { margin: 10px; }' }); }), // Main hash should change, since inline styles go in the main bundle. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, ['main']); @@ -93,7 +93,7 @@ describe('Browser Builder output hashing', () => { host.appendToFile('src/app/lazy/lazy.module.ts', `console.log(1);`); }), // Lazy loaded bundle should change, and so should inline. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, ['lazy.module']); @@ -101,7 +101,7 @@ describe('Browser Builder output hashing', () => { host.appendToFile('src/main.ts', ''); }), // Nothing should have changed. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides)), + concatMap(() => runTargetSpec(host, browserTargetSpec, overrides)), tap(() => { newHashes = generateFileHashMap(); validateHashes(oldHashes, newHashes, []); @@ -117,9 +117,7 @@ describe('Browser Builder output hashing', () => { // We must do several builds instead of a single one in watch mode, so that the output // path is deleted on each run and only contains the most recent files. // 'all' should hash everything. - runTargetSpec( - workspaceRoot, host, browserTargetSpec, { outputHashing: 'all', extractCss: true }, - ).pipe( + runTargetSpec(host, browserTargetSpec, { outputHashing: 'all', extractCss: true }).pipe( tap(() => { expect(host.fileMatchExists('dist', /runtime\.[0-9a-f]{20}\.js/)).toBeTruthy(); expect(host.fileMatchExists('dist', /main\.[0-9a-f]{20}\.js/)).toBeTruthy(); @@ -129,7 +127,7 @@ describe('Browser Builder output hashing', () => { expect(host.fileMatchExists('dist', /spectrum\.[0-9a-f]{20}\.png/)).toBeTruthy(); }), // 'none' should hash nothing. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { outputHashing: 'none', extractCss: true })), tap(() => { expect(host.fileMatchExists('dist', /runtime\.[0-9a-f]{20}\.js/)).toBeFalsy(); @@ -140,7 +138,7 @@ describe('Browser Builder output hashing', () => { expect(host.fileMatchExists('dist', /spectrum\.[0-9a-f]{20}\.png/)).toBeFalsy(); }), // 'media' should hash css resources only. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { outputHashing: 'media', extractCss: true })), tap(() => { expect(host.fileMatchExists('dist', /runtime\.[0-9a-f]{20}\.js/)).toBeFalsy(); @@ -151,7 +149,7 @@ describe('Browser Builder output hashing', () => { expect(host.fileMatchExists('dist', /spectrum\.[0-9a-f]{20}\.png/)).toBeTruthy(); }), // 'bundles' should hash bundles only. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { outputHashing: 'bundles', extractCss: true })), tap(() => { expect(host.fileMatchExists('dist', /runtime\.[0-9a-f]{20}\.js/)).toBeTruthy(); diff --git a/packages/angular_devkit/build_angular/test/browser/output-path_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/output-path_spec_large.ts index 9c2e20b640..9ec320f34f 100644 --- a/packages/angular_devkit/build_angular/test/browser/output-path_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/output-path_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder output path', () => { @@ -23,11 +23,11 @@ describe('Browser Builder output path', () => { host.scopedSync().write(join(outputPath, 'file.txt'), virtualFs.stringToFileBuffer('file')); // Delete an app file to force a failed compilation. // Failed compilations still delete files, but don't output any. - host.delete(join(workspaceRoot, 'src', 'app', 'app.component.ts')).subscribe({ + host.delete(join(host.root(), 'src', 'app', 'app.component.ts')).subscribe({ error: done.fail, }); - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); expect(host.scopedSync().exists(outputPath)).toBe(false); @@ -38,7 +38,7 @@ describe('Browser Builder output path', () => { it('does not allow output path to be project root', (done) => { const overrides = { outputPath: './' }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + runTargetSpec(host, browserTargetSpec, overrides) .subscribe(undefined, () => done(), done.fail); }, Timeout.Basic); }); diff --git a/packages/angular_devkit/build_angular/test/browser/poll_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/poll_spec_large.ts index de800bca19..2c6987fdd8 100644 --- a/packages/angular_devkit/build_angular/test/browser/poll_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/poll_spec_large.ts @@ -8,7 +8,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { debounceTime, take, tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder poll', () => { @@ -19,7 +19,7 @@ describe('Browser Builder poll', () => { const overrides = { watch: true, poll: 1000 }; let msAvg = 1000; let lastTime: number; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( // Debounce 1s, otherwise changes are too close together and polling doesn't work. debounceTime(1000), tap((buildEvent) => expect(buildEvent.success).toBe(true)), diff --git a/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts index a34a273c47..17e121cb3d 100644 --- a/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts @@ -9,7 +9,7 @@ import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { debounceTime, take, tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; import { lazyModuleFiles, lazyModuleImport } from './lazy-module_spec_large'; @@ -79,7 +79,7 @@ describe('Browser Builder rebuilds', () => { let buildNumber = 0; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( // We must debounce on watch mode because file watchers are not very accurate. // Changes from just before a process runs can be picked up and cause rebuilds. // In this case, cleanup from the test right before this one causes a few rebuilds. @@ -127,7 +127,7 @@ describe('Browser Builder rebuilds', () => { it('rebuilds on CSS changes', (done) => { const overrides = { watch: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( debounceTime(500), tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => host.appendToFile('src/app/app.component.css', ':host { color: blue; }')), @@ -150,7 +150,7 @@ describe('Browser Builder rebuilds', () => { const typeError = `is not assignable to parameter of type 'number'`; let buildNumber = 0; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( debounceTime(1000), tap((buildEvent) => { buildNumber += 1; @@ -200,7 +200,7 @@ describe('Browser Builder rebuilds', () => { const overrides = { watch: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( debounceTime(1000), tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => host.writeMultipleFiles({ 'src/type.ts': `export type MyType = string;` })), @@ -222,7 +222,7 @@ describe('Browser Builder rebuilds', () => { const syntaxError = 'Declaration or statement expected.'; let buildNumber = 0; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides, logger).pipe( + runTargetSpec(host, browserTargetSpec, overrides, logger).pipe( debounceTime(1000), tap((buildEvent) => { buildNumber += 1; @@ -284,7 +284,7 @@ describe('Browser Builder rebuilds', () => { const overrides = { watch: true, aot: true, forkTypeChecker: false }; let buildNumber = 0; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( debounceTime(1000), tap((buildEvent) => { buildNumber += 1; diff --git a/packages/angular_devkit/build_angular/test/browser/replacements_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/replacements_spec_large.ts index 91d9068092..fb6e32602f 100644 --- a/packages/angular_devkit/build_angular/test/browser/replacements_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/replacements_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder file replacements', () => { @@ -39,7 +39,7 @@ describe('Browser Builder file replacements', () => { ], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -61,7 +61,7 @@ describe('Browser Builder file replacements', () => { ], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js'); @@ -83,7 +83,7 @@ describe('Browser Builder file replacements', () => { ], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + runTargetSpec(host, browserTargetSpec, overrides) .subscribe(undefined, () => done(), done.fail); }, Timeout.Basic); @@ -97,7 +97,7 @@ describe('Browser Builder file replacements', () => { ], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + runTargetSpec(host, browserTargetSpec, overrides) .subscribe(undefined, () => done(), done.fail); }, Timeout.Basic); }); diff --git a/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts index 658a5fcca9..a683b508f5 100644 --- a/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { PathFragment, join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder scripts array', () => { @@ -67,7 +67,7 @@ describe('Browser Builder scripts array', () => { scripts: getScriptsOption(), }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => Object.keys(matches).forEach(fileName => { const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName))); @@ -86,7 +86,7 @@ describe('Browser Builder scripts array', () => { scripts: getScriptsOption(), }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const scriptsBundle = host.fileMatchExists(outputPath, /scripts\.[0-9a-f]{20}\.js/); @@ -115,7 +115,7 @@ describe('Browser Builder scripts array', () => { const overrides = { scripts: getScriptsOption() }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const re = new RegExp( diff --git a/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts index 0eed66f994..f490f4db0f 100644 --- a/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/service-worker_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder service worker', () => { @@ -45,7 +45,7 @@ describe('Browser Builder service worker', () => { it('errors if no ngsw-config.json is present', (done) => { const overrides = { serviceWorker: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides) + runTargetSpec(host, browserTargetSpec, overrides) .subscribe(event => { expect(event.success).toBe(false); }, () => done(), done.fail); @@ -58,7 +58,7 @@ describe('Browser Builder service worker', () => { }); const overrides = { serviceWorker: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap(buildEvent => { expect(buildEvent.success).toBe(true); expect(host.scopedSync().exists(normalize('dist/ngsw.json'))); @@ -113,7 +113,7 @@ describe('Browser Builder service worker', () => { }); const overrides = { serviceWorker: true, baseHref: '/foo/bar' }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap(buildEvent => { expect(buildEvent.success).toBe(true); expect(host.scopedSync().exists(normalize('dist/ngsw.json'))); diff --git a/packages/angular_devkit/build_angular/test/browser/source-map_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/source-map_spec_large.ts index e9aa783127..0383d61ea0 100644 --- a/packages/angular_devkit/build_angular/test/browser/source-map_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/source-map_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder source map', () => { @@ -21,7 +21,7 @@ describe('Browser Builder source map', () => { it('works', (done) => { const overrides = { sourceMap: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js.map'); @@ -33,7 +33,7 @@ describe('Browser Builder source map', () => { it('does not output source map when disabled', (done) => { const overrides = { sourceMap: false }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'main.js.map'); @@ -45,7 +45,7 @@ describe('Browser Builder source map', () => { it('supports eval source map', (done) => { const overrides = { sourceMap: true, evalSourceMap: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(join(outputPath, 'main.js.map'))).toBe(false); diff --git a/packages/angular_devkit/build_angular/test/browser/stats-json_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/stats-json_spec_large.ts index e853a74f94..869431949b 100644 --- a/packages/angular_devkit/build_angular/test/browser/stats-json_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/stats-json_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder stats json', () => { @@ -21,7 +21,7 @@ describe('Browser Builder stats json', () => { it('works', (done) => { const overrides = { statsJson: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'stats.json'); diff --git a/packages/angular_devkit/build_angular/test/browser/styles_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/styles_spec_large.ts index 36d5082207..4a87f52ad2 100644 --- a/packages/angular_devkit/build_angular/test/browser/styles_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/styles_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, tags, virtualFs } from '@angular-devkit/core'; import { concatMap, tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder styles', () => { @@ -67,7 +67,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true, styles: getStylesOption() }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), // Check css files were created. tap(() => Object.keys(cssMatches).forEach(fileName => { @@ -84,7 +84,7 @@ describe('Browser Builder styles', () => { expect(content).toMatch(cssIndexMatches[fileName]); })), // Also test with extractCss false. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { extractCss: false, styles: getStylesOption() })), // TODO: figure out why adding this tap breaks typings. // This also happens in the output-hashing spec. @@ -124,7 +124,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -173,7 +173,7 @@ describe('Browser Builder styles', () => { host.replaceInFile('src/app/app.component.ts', './app.component.css', `./app.component.${ext}`); - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => Object.keys(matches).forEach(fileName => { const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName))); @@ -203,7 +203,7 @@ describe('Browser Builder styles', () => { styles: [{ input: `src/styles.${ext}` }], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -218,7 +218,7 @@ describe('Browser Builder styles', () => { ], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Complex); @@ -267,7 +267,7 @@ describe('Browser Builder styles', () => { }, }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => Object.keys(matches).forEach(fileName => { const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName))); @@ -300,7 +300,7 @@ describe('Browser Builder styles', () => { styles: [`src/styles.scss`], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = 'dist/styles.css'; @@ -343,7 +343,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true, styles: [`src/styles.scss`] }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -358,7 +358,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true, optimization: false }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = 'dist/styles.css'; @@ -381,7 +381,7 @@ describe('Browser Builder styles', () => { const overrides = { extractCss: true, optimization: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = 'dist/styles.css'; @@ -416,7 +416,7 @@ describe('Browser Builder styles', () => { const mainBundle = 'dist/main.js'; // Check base paths are correctly generated. - runTargetSpec(workspaceRoot, host, browserTargetSpec, { aot: true, extractCss: true }).pipe( + runTargetSpec(host, browserTargetSpec, { aot: true, extractCss: true }).pipe( tap(() => { const styles = virtualFs.fileBufferToString( host.scopedSync().read(normalize(stylesBundle)), @@ -436,7 +436,7 @@ describe('Browser Builder styles', () => { .toBe(true); }), // Check urls with deploy-url scheme are used as is. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { extractCss: true, baseHref: '/base/', deployUrl: 'http://deploy.url/' }, )), tap(() => { @@ -450,7 +450,7 @@ describe('Browser Builder styles', () => { .toContain(`url('http://deploy.url/assets/component-img-absolute.svg')`); }), // Check urls with base-href scheme are used as is (with deploy-url). - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { extractCss: true, baseHref: 'http://base.url/', deployUrl: 'deploy/' }, )), tap(() => { @@ -464,7 +464,7 @@ describe('Browser Builder styles', () => { .toContain(`url('http://base.url/deploy/assets/component-img-absolute.svg')`); }), // Check urls with deploy-url and base-href scheme only use deploy-url. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, { + concatMap(() => runTargetSpec(host, browserTargetSpec, { extractCss: true, baseHref: 'http://base.url/', deployUrl: 'http://deploy.url/', @@ -479,7 +479,7 @@ describe('Browser Builder styles', () => { expect(main).toContain(`url('http://deploy.url/assets/component-img-absolute.svg')`); }), // Check with schemeless base-href and deploy-url flags. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { extractCss: true, baseHref: '/base/', deployUrl: 'deploy/' }, )), tap(() => { @@ -491,7 +491,7 @@ describe('Browser Builder styles', () => { expect(main).toContain(`url('/base/deploy/assets/component-img-absolute.svg')`); }), // Check with identical base-href and deploy-url flags. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { extractCss: true, baseHref: '/base/', deployUrl: '/base/' }, )), tap(() => { @@ -503,7 +503,7 @@ describe('Browser Builder styles', () => { expect(main).toContain(`url('/base/assets/component-img-absolute.svg')`); }), // Check with only base-href flag. - concatMap(() => runTargetSpec(workspaceRoot, host, browserTargetSpec, + concatMap(() => runTargetSpec(host, browserTargetSpec, { extractCss: true, baseHref: '/base/' }, )), tap(() => { @@ -524,7 +524,7 @@ describe('Browser Builder styles', () => { scripts: ['../../../../node_modules/bootstrap/dist/js/bootstrap.js'], }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); diff --git a/packages/angular_devkit/build_angular/test/browser/subresource-integrity_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/subresource-integrity_spec_large.ts index 9b47d87c28..7ecffe4a88 100644 --- a/packages/angular_devkit/build_angular/test/browser/subresource-integrity_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/subresource-integrity_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder subresource integrity', () => { @@ -26,7 +26,7 @@ describe('Browser Builder subresource integrity', () => { const overrides = { subresourceIntegrity: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'index.html'); diff --git a/packages/angular_devkit/build_angular/test/browser/tsconfig-paths_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/tsconfig-paths_spec_large.ts index ee565f6368..ea222e187f 100644 --- a/packages/angular_devkit/build_angular/test/browser/tsconfig-paths_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/tsconfig-paths_spec_large.ts @@ -8,7 +8,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder tsconfig paths', () => { @@ -26,7 +26,7 @@ describe('Browser Builder tsconfig paths', () => { }, `); - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -68,7 +68,7 @@ describe('Browser Builder tsconfig paths', () => { console.log(meaning5) `); - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); diff --git a/packages/angular_devkit/build_angular/test/browser/vendor-chunk_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/vendor-chunk_spec_large.ts index 8f852678ee..fbd50c5b2b 100644 --- a/packages/angular_devkit/build_angular/test/browser/vendor-chunk_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/vendor-chunk_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder vendor chunk', () => { @@ -21,7 +21,7 @@ describe('Browser Builder vendor chunk', () => { it('works', (done) => { const overrides = { vendorChunk: true }; - runTargetSpec(workspaceRoot, host, browserTargetSpec, overrides).pipe( + runTargetSpec(host, browserTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = join(outputPath, 'vendor.js'); diff --git a/packages/angular_devkit/build_angular/test/browser/works_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/works_spec_large.ts index af589d74d9..4db4989456 100644 --- a/packages/angular_devkit/build_angular/test/browser/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/works_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, browserTargetSpec, host, workspaceRoot } from '../utils'; +import { Timeout, browserTargetSpec, host } from '../utils'; describe('Browser Builder basic test', () => { @@ -19,7 +19,7 @@ describe('Browser Builder basic test', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(workspaceRoot, host, browserTargetSpec).pipe( + runTargetSpec(host, browserTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { // Default files should be in outputPath. diff --git a/packages/angular_devkit/build_angular/test/dev-server/proxy_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/proxy_spec_large.ts index 79011b20c8..54bec1016f 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/proxy_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/proxy_spec_large.ts @@ -12,7 +12,7 @@ import * as http from 'http'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; import { DevServerBuilderOptions } from '../../src'; -import { devServerTargetSpec, host, workspaceRoot } from '../utils'; +import { devServerTargetSpec, host } from '../utils'; describe('Dev Server Builder proxy', () => { @@ -40,7 +40,7 @@ describe('Dev Server Builder proxy', () => { const overrides: Partial = { proxyConfig: 'proxy.config.json' }; - runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( + runTargetSpec(host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/api/test'))), tap(response => { @@ -54,7 +54,7 @@ describe('Dev Server Builder proxy', () => { it('errors out with a missing proxy file', (done) => { const overrides: Partial = { proxyConfig: '../proxy.config.json' }; - runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides) + runTargetSpec(host, devServerTargetSpec, overrides) .subscribe(undefined, () => done(), done.fail); }, 30000); }); diff --git a/packages/angular_devkit/build_angular/test/dev-server/public-host_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/public-host_spec_large.ts index 7e8d82ca7d..6f626c56e7 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/public-host_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/public-host_spec_large.ts @@ -10,7 +10,7 @@ import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; import { DevServerBuilderOptions } from '../../src'; -import { devServerTargetSpec, host, workspaceRoot } from '../utils'; +import { devServerTargetSpec, host } from '../utils'; describe('Dev Server Builder public host', () => { @@ -22,7 +22,7 @@ describe('Dev Server Builder public host', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(workspaceRoot, host, devServerTargetSpec).pipe( + runTargetSpec(host, devServerTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/', headers))), tap(response => expect(response).toContain('Invalid Host header')), @@ -33,7 +33,7 @@ describe('Dev Server Builder public host', () => { it('works', (done) => { const overrides: Partial = { publicHost: headers.host }; - runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( + runTargetSpec(host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/', headers))), tap(response => expect(response).toContain('HelloWorldApp')), @@ -44,7 +44,7 @@ describe('Dev Server Builder public host', () => { it('works', (done) => { const overrides: Partial = { disableHostCheck: true }; - runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( + runTargetSpec(host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/', headers))), tap(response => expect(response).toContain('HelloWorldApp')), diff --git a/packages/angular_devkit/build_angular/test/dev-server/serve-path_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/serve-path_spec_large.ts index efcb8a322f..fa8e36dced 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/serve-path_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/serve-path_spec_large.ts @@ -10,7 +10,7 @@ import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; import { DevServerBuilderOptions } from '../../src'; -import { devServerTargetSpec, host, workspaceRoot } from '../utils'; +import { devServerTargetSpec, host } from '../utils'; describe('Dev Server Builder serve path', () => { @@ -21,7 +21,7 @@ describe('Dev Server Builder serve path', () => { it('works', (done) => { const overrides: Partial = { servePath: 'test/' }; - runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( + runTargetSpec(host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/test/'))), tap(response => expect(response).toContain('HelloWorldApp')), diff --git a/packages/angular_devkit/build_angular/test/dev-server/ssl_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/ssl_spec_large.ts index 718c930974..9092f386d0 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/ssl_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/ssl_spec_large.ts @@ -11,7 +11,7 @@ import { tags } from '@angular-devkit/core'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; import { DevServerBuilderOptions } from '../../src'; -import { devServerTargetSpec, host, workspaceRoot } from '../utils'; +import { devServerTargetSpec, host } from '../utils'; describe('Dev Server Builder ssl', () => { @@ -21,7 +21,7 @@ describe('Dev Server Builder ssl', () => { it('works', (done) => { const overrides: Partial = { ssl: true }; - runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( + runTargetSpec(host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('https://localhost:4200/index.html'))), tap(response => expect(response).toContain('HelloWorldApp')), @@ -93,7 +93,7 @@ describe('Dev Server Builder ssl', () => { sslCert: '../ssl/server.crt', }; - runTargetSpec(workspaceRoot, host, devServerTargetSpec, overrides).pipe( + runTargetSpec(host, devServerTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('https://localhost:4200/index.html'))), tap(response => expect(response).toContain('HelloWorldApp')), diff --git a/packages/angular_devkit/build_angular/test/dev-server/works_spec_large.ts b/packages/angular_devkit/build_angular/test/dev-server/works_spec_large.ts index 9f141db9bb..1d7b00eb49 100644 --- a/packages/angular_devkit/build_angular/test/dev-server/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/dev-server/works_spec_large.ts @@ -9,7 +9,7 @@ import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; -import { devServerTargetSpec, host, workspaceRoot } from '../utils'; +import { devServerTargetSpec, host } from '../utils'; describe('Dev Server Builder', () => { @@ -17,7 +17,7 @@ describe('Dev Server Builder', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(workspaceRoot, host, devServerTargetSpec).pipe( + runTargetSpec(host, devServerTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:4200/index.html'))), tap(response => expect(response).toContain('HelloWorldApp')), diff --git a/packages/angular_devkit/build_angular/test/extract-i18n/works_spec_large.ts b/packages/angular_devkit/build_angular/test/extract-i18n/works_spec_large.ts index bd2ef62582..b45a12a549 100644 --- a/packages/angular_devkit/build_angular/test/extract-i18n/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/extract-i18n/works_spec_large.ts @@ -9,7 +9,7 @@ import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { extractI18nTargetSpec, host, workspaceRoot } from '../utils'; +import { extractI18nTargetSpec, host } from '../utils'; describe('Extract i18n Target', () => { @@ -21,7 +21,7 @@ describe('Extract i18n Target', () => { it('works', (done) => { host.appendToFile('src/app/app.component.html', '

i18n test

'); - runTargetSpec(workspaceRoot, host, extractI18nTargetSpec).pipe( + runTargetSpec(host, extractI18nTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists((extractionFile))).toBe(true); @@ -36,7 +36,7 @@ describe('Extract i18n Target', () => { host.appendToFile('src/app/app.component.html', '

Hello world inner

'); - runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, {}, logger).pipe( + runTargetSpec(host, extractI18nTargetSpec, {}, logger).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(false); const msg = 'Could not mark an element as translatable inside a translatable section'; @@ -49,7 +49,7 @@ describe('Extract i18n Target', () => { host.appendToFile('src/app/app.component.html', '

i18n test

'); const overrides = { i18nLocale: 'fr' }; - runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, overrides).pipe( + runTargetSpec(host, extractI18nTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists((extractionFile))).toBe(true); @@ -65,7 +65,7 @@ describe('Extract i18n Target', () => { const extractionFile = join(normalize('src'), outFile); const overrides = { outFile }; - runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, overrides).pipe( + runTargetSpec(host, extractI18nTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(extractionFile)).toBe(true); @@ -82,7 +82,7 @@ describe('Extract i18n Target', () => { const extractionFile = join(normalize('src'), outputPath, 'messages.xlf'); const overrides = { outputPath }; - runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, overrides).pipe( + runTargetSpec(host, extractI18nTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(extractionFile)).toBe(true); @@ -97,7 +97,7 @@ describe('Extract i18n Target', () => { const extractionFile = join(normalize('src'), 'messages.xmb'); const overrides = { i18nFormat: 'xmb' }; - runTargetSpec(workspaceRoot, host, extractI18nTargetSpec, overrides).pipe( + runTargetSpec(host, extractI18nTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(host.scopedSync().exists(extractionFile)).toBe(true); diff --git a/packages/angular_devkit/build_angular/test/karma/assets_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/assets_spec_large.ts index a7ee0e920b..e5ec2bd749 100644 --- a/packages/angular_devkit/build_angular/test/karma/assets_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/assets_spec_large.ts @@ -8,7 +8,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { host, karmaTargetSpec, workspaceRoot } from '../utils'; +import { host, karmaTargetSpec } from '../utils'; describe('Karma Builder assets', () => { @@ -100,7 +100,7 @@ describe('Karma Builder assets', () => { ], }; - runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( + runTargetSpec(host, karmaTargetSpec, overrides).pipe( tap(buildEvent => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 45000); diff --git a/packages/angular_devkit/build_angular/test/karma/code-coverage_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/code-coverage_spec_large.ts index 67aef82541..9ed27f9926 100644 --- a/packages/angular_devkit/build_angular/test/karma/code-coverage_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/code-coverage_spec_large.ts @@ -10,7 +10,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { debounceTime, tap } from 'rxjs/operators'; import { NormalizedKarmaBuilderSchema } from '../../src'; -import { host, karmaTargetSpec, workspaceRoot } from '../utils'; +import { host, karmaTargetSpec } from '../utils'; describe('Karma Builder code coverage', () => { @@ -22,7 +22,7 @@ describe('Karma Builder code coverage', () => { it('works', (done) => { const overrides: Partial = { codeCoverage: true }; - runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( + runTargetSpec(host, karmaTargetSpec, overrides).pipe( // It seems like the coverage files take a while being written to disk, so we wait 500ms here. debounceTime(500), tap(buildEvent => { @@ -44,7 +44,7 @@ describe('Karma Builder code coverage', () => { ], }; - runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( + runTargetSpec(host, karmaTargetSpec, overrides).pipe( // It seems like the coverage files take a while being written to disk, so we wait 500ms here. debounceTime(500), tap(buildEvent => { diff --git a/packages/angular_devkit/build_angular/test/karma/rebuilds_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/rebuilds_spec_large.ts index 33d652d339..8fdf7b8636 100644 --- a/packages/angular_devkit/build_angular/test/karma/rebuilds_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/rebuilds_spec_large.ts @@ -8,7 +8,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { debounceTime, take, tap } from 'rxjs/operators'; -import { host, karmaTargetSpec, workspaceRoot } from '../utils'; +import { host, karmaTargetSpec } from '../utils'; // Karma watch mode is currently bugged: @@ -21,7 +21,7 @@ xdescribe('Karma Builder watch mode', () => { it('works', (done) => { const overrides = { watch: true }; - runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( + runTargetSpec(host, karmaTargetSpec, overrides).pipe( debounceTime(500), tap((buildEvent) => expect(buildEvent.success).toBe(true)), take(1), @@ -32,7 +32,7 @@ xdescribe('Karma Builder watch mode', () => { const overrides = { watch: true }; let buildNumber = 0; - runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( + runTargetSpec(host, karmaTargetSpec, overrides).pipe( debounceTime(500), tap((buildEvent) => { buildNumber += 1; diff --git a/packages/angular_devkit/build_angular/test/karma/replacements_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/replacements_spec_large.ts index 47d004a3f9..0359881aca 100644 --- a/packages/angular_devkit/build_angular/test/karma/replacements_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/replacements_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { host, karmaTargetSpec, workspaceRoot } from '../utils'; +import { host, karmaTargetSpec } from '../utils'; describe('Karma Builder file replacements', () => { @@ -39,7 +39,7 @@ describe('Karma Builder file replacements', () => { }], }; - runTargetSpec(workspaceRoot, host, karmaTargetSpec, overrides).pipe( + runTargetSpec(host, karmaTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); diff --git a/packages/angular_devkit/build_angular/test/karma/works_spec_large.ts b/packages/angular_devkit/build_angular/test/karma/works_spec_large.ts index d461b6af1c..760ab692cb 100644 --- a/packages/angular_devkit/build_angular/test/karma/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/karma/works_spec_large.ts @@ -8,7 +8,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { tap } from 'rxjs/operators'; -import { host, karmaTargetSpec, workspaceRoot } from '../utils'; +import { host, karmaTargetSpec } from '../utils'; describe('Karma Builder', () => { @@ -16,7 +16,7 @@ describe('Karma Builder', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('runs', (done) => { - runTargetSpec(workspaceRoot, host, karmaTargetSpec).pipe( + runTargetSpec(host, karmaTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -25,14 +25,14 @@ describe('Karma Builder', () => { host.writeMultipleFiles({ 'src/app/app.component.spec.ts': '

definitely not typescript

', }); - runTargetSpec(workspaceRoot, host, karmaTargetSpec).pipe( + runTargetSpec(host, karmaTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), ).subscribe(undefined, done.fail, done); }, 30000); it('supports ES2015 target', (done) => { host.replaceInFile('tsconfig.json', '"target": "es5"', '"target": "es2015"'); - runTargetSpec(workspaceRoot, host, karmaTargetSpec).pipe( + runTargetSpec(host, karmaTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); diff --git a/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts b/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts index 4a9a3c2fc9..47cf54a0c0 100644 --- a/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/protractor/works_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize } from '@angular-devkit/core'; import { retry } from 'rxjs/operators'; -import { host, protractorTargetSpec, workspaceRoot } from '../utils'; +import { host, protractorTargetSpec } from '../utils'; // TODO: replace this with an "it()" macro that's reusable globally. @@ -24,7 +24,7 @@ describe('Protractor Builder', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); linuxOnlyIt('works', (done) => { - runTargetSpec(workspaceRoot, host, protractorTargetSpec).pipe( + runTargetSpec(host, protractorTargetSpec).pipe( retry(3), ).subscribe(undefined, done.fail, done); }, 30000); @@ -32,7 +32,7 @@ describe('Protractor Builder', () => { linuxOnlyIt('works with no devServerTarget', (done) => { const overrides = { devServerTarget: undefined }; - runTargetSpec(workspaceRoot, host, protractorTargetSpec, overrides).pipe( + runTargetSpec(host, protractorTargetSpec, overrides).pipe( // This should fail because no server is available for connection. ).subscribe(undefined, () => done(), done.fail); }, 30000); @@ -43,7 +43,7 @@ describe('Protractor Builder', () => { const overrides = { specs: ['./e2e/renamed-app.e2e-spec.ts'] }; - runTargetSpec(workspaceRoot, host, protractorTargetSpec, overrides).pipe( + runTargetSpec(host, protractorTargetSpec, overrides).pipe( retry(3), ).subscribe(undefined, done.fail, done); }, 60000); @@ -62,7 +62,7 @@ describe('Protractor Builder', () => { const overrides = { suite: 'app' }; - runTargetSpec(workspaceRoot, host, protractorTargetSpec, overrides).pipe( + runTargetSpec(host, protractorTargetSpec, overrides).pipe( retry(3), ).subscribe(undefined, done.fail, done); }, 60000); diff --git a/packages/angular_devkit/build_angular/test/server/base_spec_large.ts b/packages/angular_devkit/build_angular/test/server/base_spec_large.ts index b6aa815e9f..6cbaad969d 100644 --- a/packages/angular_devkit/build_angular/test/server/base_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/server/base_spec_large.ts @@ -9,7 +9,7 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { Timeout, host, workspaceRoot } from '../utils'; +import { Timeout, host } from '../utils'; describe('Server Builder', () => { @@ -21,7 +21,7 @@ describe('Server Builder', () => { it('works (base)', (done) => { const overrides = { }; - runTargetSpec(workspaceRoot, host, { project: 'app', target: 'server' }, overrides).pipe( + runTargetSpec(host, { project: 'app', target: 'server' }, overrides).pipe( tap((buildEvent) => { expect(buildEvent.success).toBe(true); diff --git a/packages/angular_devkit/build_angular/test/tslint/works_spec_large.ts b/packages/angular_devkit/build_angular/test/tslint/works_spec_large.ts index 4056c8ecf8..28ed9b2a24 100644 --- a/packages/angular_devkit/build_angular/test/tslint/works_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/tslint/works_spec_large.ts @@ -10,7 +10,7 @@ import { TestLogger, runTargetSpec } from '@angular-devkit/architect/testing'; import { normalize, virtualFs } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; import { TslintBuilderOptions } from '../../src'; -import { host, tslintTargetSpec, workspaceRoot } from '../utils'; +import { host, tslintTargetSpec } from '../utils'; describe('Tslint Target', () => { @@ -20,7 +20,7 @@ describe('Tslint Target', () => { afterEach(done => host.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(workspaceRoot, host, tslintTargetSpec).pipe( + runTargetSpec(host, tslintTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -29,7 +29,7 @@ describe('Tslint Target', () => { host.writeMultipleFiles(filesWithErrors); const overrides: Partial = { exclude: ['**/foo.ts'] }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( + runTargetSpec(host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -38,7 +38,7 @@ describe('Tslint Target', () => { host.writeMultipleFiles(filesWithErrors); const overrides: Partial = { fix: true }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( + runTargetSpec(host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { const fileName = normalize('src/foo.ts'); @@ -53,7 +53,7 @@ describe('Tslint Target', () => { const logger = new TestLogger('lint-force'); const overrides: Partial = { force: true }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides, logger).pipe( + runTargetSpec(host, tslintTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { expect(logger.includes(`" should be '`)).toBe(true); @@ -67,7 +67,7 @@ describe('Tslint Target', () => { const logger = new TestLogger('lint-format'); const overrides: Partial = { format: 'stylish' }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides, logger).pipe( + runTargetSpec(host, tslintTargetSpec, overrides, logger).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), tap(() => { expect(logger.includes(`quotemark`)).toBe(true); @@ -91,7 +91,7 @@ describe('Tslint Target', () => { }); const overrides: Partial = { tslintConfig: undefined }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( + runTargetSpec(host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(false)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -112,7 +112,7 @@ describe('Tslint Target', () => { }); const overrides: Partial = { tslintConfig: 'tslint.json' }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( + runTargetSpec(host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -123,7 +123,7 @@ describe('Tslint Target', () => { files: ['src/app/**/*.ts'], }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( + runTargetSpec(host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -133,7 +133,7 @@ describe('Tslint Target', () => { tsConfig: 'src/tsconfig.app.json', }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( + runTargetSpec(host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -143,7 +143,7 @@ describe('Tslint Target', () => { tsConfig: ['src/tsconfig.app.json'], }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( + runTargetSpec(host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -153,7 +153,7 @@ describe('Tslint Target', () => { tsConfig: ['src/tsconfig.app.json', 'src/tsconfig.spec.json'], }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides).pipe( + runTargetSpec(host, tslintTargetSpec, overrides).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, 30000); @@ -164,7 +164,7 @@ describe('Tslint Target', () => { typeCheck: true, }; - runTargetSpec(workspaceRoot, host, tslintTargetSpec, overrides) + runTargetSpec(host, tslintTargetSpec, overrides) .subscribe(undefined, () => done(), done.fail); }, 30000); }); diff --git a/packages/angular_devkit/build_angular/test/utils.ts b/packages/angular_devkit/build_angular/test/utils.ts index ef4f819b84..3eaa672bf6 100644 --- a/packages/angular_devkit/build_angular/test/utils.ts +++ b/packages/angular_devkit/build_angular/test/utils.ts @@ -11,8 +11,7 @@ import { join, normalize } from '@angular-devkit/core'; const devkitRoot = normalize((global as any)._DevKitRoot); // tslint:disable-line:no-any -export const workspaceRoot = join(devkitRoot, - 'tests/@angular_devkit/build_angular/hello-world-app/'); +const workspaceRoot = join(devkitRoot, 'tests/@angular_devkit/build_angular/hello-world-app/'); export const host = new TestProjectHost(workspaceRoot); export const outputPath = normalize('dist'); diff --git a/packages/angular_devkit/build_ng_packagr/src/build/index_spec_large.ts b/packages/angular_devkit/build_ng_packagr/src/build/index_spec_large.ts index 62db4a7389..cd8dee6ded 100644 --- a/packages/angular_devkit/build_ng_packagr/src/build/index_spec_large.ts +++ b/packages/angular_devkit/build_ng_packagr/src/build/index_spec_large.ts @@ -28,10 +28,13 @@ export enum Timeout { } describe('NgPackagr Builder', () => { + beforeEach(done => host.initialize().subscribe(undefined, done.fail, done)); + afterEach(done => host.restore().subscribe(undefined, done.fail, done)); + linuxOnlyIt('works', (done) => { const targetSpec: TargetSpecifier = { project: 'lib', target: 'build' }; - runTargetSpec(workspaceRoot, host, targetSpec).pipe( + runTargetSpec(host, targetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); @@ -39,7 +42,7 @@ describe('NgPackagr Builder', () => { linuxOnlyIt('tests works', (done) => { const targetSpec: TargetSpecifier = { project: 'lib', target: 'test' }; - runTargetSpec(workspaceRoot, host, targetSpec).pipe( + runTargetSpec(host, targetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Standard); @@ -47,7 +50,7 @@ describe('NgPackagr Builder', () => { it('lint works', (done) => { const targetSpec: TargetSpecifier = { project: 'lib', target: 'lint' }; - runTargetSpec(workspaceRoot, host, targetSpec).pipe( + runTargetSpec(host, targetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), ).subscribe(undefined, done.fail, done); }, Timeout.Basic); diff --git a/packages/angular_devkit/build_webpack/src/test-utils.ts b/packages/angular_devkit/build_webpack/src/test-utils.ts index 0082101d1c..78ff4a1dde 100644 --- a/packages/angular_devkit/build_webpack/src/test-utils.ts +++ b/packages/angular_devkit/build_webpack/src/test-utils.ts @@ -11,8 +11,7 @@ import { join, normalize } from '@angular-devkit/core'; const devkitRoot = normalize((global as any)._DevKitRoot); // tslint:disable-line:no-any -export const basicWorkspaceRoot = join(devkitRoot, - 'tests/@angular_devkit/build_webpack/basic-app/'); +const basicWorkspaceRoot = join(devkitRoot, 'tests/@angular_devkit/build_webpack/basic-app/'); export const basicHost = new TestProjectHost(basicWorkspaceRoot); -export const workspaceRoot = join(devkitRoot, 'tests/@angular_devkit/build_webpack/angular-app/'); -export const host = new TestProjectHost(workspaceRoot); +const angularWorkspaceRoot = join(devkitRoot, 'tests/@angular_devkit/build_webpack/angular-app/'); +export const angularHost = new TestProjectHost(angularWorkspaceRoot); diff --git a/packages/angular_devkit/build_webpack/src/webpack-dev-server/index_spec_large.ts b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index_spec_large.ts index fca1849193..93c8a08567 100644 --- a/packages/angular_devkit/build_webpack/src/webpack-dev-server/index_spec_large.ts +++ b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index_spec_large.ts @@ -9,17 +9,17 @@ import { request, runTargetSpec } from '@angular-devkit/architect/testing'; import { from } from 'rxjs'; import { concatMap, take, tap } from 'rxjs/operators'; -import { host, workspaceRoot } from '../test-utils'; +import { basicHost } from '../test-utils'; describe('Dev Server Builder', () => { const webpackTargetSpec = { project: 'app', target: 'serve' }; - beforeEach(done => host.initialize().subscribe(undefined, done.fail, done)); - afterEach(done => host.restore().subscribe(undefined, done.fail, done)); + beforeEach(done => basicHost.initialize().subscribe(undefined, done.fail, done)); + afterEach(done => basicHost.restore().subscribe(undefined, done.fail, done)); it('works', (done) => { - runTargetSpec(workspaceRoot, host, webpackTargetSpec).pipe( + runTargetSpec(basicHost, webpackTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), concatMap(() => from(request('http://localhost:8080/bundle.js'))), tap(response => expect(response).toContain(`console.log('hello world')`)), diff --git a/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts index 03d842b611..42b5a4c1d7 100644 --- a/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts +++ b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts @@ -9,38 +9,45 @@ import { runTargetSpec } from '@angular-devkit/architect/testing'; import { join, normalize } from '@angular-devkit/core'; import { tap } from 'rxjs/operators'; -import { basicHost, basicWorkspaceRoot, host, workspaceRoot } from '../test-utils'; +import { angularHost, basicHost } from '../test-utils'; describe('Webpack Builder basic test', () => { const outputPath = normalize('dist'); const webpackTargetSpec = { project: 'app', target: 'build' }; - beforeEach(done => host.initialize().subscribe(undefined, done.fail, done)); - afterEach(done => host.restore().subscribe(undefined, done.fail, done)); + describe('basic app', () => { + beforeEach(done => basicHost.initialize().subscribe(undefined, done.fail, done)); + afterEach(done => basicHost.restore().subscribe(undefined, done.fail, done)); - it('works with a basic webpack app', (done) => { - runTargetSpec(basicWorkspaceRoot, basicHost, webpackTargetSpec).pipe( - tap((buildEvent) => expect(buildEvent.success).toBe(true)), - tap(() => { - expect(host.scopedSync().exists(join(outputPath, 'bundle.js'))).toBe(true); - }), - ).subscribe(undefined, done.fail, done); - }, 30000); + it('works', (done) => { + runTargetSpec(basicHost, webpackTargetSpec).pipe( + tap((buildEvent) => expect(buildEvent.success).toBe(true)), + tap(() => { + expect(basicHost.scopedSync().exists(join(outputPath, 'bundle.js'))).toBe(true); + }), + ).subscribe(undefined, done.fail, done); + }, 30000); + }); - it('works with a Angular app', (done) => { - runTargetSpec(workspaceRoot, host, webpackTargetSpec, {}).pipe( - tap((buildEvent) => expect(buildEvent.success).toBe(true)), - tap(() => { - // Default files should be in outputPath. - // expect(host.scopedSync().exists(join(outputPath, 'runtime.js'))).toBe(true); - expect(host.scopedSync().exists(join(outputPath, 'main.js'))).toBe(true); - expect(host.scopedSync().exists(join(outputPath, 'polyfills.js'))).toBe(true); - // expect(host.scopedSync().exists(join(outputPath, 'styles.js'))).toBe(true); - // expect(host.scopedSync().exists(join(outputPath, 'vendor.js'))).toBe(true); - // expect(host.scopedSync().exists(join(outputPath, 'favicon.ico'))).toBe(true); - // expect(host.scopedSync().exists(join(outputPath, 'index.html'))).toBe(true); - }), - ).subscribe(undefined, done.fail, done); - }, 30000); + describe('Angular app', () => { + beforeEach(done => angularHost.initialize().subscribe(undefined, done.fail, done)); + afterEach(done => angularHost.restore().subscribe(undefined, done.fail, done)); + + it('works with a Angular app', (done) => { + runTargetSpec(angularHost, webpackTargetSpec, {}).pipe( + tap((buildEvent) => expect(buildEvent.success).toBe(true)), + tap(() => { + // Default files should be in outputPath. + // expect(host.scopedSync().exists(join(outputPath, 'runtime.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'main.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'polyfills.js'))).toBe(true); + // expect(host.scopedSync().exists(join(outputPath, 'styles.js'))).toBe(true); + // expect(host.scopedSync().exists(join(outputPath, 'vendor.js'))).toBe(true); + // expect(host.scopedSync().exists(join(outputPath, 'favicon.ico'))).toBe(true); + // expect(host.scopedSync().exists(join(outputPath, 'index.html'))).toBe(true); + }), + ).subscribe(undefined, done.fail, done); + }, 30000); + }); }); From 83494cab4d3b35cf90202f4954bbe2827bfb04c8 Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Wed, 16 May 2018 15:27:21 +0100 Subject: [PATCH 6/9] refactor(@angular-devkit/build-angular): clean old CLI code Refactored code to be used by build-webpack test and eject command schematic. --- package-lock.json | 330 +++++++++++------- package.json | 2 + .../angular_devkit/build_angular/package.json | 1 - .../build_angular/plugins/webpack.ts | 9 + .../angular-cli-files/models/build-options.ts | 4 +- .../models/webpack-configs/browser.ts | 94 ++--- .../models/webpack-configs/common.ts | 81 ++--- .../models/webpack-configs/styles.ts | 204 +++-------- .../models/webpack-configs/utils.ts | 14 +- .../src/angular-cli-files/plugins/webpack.ts | 4 +- ...chunk-sort.ts => generate-entry-points.ts} | 31 +- .../utilities/postcss-plugins-factory.ts | 139 ++++++++ .../src/webpack/index_spec_large.ts | 37 +- tsconfig.json | 1 + 14 files changed, 504 insertions(+), 447 deletions(-) create mode 100644 packages/angular_devkit/build_angular/plugins/webpack.ts rename packages/angular_devkit/build_angular/src/angular-cli-files/utilities/{package-chunk-sort.ts => generate-entry-points.ts} (50%) create mode 100644 packages/angular_devkit/build_angular/src/angular-cli-files/utilities/postcss-plugins-factory.ts diff --git a/package-lock.json b/package-lock.json index da25cbc3f3..589ea96701 100644 --- a/package-lock.json +++ b/package-lock.json @@ -150,6 +150,64 @@ "@types/estree": "0.0.39" } }, + "@types/autoprefixer": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@types/autoprefixer/-/autoprefixer-6.7.3.tgz", + "integrity": "sha512-1iqqxR9rcUsTrngdea+dpGP3/iuokNnsGYmgXsclJ6iPJ79gqCcYuJAR1AyQRKUVpikxBZBjJKFzStJAlSWMvw==", + "requires": { + "postcss": "5.2.18" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "requires": { + "chalk": "1.1.3", + "js-base64": "2.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "requires": { + "has-flag": "1.0.0" + } + } + } + }, "@types/body-parser": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz", @@ -364,6 +422,14 @@ } } }, + "@types/uglifyjs-webpack-plugin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.1.0.tgz", + "integrity": "sha512-QoCJYq+zNtuvKw4nutaIxQXKBpvc0Hd6U7BUVi2Cest2FrkGTYDBD6YpSq5d9IHjo94SjXk+6KDqQVOcEzFJZA==", + "requires": { + "@types/webpack": "4.1.4" + } + }, "@types/webpack": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.1.4.tgz", @@ -5017,10 +5083,10 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" } } } @@ -6064,7 +6130,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", "requires": { - "lodash": "^4.14.0" + "lodash": "4.17.10" } } } @@ -7357,9 +7423,9 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "load-json-file": "4.0.0", + "normalize-package-data": "2.4.0", + "path-type": "3.0.0" } }, "read-pkg-up": { @@ -7367,8 +7433,8 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" + "find-up": "2.1.0", + "read-pkg": "3.0.0" } }, "rxjs": { @@ -7560,11 +7626,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "cryptiles": { @@ -7590,10 +7656,10 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" + "chalk": "1.1.3", + "commander": "2.15.1", + "is-my-json-valid": "2.17.2", + "pinkie-promise": "2.0.1" } }, "hawk": { @@ -7671,26 +7737,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~2.0.6", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "qs": "~6.3.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "~0.4.1", - "uuid": "^3.0.0" + "aws-sign2": "0.6.0", + "aws4": "1.7.0", + "caseless": "0.11.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "qs": "6.3.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.4.3", + "uuid": "3.2.1" } }, "sntp": { @@ -11283,16 +11349,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.2", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -11300,7 +11366,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -11310,13 +11376,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -11324,7 +11390,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -11332,7 +11398,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -11340,7 +11406,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -11348,7 +11414,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -11358,7 +11424,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -11366,7 +11432,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -11376,9 +11442,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" } }, "kind-of": { @@ -11393,14 +11459,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -11408,7 +11474,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -11416,7 +11482,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -11426,10 +11492,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -11437,7 +11503,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -11447,7 +11513,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-data-descriptor": { @@ -11455,7 +11521,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.2" } }, "is-descriptor": { @@ -11463,9 +11529,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" } }, "is-number": { @@ -11473,7 +11539,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -11481,7 +11547,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -11501,19 +11567,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } } } @@ -11623,7 +11689,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -11641,12 +11707,12 @@ "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", "requires": { - "globby": "^6.1.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "p-map": "^1.1.1", - "pify": "^3.0.0", - "rimraf": "^2.2.8" + "globby": "6.1.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "p-map": "1.2.0", + "pify": "3.0.0", + "rimraf": "2.6.2" } }, "globby": { @@ -11654,11 +11720,11 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" }, "dependencies": { "pify": { @@ -11678,9 +11744,9 @@ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" } }, "string-width": { @@ -11688,8 +11754,8 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" }, "dependencies": { "strip-ansi": { @@ -11697,7 +11763,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "3.0.0" } } } @@ -11717,18 +11783,18 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" + "cliui": "4.1.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" } }, "yargs-parser": { @@ -11736,7 +11802,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "requires": { - "camelcase": "^4.1.0" + "camelcase": "4.1.0" } } } diff --git a/package.json b/package.json index 0e5b25ded2..aceb5cb5aa 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "@angular/router": "6.0.0-rc.5", "@angular/service-worker": "6.0.0-rc.5", "@ngtools/json-schema": "^1.0.9", + "@types/autoprefixer": "^6.7.3", "@types/copy-webpack-plugin": "^4.0.1", "@types/express": "^4.11.1", "@types/glob": "^5.0.29", @@ -77,6 +78,7 @@ "@types/request": "^2.47.0", "@types/semver": "^5.3.30", "@types/source-map": "0.5.2", + "@types/uglifyjs-webpack-plugin": "^1.1.0", "@types/webpack": "^4.1.3", "@types/webpack-dev-server": "^2.9.4", "@types/webpack-sources": "^0.1.4", diff --git a/packages/angular_devkit/build_angular/package.json b/packages/angular_devkit/build_angular/package.json index 88006680c9..b0f96b6478 100644 --- a/packages/angular_devkit/build_angular/package.json +++ b/packages/angular_devkit/build_angular/package.json @@ -23,7 +23,6 @@ "copy-webpack-plugin": "^4.5.1", "file-loader": "^1.1.11", "glob": "^7.0.3", - "html-webpack-plugin": "^3.0.6", "istanbul": "^0.4.5", "istanbul-instrumenter-loader": "^3.0.1", "karma-source-map-support": "^1.2.0", diff --git a/packages/angular_devkit/build_angular/plugins/webpack.ts b/packages/angular_devkit/build_angular/plugins/webpack.ts new file mode 100644 index 0000000000..204cab5f27 --- /dev/null +++ b/packages/angular_devkit/build_angular/plugins/webpack.ts @@ -0,0 +1,9 @@ +/** + * @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 '../src/angular-cli-files/plugins/webpack'; diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts index 26c060e964..1ed05a82f3 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts @@ -10,7 +10,7 @@ // tslint:disable-next-line:no-implicit-dependencies import * as ts from 'typescript'; -import { AssetPatternObject, Budget, ExtraEntryPoint } from '../../browser/schema'; +import { AssetPatternObject, Budget, ExtraEntryPoint, OutputHashing } from '../../browser/schema'; export interface BuildOptions { optimization: boolean; @@ -32,7 +32,7 @@ export interface BuildOptions { extractCss?: boolean; bundleDependencies?: 'none' | 'all'; watch?: boolean; - outputHashing?: string; + outputHashing?: OutputHashing; poll?: number; app?: string; deleteOutputPath?: boolean; diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/browser.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/browser.ts index c4d7460d40..fdee996c1c 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/browser.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/browser.ts @@ -5,61 +5,21 @@ * 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. -import * as path from 'path'; -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const SubresourceIntegrityPlugin = require('webpack-subresource-integrity'); import { LicenseWebpackPlugin } from 'license-webpack-plugin'; -import { generateEntryPoints, packageChunkSort } from '../../utilities/package-chunk-sort'; -import { BaseHrefWebpackPlugin } from '../../lib/base-href-webpack'; -import { IndexHtmlWebpackPlugin } from '../../plugins/index-html-webpack-plugin'; -import { ExtraEntryPoint } from '../../../browser/schema'; -import { BrowserBuilderSchema } from '../../../browser/schema'; +import * as path from 'path'; +import { Plugin } from 'webpack'; +import { IndexHtmlWebpackPlugin } from '../../plugins/webpack'; +import { generateEntryPoints } from '../../utilities/generate-entry-points'; import { WebpackConfigOptions } from '../build-options'; -import { normalizeExtraEntryPoints } from './utils'; +const SubresourceIntegrityPlugin = require('webpack-subresource-integrity'); -/** -+ * license-webpack-plugin has a peer dependency on webpack-sources, list it in a comment to -+ * let the dependency validator know it is used. -+ * -+ * require('webpack-sources') -+ */ export function getBrowserConfig(wco: WebpackConfigOptions) { - const { root, projectRoot, buildOptions } = wco; - - - let extraPlugins: any[] = []; - - // Figure out which are the lazy loaded bundle names. - const lazyChunkBundleNames = normalizeExtraEntryPoints( - // We don't really need a default name because we pre-filtered by lazy only entries. - [...buildOptions.styles, ...buildOptions.scripts], 'not-lazy') - .filter(entry => entry.lazy) - .map(entry => entry.bundleName) - - const generateIndexHtml = false; - if (generateIndexHtml) { - extraPlugins.push(new HtmlWebpackPlugin({ - template: path.resolve(root, buildOptions.index), - filename: path.resolve(buildOptions.outputPath, buildOptions.index), - chunksSortMode: packageChunkSort(buildOptions), - excludeChunks: lazyChunkBundleNames, - xhtml: true, - minify: buildOptions.optimization ? { - caseSensitive: true, - collapseWhitespace: true, - keepClosingSlash: true - } : false - })); - extraPlugins.push(new BaseHrefWebpackPlugin({ - baseHref: buildOptions.baseHref as string - })); - } - + const { root, buildOptions } = wco; + const extraPlugins: Plugin[] = []; let sourcemaps: string | false = false; + if (buildOptions.sourceMap) { // See https://webpack.js.org/configuration/devtool/ for sourcemap types. if (buildOptions.evalSourceMap && !buildOptions.optimization) { @@ -73,32 +33,36 @@ export function getBrowserConfig(wco: WebpackConfigOptions) { if (buildOptions.subresourceIntegrity) { extraPlugins.push(new SubresourceIntegrityPlugin({ - hashFuncNames: ['sha384'] + hashFuncNames: ['sha384'], })); } if (buildOptions.extractLicenses) { + /** + * license-webpack-plugin has a peer dependency on webpack-sources, so we list it in a comment + * to let the dependency validator know it is used. + * + * require('webpack-sources') + */ + extraPlugins.push(new LicenseWebpackPlugin({ pattern: /.*/, suppressErrors: true, perChunkOutput: false, - outputFilename: `3rdpartylicenses.txt` + outputFilename: `3rdpartylicenses.txt`, })); } - const globalStylesBundleNames = normalizeExtraEntryPoints(buildOptions.styles, 'styles') - .map(style => style.bundleName); - return { devtool: sourcemaps, resolve: { mainFields: [ ...(wco.supportES2015 ? ['es2015'] : []), - 'browser', 'module', 'main' - ] + 'browser', 'module', 'main', + ], }, output: { - crossOriginLoading: buildOptions.subresourceIntegrity ? 'anonymous' : false + crossOriginLoading: buildOptions.subresourceIntegrity ? 'anonymous' : false, }, optimization: { runtimeChunk: 'single', @@ -122,15 +86,19 @@ export function getBrowserConfig(wco: WebpackConfigOptions) { name: 'vendor', chunks: 'initial', enforce: true, - test: (module: any, chunks: Array<{ name: string }>) => { - const moduleName = module.nameForCondition ? module.nameForCondition() : ''; - return /[\\/]node_modules[\\/]/.test(moduleName) - && !chunks.some(({ name }) => name === 'polyfills' - || globalStylesBundleNames.includes(name)); + test: (module: { nameForCondition?: Function }, chunks: Array<{ name: string }>) => { + if (!module.nameForCondition) { + return false; + } + + // Vendor modules are those that have '/node_modules/' in their path and do not + // contain chunks from either the polyfills or global styles entry points. + return /[\\/]node_modules[\\/]/.test(module.nameForCondition()) + && !chunks.some(({ name }) => name === 'polyfills' || ['styles'].includes(name)); }, }, - } - } + }, + }, }, plugins: extraPlugins.concat([ new IndexHtmlWebpackPlugin({ diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts index dbfe542b03..1283b672bf 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts @@ -5,28 +5,26 @@ * 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. -import * as path from 'path'; -import { HashedModuleIdsPlugin } from 'webpack'; import * as CopyWebpackPlugin from 'copy-webpack-plugin'; -import { getOutputHashFormat } from './utils'; +import * as path from 'path'; +import * as UglifyJSPlugin from 'uglifyjs-webpack-plugin'; +import { Entry, HashedModuleIdsPlugin, Plugin } from 'webpack'; +import { AssetPatternObject } from '../../../browser/schema'; +import { + BundleBudgetPlugin, + CleanCssWebpackPlugin, + ScriptsWebpackPlugin, +} from '../../plugins/webpack'; +import { findUp } from '../../utilities/find-up'; import { isDirectory } from '../../utilities/is-directory'; import { requireProjectModule } from '../../utilities/require-project-module'; import { WebpackConfigOptions } from '../build-options'; -import { BundleBudgetPlugin } from '../../plugins/bundle-budget'; -import { CleanCssWebpackPlugin } from '../../plugins/cleancss-webpack-plugin'; -import { ScriptsWebpackPlugin } from '../../plugins/scripts-webpack-plugin'; -import { findUp } from '../../utilities/find-up'; -import { AssetPatternObject, ExtraEntryPoint } from '../../../browser/schema'; -import { normalizeExtraEntryPoints } from './utils'; +import { getOutputHashFormat, normalizeExtraEntryPoints } from './utils'; const ProgressPlugin = require('webpack/lib/ProgressPlugin'); const CircularDependencyPlugin = require('circular-dependency-plugin'); -const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); const StatsPlugin = require('stats-webpack-plugin'); -const SilentError = require('silent-error'); const resolve = require('resolve'); /** @@ -41,7 +39,7 @@ const resolve = require('resolve'); * require('@angular-devkit/build-optimizer') */ -const g: any = typeof global !== 'undefined' ? global : {}; +const g: any = typeof global !== 'undefined' ? global : {}; // tslint:disable-line:no-any export const buildOptimizerLoader: string = g['_DevKitIsLocal'] ? require.resolve('@angular-devkit/build-optimizer/src/build-optimizer/webpack-loader') : '@angular-devkit/build-optimizer/webpack-loader'; @@ -51,11 +49,11 @@ export function getCommonConfig(wco: WebpackConfigOptions) { const nodeModules = findUp('node_modules', projectRoot); if (!nodeModules) { - throw new Error('Cannot locate node_modules directory.') + throw new Error('Cannot locate node_modules directory.'); } - let extraPlugins: any[] = []; - let entryPoints: { [key: string]: string[] } = {}; + const extraPlugins: Plugin[] = []; + const entryPoints: Entry = {}; if (buildOptions.main) { entryPoints['main'] = [path.resolve(root, buildOptions.main)]; @@ -66,7 +64,7 @@ export function getCommonConfig(wco: WebpackConfigOptions) { } // determine hashing format - const hashFormat = getOutputHashFormat(buildOptions.outputHashing as any); + const hashFormat = getOutputHashFormat(buildOptions.outputHashing); // process global scripts if (buildOptions.scripts.length > 0) { @@ -74,7 +72,7 @@ export function getCommonConfig(wco: WebpackConfigOptions) { .reduce((prev: { bundleName: string, paths: string[], lazy: boolean }[], curr) => { const bundleName = curr.bundleName; const resolvedPath = path.resolve(root, curr.input); - let existingEntry = prev.find((el) => el.bundleName === bundleName); + const existingEntry = prev.find((el) => el.bundleName === bundleName); if (existingEntry) { if (existingEntry.lazy && !curr.lazy) { // All entries have to be lazy for the bundle to be lazy. @@ -87,9 +85,10 @@ export function getCommonConfig(wco: WebpackConfigOptions) { prev.push({ bundleName, paths: [resolvedPath], - lazy: curr.lazy + lazy: curr.lazy, }); } + return prev; }, []); @@ -130,21 +129,14 @@ export function getCommonConfig(wco: WebpackConfigOptions) { to: asset.output.replace(/^\//, ''), from: { glob: asset.glob, - dot: true - } + dot: true, + }, }; }); const copyWebpackPluginOptions = { ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'] }; - const copyWebpackPluginInstance = new CopyWebpackPlugin(copyWebpackPluginPatterns, - copyWebpackPluginOptions); - - // Save options so we can use them in eject. - (copyWebpackPluginInstance as any)['copyWebpackPluginPatterns'] = copyWebpackPluginPatterns; - (copyWebpackPluginInstance as any)['copyWebpackPluginOptions'] = copyWebpackPluginOptions; - - extraPlugins.push(copyWebpackPluginInstance); + extraPlugins.push(new CopyWebpackPlugin(copyWebpackPluginPatterns, copyWebpackPluginOptions)); } if (buildOptions.progress) { @@ -153,7 +145,7 @@ export function getCommonConfig(wco: WebpackConfigOptions) { if (buildOptions.showCircularDependencies) { extraPlugins.push(new CircularDependencyPlugin({ - exclude: /[\\\/]node_modules[\\\/]/ + exclude: /[\\\/]node_modules[\\\/]/, })); } @@ -173,11 +165,11 @@ export function getCommonConfig(wco: WebpackConfigOptions) { use: [ { loader: 'cache-loader', - options: { cacheDirectory } + options: { cacheDirectory }, }, { loader: buildOptimizerLoader, - options: { sourceMap: buildOptions.sourceMap } + options: { sourceMap: buildOptions.sourceMap }, }, ], }; @@ -227,10 +219,10 @@ export function getCommonConfig(wco: WebpackConfigOptions) { // Workaround known uglify-es issue // See https://github.com/mishoo/UglifyJS2/issues/2949#issuecomment-368070307 inline: wco.supportES2015 ? 1 : 3, - } + }, }), // We also want to avoid mangling on server. - ...(buildOptions.platform == 'server' ? { mangle: false } : {}) + ...(buildOptions.platform == 'server' ? { mangle: false } : {}), }; return { @@ -243,21 +235,21 @@ export function getCommonConfig(wco: WebpackConfigOptions) { wco.tsConfig.options.baseUrl || projectRoot, 'node_modules', ], - alias + alias, }, resolveLoader: { - modules: loaderNodeModules + modules: loaderNodeModules, }, context: projectRoot, entry: entryPoints, output: { - path: path.resolve(root, buildOptions.outputPath as string), + path: path.resolve(root, buildOptions.outputPath), publicPath: buildOptions.deployUrl, filename: `[name]${hashFormat.chunk}.js`, }, watch: buildOptions.watch, watchOptions: { - poll: buildOptions.poll + poll: buildOptions.poll, }, performance: { hints: false, @@ -270,16 +262,16 @@ export function getCommonConfig(wco: WebpackConfigOptions) { loader: 'file-loader', options: { name: `[name]${hashFormat.file}.[ext]`, - limit: 10000 - } + limit: 10000, + }, }, { test: /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/, loader: 'url-loader', options: { name: `[name]${hashFormat.file}.[ext]`, - limit: 10000 - } + limit: 10000, + }, }, { // Mark files inside `@angular/core` as using SystemJS style dynamic imports. @@ -291,13 +283,12 @@ export function getCommonConfig(wco: WebpackConfigOptions) { test: /\.js$/, ...buildOptimizerUseRule, }, - ] + ], }, optimization: { noEmitOnErrors: true, minimizer: [ new HashedModuleIdsPlugin(), - // TODO: check with Mike what this feature needs. new BundleBudgetPlugin({ budgets: buildOptions.budgets }), new CleanCssWebpackPlugin({ sourceMap: buildOptions.sourceMap, diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/styles.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/styles.ts index 8345b0accc..7783964aa7 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/styles.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/styles.ts @@ -5,24 +5,19 @@ * 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. -import * as webpack from 'webpack'; import * as path from 'path'; -import { SuppressExtractedTextChunksWebpackPlugin } from '../../plugins/webpack'; -import { getOutputHashFormat } from './utils'; +import * as webpack from 'webpack'; +import { Plugin } from 'webpack'; +import { + RawCssLoader, + SuppressExtractedTextChunksWebpackPlugin, + postcssPluginsFactory, +} from '../../plugins/webpack'; import { WebpackConfigOptions } from '../build-options'; -import { findUp } from '../../utilities/find-up'; -import { RawCssLoader } from '../../plugins/webpack'; -import { ExtraEntryPoint } from '../../../browser/schema'; -import { normalizeExtraEntryPoints } from './utils'; +import { getOutputHashFormat, normalizeExtraEntryPoints } from './utils'; -const postcssUrl = require('postcss-url'); -const autoprefixer = require('autoprefixer'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const postcssImports = require('postcss-import'); -const PostcssCliResources = require('../../plugins/webpack').PostcssCliResources; /** * Enumerate loaders and their dependencies from this file to let the dependency validator @@ -38,123 +33,25 @@ const PostcssCliResources = require('../../plugins/webpack').PostcssCliResources * require('sass-loader') */ -interface PostcssUrlAsset { - url: string; - hash: string; - absolutePath: string; -} - export function getStylesConfig(wco: WebpackConfigOptions) { const { root, projectRoot, buildOptions } = wco; // const appRoot = path.resolve(projectRoot, appConfig.root); const entryPoints: { [key: string]: string[] } = {}; const globalStylePaths: string[] = []; - const extraPlugins: any[] = []; + const extraPlugins: Plugin[] = []; const cssSourceMap = buildOptions.sourceMap; - // Maximum resource size to inline (KiB) - const maximumInlineSize = 10; // Determine hashing format. - const hashFormat = getOutputHashFormat(buildOptions.outputHashing as string); - // Convert absolute resource URLs to account for base-href and deploy-url. - const baseHref = wco.buildOptions.baseHref || ''; - const deployUrl = wco.buildOptions.deployUrl || ''; - - const postcssPluginCreator = function (loader: webpack.loader.LoaderContext) { - return [ - postcssImports({ - resolve: (url: string, context: string) => { - return new Promise((resolve, reject) => { - let hadTilde = false; - if (url && url.startsWith('~')) { - url = url.substr(1); - hadTilde = true; - } - loader.resolve(context, (hadTilde ? '' : './') + url, (err: Error, result: string) => { - if (err) { - if (hadTilde) { - reject(err); - return; - } - loader.resolve(context, url, (err: Error, result: string) => { - if (err) { - reject(err); - } else { - resolve(result); - } - }); - } else { - resolve(result); - } - }); - }); - }, - load: (filename: string) => { - return new Promise((resolve, reject) => { - loader.fs.readFile(filename, (err: Error, data: Buffer) => { - if (err) { - reject(err); - return; - } + const hashFormat = getOutputHashFormat(wco.buildOptions.outputHashing); - const content = data.toString(); - resolve(content); - }); - }); - } - }), - postcssUrl({ - filter: ({ url }: PostcssUrlAsset) => url.startsWith('~'), - url: ({ url }: PostcssUrlAsset) => { - // Note: This will only find the first node_modules folder. - const nodeModules = findUp('node_modules', projectRoot); - if (!nodeModules) { - throw new Error('Cannot locate node_modules directory.') - } - const fullPath = path.join(nodeModules, url.substr(1)); - return path.relative(loader.context, fullPath).replace(/\\/g, '/'); - } - }), - postcssUrl([ - { - // Only convert root relative URLs, which CSS-Loader won't process into require(). - filter: ({ url }: PostcssUrlAsset) => url.startsWith('/') && !url.startsWith('//'), - url: ({ url }: PostcssUrlAsset) => { - if (deployUrl.match(/:\/\//) || deployUrl.startsWith('/')) { - // If deployUrl is absolute or root relative, ignore baseHref & use deployUrl as is. - return `${deployUrl.replace(/\/$/, '')}${url}`; - } else if (baseHref.match(/:\/\//)) { - // If baseHref contains a scheme, include it as is. - return baseHref.replace(/\/$/, '') + - `/${deployUrl}/${url}`.replace(/\/\/+/g, '/'); - } else { - // Join together base-href, deploy-url and the original URL. - // Also dedupe multiple slashes into single ones. - return `/${baseHref}/${deployUrl}/${url}`.replace(/\/\/+/g, '/'); - } - } - }, - { - // TODO: inline .cur if not supporting IE (use browserslist to check) - filter: (asset: PostcssUrlAsset) => { - return maximumInlineSize > 0 && !asset.hash && !asset.absolutePath.endsWith('.cur'); - }, - url: 'inline', - // NOTE: maxSize is in KB - maxSize: maximumInlineSize, - fallback: 'rebase', - }, - { url: 'rebase' }, - ]), - PostcssCliResources({ - deployUrl: loader.loaders[loader.loaderIndex].options.ident == 'extracted' ? '' : deployUrl, - loader, - filename: `[name]${hashFormat.file}.[ext]`, - }), - autoprefixer({ grid: true }), - ]; - }; + // Build PostCSS plugins. + const postCssPlugins = postcssPluginsFactory({ + projectRoot, + deployUrl: wco.buildOptions.deployUrl, + baseHref: wco.buildOptions.baseHref, + outputHashing: buildOptions.outputHashing, + }); // use includePaths from appConfig const includePaths: string[] = []; @@ -178,9 +75,9 @@ export function getStylesConfig(wco: WebpackConfigOptions) { // Add style entry points. if (entryPoints[style.bundleName]) { - entryPoints[style.bundleName].push(resolvedPath) + entryPoints[style.bundleName].push(resolvedPath); } else { - entryPoints[style.bundleName] = [resolvedPath] + entryPoints[style.bundleName] = [resolvedPath]; } // Add global css paths. @@ -198,9 +95,9 @@ export function getStylesConfig(wco: WebpackConfigOptions) { sourceMap: cssSourceMap, // bootstrap-sass requires a minimum precision of 8 precision: 8, - includePaths - } - }] + includePaths, + }, + }], }, { test: /\.less$/, use: [{ @@ -208,18 +105,18 @@ export function getStylesConfig(wco: WebpackConfigOptions) { options: { sourceMap: cssSourceMap, ...lessPathOptions, - } - }] + }, + }], }, { test: /\.styl$/, use: [{ loader: 'stylus-loader', options: { sourceMap: cssSourceMap, - paths: includePaths - } - }] - } + paths: includePaths, + }, + }], + }, ]; // load component css as raw strings @@ -230,51 +127,40 @@ export function getStylesConfig(wco: WebpackConfigOptions) { loader: 'postcss-loader', options: { ident: 'embedded', - plugins: postcssPluginCreator, - sourceMap: cssSourceMap - } + plugins: postCssPlugins, + sourceMap: cssSourceMap, + }, }, - ...(use as webpack.Loader[]) - ] + ...(use as webpack.Loader[]), + ], })); // load global css as css files if (globalStylePaths.length > 0) { rules.push(...baseRules.map(({ test, use }) => { - const extractTextPlugin = { + return { + include: globalStylePaths, + test, use: [ + buildOptions.extractCss ? MiniCssExtractPlugin.loader : 'style-loader', // style-loader still has issues with relative url()'s with sourcemaps enabled; // even with the convertToAbsoluteUrls options as it uses 'document.location' // which breaks when used with routing. // Once style-loader 1.0 is released the following conditional won't be necessary // due to this 1.0 PR: https://github.com/webpack-contrib/style-loader/pull/219 - { loader: buildOptions.extractCss ? RawCssLoader : 'raw-loader' }, + buildOptions.extractCss ? RawCssLoader : 'raw-loader', { loader: 'postcss-loader', options: { + // postcssPluginsFactory contains special logic for 'extracted' ident. ident: buildOptions.extractCss ? 'extracted' : 'embedded', - plugins: postcssPluginCreator, - sourceMap: cssSourceMap - } + plugins: postCssPlugins, + sourceMap: cssSourceMap, + }, }, - ...(use as webpack.Loader[]) + ...(use as webpack.Loader[]), ], - // publicPath needed as a workaround https://github.com/angular/angular-cli/issues/4035 - publicPath: '' - }; - const ret: any = { - include: globalStylePaths, - test, - use: [ - buildOptions.extractCss ? MiniCssExtractPlugin.loader : 'style-loader', - ...extractTextPlugin.use, - ] }; - // Save the original options as arguments for eject. - // if (buildOptions.extractCss) { - // ret[pluginArgs] = extractTextPlugin; - // } - return ret; })); } @@ -287,10 +173,8 @@ export function getStylesConfig(wco: WebpackConfigOptions) { } return { - // Workaround stylus-loader defect: https://github.com/shama/stylus-loader/issues/189 - loader: { stylus: {} }, entry: entryPoints, module: { rules }, - plugins: [].concat(extraPlugins as any) + plugins: extraPlugins, }; } diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/utils.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/utils.ts index f32f3f8afa..3c281818b5 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/utils.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/utils.ts @@ -5,11 +5,9 @@ * 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. -import * as path from 'path'; import { basename, normalize } from '@angular-devkit/core'; +import * as path from 'path'; import { ExtraEntryPoint, ExtraEntryPointObject } from '../../../browser/schema'; export const ngAppResolve = (resolvePath: string): string => { @@ -23,7 +21,7 @@ export interface HashFormat { script: string; } -export function getOutputHashFormat(option: string, length = 20): HashFormat { +export function getOutputHashFormat(option?: string, length = 20): HashFormat { /* tslint:disable:max-line-length */ const hashFormats: { [option: string]: HashFormat } = { none: { chunk: '', extract: '', file: '' , script: '' }, @@ -32,6 +30,10 @@ export function getOutputHashFormat(option: string, length = 20): HashFormat { all: { chunk: `.[chunkhash:${length}]`, extract: `.[contenthash:${length}]`, file: `.[hash:${length}]`, script: `.[hash:${length}]` }, }; /* tslint:enable:max-line-length */ + if (!option) { + return hashFormats['none']; + } + return hashFormats[option] || hashFormats['none']; } @@ -39,7 +41,7 @@ export type NormalizedEntryPoint = ExtraEntryPointObject & { bundleName: string export function normalizeExtraEntryPoints( extraEntryPoints: ExtraEntryPoint[], - defaultBundleName: string + defaultBundleName: string, ): NormalizedEntryPoint[] { return extraEntryPoints.map(entry => { let normalizedEntry; @@ -64,5 +66,5 @@ export function normalizeExtraEntryPoints( } return normalizedEntry; - }) + }); } diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/plugins/webpack.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/plugins/webpack.ts index 0480230ad4..a13d08d6c2 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/plugins/webpack.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/plugins/webpack.ts @@ -5,8 +5,6 @@ * 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. // Exports the webpack plugins we use internally. export { BaseHrefWebpackPlugin } from '../lib/base-href-webpack/base-href-webpack-plugin'; @@ -14,6 +12,8 @@ export { CleanCssWebpackPlugin, CleanCssWebpackPluginOptions } from './cleancss- export { BundleBudgetPlugin, BundleBudgetPluginOptions } from './bundle-budget'; export { ScriptsWebpackPlugin, ScriptsWebpackPluginOptions } from './scripts-webpack-plugin'; export { SuppressExtractedTextChunksWebpackPlugin } from './suppress-entry-chunks-webpack-plugin'; +export { IndexHtmlWebpackPlugin } from './index-html-webpack-plugin'; +export { postcssPluginsFactory } from '../utilities/postcss-plugins-factory'; export { default as PostcssCliResources, PostcssCliResourcesOptions, diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/package-chunk-sort.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/generate-entry-points.ts similarity index 50% rename from packages/angular_devkit/build_angular/src/angular-cli-files/utilities/package-chunk-sort.ts rename to packages/angular_devkit/build_angular/src/angular-cli-files/utilities/generate-entry-points.ts index ce9f1b3e5d..af32a93059 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/package-chunk-sort.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/generate-entry-points.ts @@ -5,14 +5,13 @@ * 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. import { ExtraEntryPoint } from '../../browser/schema'; +import { BuildOptions } from '../models/build-options'; import { normalizeExtraEntryPoints } from '../models/webpack-configs/utils'; -export function generateEntryPoints(appConfig: any) { - let entryPoints = ['polyfills', 'sw-register']; +export function generateEntryPoints(appConfig: BuildOptions) { + const entryPoints = ['polyfills', 'sw-register']; // Add all styles/scripts, except lazy-loaded ones. [ @@ -32,27 +31,3 @@ export function generateEntryPoints(appConfig: any) { return entryPoints; } - -// Sort chunks according to a predefined order: -// inline, polyfills, all styles, vendor, main -export function packageChunkSort(appConfig: any) { - const entryPoints = generateEntryPoints(appConfig); - - function sort(left: any, right: any) { - let leftIndex = entryPoints.indexOf(left.names[0]); - let rightindex = entryPoints.indexOf(right.names[0]); - - if (leftIndex > rightindex) { - return 1; - } else if (leftIndex < rightindex) { - return -1; - } else { - return 0; - } - } - - // We need to list of entry points for the Ejected webpack config to work (we reuse the function - // defined above). - (sort as any).entryPoints = entryPoints; - return sort; -} diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/postcss-plugins-factory.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/postcss-plugins-factory.ts new file mode 100644 index 0000000000..1aabb7842e --- /dev/null +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/postcss-plugins-factory.ts @@ -0,0 +1,139 @@ +/** + * @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 autoprefixer from 'autoprefixer'; +import * as path from 'path'; +import { loader } from 'webpack'; +import { OutputHashing } from '../../browser/schema'; +import { getOutputHashFormat } from '../models/webpack-configs/utils'; +import PostcssCliResources from '../plugins/postcss-cli-resources'; +import { findUp } from './find-up'; +const postcssImports = require('postcss-import'); +const postcssUrl = require('postcss-url'); + + +interface PostcssUrlAsset { + url: string; + hash: string; + absolutePath: string; +} + +export interface PostcssPluginsFactoryOptions { + projectRoot: string; + deployUrl?: string; + baseHref?: string; + maximumInlineSize?: number; + outputHashing?: OutputHashing; +} + +export function postcssPluginsFactory(options: PostcssPluginsFactoryOptions) { + const projectRoot = options.projectRoot; + // Determine hashing format. + const hashFormat = getOutputHashFormat(options.outputHashing); + // Convert absolute resource URLs to account for base-href and deploy-url. + const baseHref = options.baseHref || ''; + const deployUrl = options.deployUrl || ''; + // Maximum resource size to inline (KiB) + const maximumInlineSize = options.maximumInlineSize || 10; + + return (loader: loader.LoaderContext) => [ + postcssImports({ + resolve: (url: string, context: string) => { + return new Promise((resolve, reject) => { + let hadTilde = false; + if (url && url.startsWith('~')) { + url = url.substr(1); + hadTilde = true; + } + loader.resolve(context, (hadTilde ? '' : './') + url, (err: Error, result: string) => { + if (err) { + if (hadTilde) { + reject(err); + + return; + } + loader.resolve(context, url, (err: Error, result: string) => { + if (err) { + reject(err); + } else { + resolve(result); + } + }); + } else { + resolve(result); + } + }); + }); + }, + load: (filename: string) => { + return new Promise((resolve, reject) => { + loader.fs.readFile(filename, (err: Error, data: Buffer) => { + if (err) { + reject(err); + + return; + } + + const content = data.toString(); + resolve(content); + }); + }); + }, + }), + postcssUrl({ + filter: ({ url }: PostcssUrlAsset) => url.startsWith('~'), + url: ({ url }: PostcssUrlAsset) => { + // Note: This will only find the first node_modules folder. + const nodeModules = findUp('node_modules', projectRoot); + if (!nodeModules) { + throw new Error('Cannot locate node_modules directory.'); + } + const fullPath = path.join(nodeModules, url.substr(1)); + + return path.relative(loader.context, fullPath).replace(/\\/g, '/'); + }, + }), + postcssUrl([ + { + // Only convert root relative URLs, which CSS-Loader won't process into require(). + filter: ({ url }: PostcssUrlAsset) => url.startsWith('/') && !url.startsWith('//'), + url: ({ url }: PostcssUrlAsset) => { + if (deployUrl.match(/:\/\//) || deployUrl.startsWith('/')) { + // If deployUrl is absolute or root relative, ignore baseHref & use deployUrl as is. + return `${deployUrl.replace(/\/$/, '')}${url}`; + } else if (baseHref.match(/:\/\//)) { + // If baseHref contains a scheme, include it as is. + return baseHref.replace(/\/$/, '') + + `/${deployUrl}/${url}`.replace(/\/\/+/g, '/'); + } else { + // Join together base-href, deploy-url and the original URL. + // Also dedupe multiple slashes into single ones. + return `/${baseHref}/${deployUrl}/${url}`.replace(/\/\/+/g, '/'); + } + }, + }, + { + // TODO: inline .cur if not supporting IE (use browserslist to check) + filter: (asset: PostcssUrlAsset) => { + return maximumInlineSize > 0 && !asset.hash && !asset.absolutePath.endsWith('.cur'); + }, + url: 'inline', + // NOTE: maxSize is in KB + maxSize: maximumInlineSize, + fallback: 'rebase', + }, + { url: 'rebase' }, + ]), + PostcssCliResources({ + deployUrl: loader.loaders[loader.loaderIndex].options.ident == 'extracted' ? '' : deployUrl, + loader, + filename: `[name]${hashFormat.file}.[ext]`, + }), + autoprefixer({ grid: true }), + ]; +} diff --git a/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts index 42b5a4c1d7..64fdf04a67 100644 --- a/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts +++ b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts @@ -34,20 +34,41 @@ describe('Webpack Builder basic test', () => { beforeEach(done => angularHost.initialize().subscribe(undefined, done.fail, done)); afterEach(done => angularHost.restore().subscribe(undefined, done.fail, done)); - it('works with a Angular app', (done) => { - runTargetSpec(angularHost, webpackTargetSpec, {}).pipe( + it('works', (done) => { + runTargetSpec(angularHost, webpackTargetSpec).pipe( tap((buildEvent) => expect(buildEvent.success).toBe(true)), tap(() => { - // Default files should be in outputPath. - // expect(host.scopedSync().exists(join(outputPath, 'runtime.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'runtime.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'runtime.js.map'))).toBe(true); expect(angularHost.scopedSync().exists(join(outputPath, 'main.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'main.js.map'))).toBe(true); expect(angularHost.scopedSync().exists(join(outputPath, 'polyfills.js'))).toBe(true); - // expect(host.scopedSync().exists(join(outputPath, 'styles.js'))).toBe(true); - // expect(host.scopedSync().exists(join(outputPath, 'vendor.js'))).toBe(true); - // expect(host.scopedSync().exists(join(outputPath, 'favicon.ico'))).toBe(true); - // expect(host.scopedSync().exists(join(outputPath, 'index.html'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'polyfills.js.map'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'styles.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'styles.js.map'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'vendor.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'vendor.js.map'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'favicon.ico'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'index.html'))).toBe(true); }), ).subscribe(undefined, done.fail, done); }, 30000); + + it('works with prod config', (done) => { + const targetSpec = { ...webpackTargetSpec, configuration: 'production' }; + runTargetSpec(angularHost, targetSpec).pipe( + tap((buildEvent) => expect(buildEvent.success).toBe(true)), + tap(() => { + expect(angularHost.scopedSync().exists(join(outputPath, 'runtime.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'main.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'main.js.map'))).toBe(false); + expect(angularHost.scopedSync().exists(join(outputPath, 'polyfills.js'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'styles.css'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'vendor.js'))).toBe(false); + expect(angularHost.scopedSync().exists(join(outputPath, 'favicon.ico'))).toBe(true); + expect(angularHost.scopedSync().exists(join(outputPath, 'index.html'))).toBe(true); + }), + ).subscribe(undefined, done.fail, done); + }, 60000); }); }); diff --git a/tsconfig.json b/tsconfig.json index ac88e47f5f..ffd9a17804 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -48,6 +48,7 @@ "@angular-devkit/architect": [ "./packages/angular_devkit/architect/src/index" ], "@angular-devkit/architect/testing": [ "./packages/angular_devkit/architect/testing/index" ], "@angular-devkit/build-webpack": [ "./packages/angular_devkit/build_webpack/src/index" ], + "@angular-devkit/build-webpack/plugins": [ "./packages/angular_devkit/build_webpack/plugins" ], "@ngtools/webpack": [ "./packages/ngtools/webpack/src/index" ], "@ngtools/webpack/*": [ "./packages/ngtools/webpack/*" ], "@schematics/angular": [ "./packages/schematics/angular/index" ] From 01ce5ad42ae16705bcf119688ac4d51885991f0d Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Wed, 16 May 2018 15:27:32 +0100 Subject: [PATCH 7/9] test: enhance build-webpack test --- .../build_webpack/angular-app/angular.json | 10 +- .../build_webpack/angular-app/src/favicon.ico | Bin 0 -> 5430 bytes .../build_webpack/angular-app/src/index.html | 14 + .../build_webpack/angular-app/src/scripts.js | 1 + .../angular-app/webpack.config.factory.js | 245 ++++++++++++++++++ .../angular-app/webpack.config.js | 42 +-- .../angular-app/webpack.config.prod.js | 6 + .../build_webpack/basic-app/angular.json | 6 +- 8 files changed, 278 insertions(+), 46 deletions(-) create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/favicon.ico create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/index.html create mode 100644 tests/@angular_devkit/build_webpack/angular-app/src/scripts.js create mode 100644 tests/@angular_devkit/build_webpack/angular-app/webpack.config.factory.js create mode 100644 tests/@angular_devkit/build_webpack/angular-app/webpack.config.prod.js diff --git a/tests/@angular_devkit/build_webpack/angular-app/angular.json b/tests/@angular_devkit/build_webpack/angular-app/angular.json index 0e357bdc7d..3a6749581d 100644 --- a/tests/@angular_devkit/build_webpack/angular-app/angular.json +++ b/tests/@angular_devkit/build_webpack/angular-app/angular.json @@ -2,12 +2,9 @@ "$schema": "../../../../packages/angular_devkit/core/src/workspace/workspace-schema.json", "version": 1, "newProjectRoot": "./projects", - "cli": {}, - "schematics": {}, - "architect": {}, "projects": { "app": { - "root": "src", + "root": "", "sourceRoot": "src", "projectType": "application", "schematics": {}, @@ -16,6 +13,11 @@ "builder": "../../../../packages/angular_devkit/build_webpack:webpack", "options": { "webpackConfig": "webpack.config.js" + }, + "configurations": { + "production": { + "webpackConfig": "webpack.config.prod.js" + } } }, "serve": { diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/favicon.ico b/tests/@angular_devkit/build_webpack/angular-app/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8081c7ceaf2be08bf59010158c586170d9d2d517 GIT binary patch literal 5430 zcmc(je{54#6vvCoAI3i*G5%$U7!sA3wtMZ$fH6V9C`=eXGJb@R1%(I_{vnZtpD{6n z5Pl{DmxzBDbrB>}`90e12m8T*36WoeDLA&SD_hw{H^wM!cl_RWcVA!I+x87ee975; z@4kD^=bYPn&pmG@(+JZ`rqQEKxW<}RzhW}I!|ulN=fmjVi@x{p$cC`)5$a!)X&U+blKNvN5tg=uLvuLnuqRM;Yc*swiexsoh#XPNu{9F#c`G zQLe{yWA(Y6(;>y|-efAy11k<09(@Oo1B2@0`PtZSkqK&${ zgEY}`W@t{%?9u5rF?}Y7OL{338l*JY#P!%MVQY@oqnItpZ}?s z!r?*kwuR{A@jg2Chlf0^{q*>8n5Ir~YWf*wmsh7B5&EpHfd5@xVaj&gqsdui^spyL zB|kUoblGoO7G(MuKTfa9?pGH0@QP^b#!lM1yHWLh*2iq#`C1TdrnO-d#?Oh@XV2HK zKA{`eo{--^K&MW66Lgsktfvn#cCAc*(}qsfhrvOjMGLE?`dHVipu1J3Kgr%g?cNa8 z)pkmC8DGH~fG+dlrp(5^-QBeEvkOvv#q7MBVLtm2oD^$lJZx--_=K&Ttd=-krx(Bb zcEoKJda@S!%%@`P-##$>*u%T*mh+QjV@)Qa=Mk1?#zLk+M4tIt%}wagT{5J%!tXAE;r{@=bb%nNVxvI+C+$t?!VJ@0d@HIyMJTI{vEw0Ul ze(ha!e&qANbTL1ZneNl45t=#Ot??C0MHjjgY8%*mGisN|S6%g3;Hlx#fMNcL<87MW zZ>6moo1YD?P!fJ#Jb(4)_cc50X5n0KoDYfdPoL^iV`k&o{LPyaoqMqk92wVM#_O0l z09$(A-D+gVIlq4TA&{1T@BsUH`Bm=r#l$Z51J-U&F32+hfUP-iLo=jg7Xmy+WLq6_tWv&`wDlz#`&)Jp~iQf zZP)tu>}pIIJKuw+$&t}GQuqMd%Z>0?t%&BM&Wo^4P^Y z)c6h^f2R>X8*}q|bblAF?@;%?2>$y+cMQbN{X$)^R>vtNq_5AB|0N5U*d^T?X9{xQnJYeU{ zoZL#obI;~Pp95f1`%X3D$Mh*4^?O?IT~7HqlWguezmg?Ybq|7>qQ(@pPHbE9V?f|( z+0xo!#m@Np9PljsyxBY-UA*{U*la#8Wz2sO|48_-5t8%_!n?S$zlGe+NA%?vmxjS- zHE5O3ZarU=X}$7>;Okp(UWXJxI%G_J-@IH;%5#Rt$(WUX?6*Ux!IRd$dLP6+SmPn= z8zjm4jGjN772R{FGkXwcNv8GBcZI#@Y2m{RNF_w8(Z%^A*!bS*!}s6sh*NnURytky humW;*g7R+&|Ledvc- + + + + HelloWorldApp + + + + + + + + + diff --git a/tests/@angular_devkit/build_webpack/angular-app/src/scripts.js b/tests/@angular_devkit/build_webpack/angular-app/src/scripts.js new file mode 100644 index 0000000000..377223d159 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/src/scripts.js @@ -0,0 +1 @@ +console.log('scripts.js'); \ No newline at end of file diff --git a/tests/@angular_devkit/build_webpack/angular-app/webpack.config.factory.js b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.factory.js new file mode 100644 index 0000000000..8bf2c3b7d2 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.factory.js @@ -0,0 +1,245 @@ +const { AngularCompilerPlugin } = require('@ngtools/webpack'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const path = require('path'); +const postcssUrl = require('postcss-url'); +const postcssImports = require('postcss-import'); +const autoprefixer = require('autoprefixer'); +const webpack = require('webpack'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +// The plugins below are loaded from Angular CLI's build system and may change over time. +// If you update @angular-devkit/build-angular and your standalone Webpack build breaks, please +// revert to the last version of @angular-devkit/build-angular you were using. +// You can also replace them with other plugins and loaders that do similar functions. +const { + CleanCssWebpackPlugin, + IndexHtmlWebpackPlugin, + RawCssLoader, + ScriptsWebpackPlugin, + postcssPluginsFactory +} = require('@angular-devkit/build-angular/plugins/webpack'); + + +// Build a webpack config based on options. +function webpackConfigFactory(options) { + // Set option defaults. + options = { + sourceMap: true, + optimize: true, + ...options, + }; + const { sourceMap, optimize } = options; + + // Global variables. + const workspaceRoot = path.resolve(__dirname, './'); + const projectRoot = path.resolve(__dirname, './'); + + // Style configurations. + const globalStylesEntryPoints = [path.resolve(workspaceRoot, 'src/styles.css')]; + const componentPostCssLoader = { + loader: 'postcss-loader', + options: { + ident: 'embedded', + plugins: postcssPluginsFactory({ projectRoot }), + sourceMap, + } + }; + const globalPostCssLoader = { + loader: 'postcss-loader', + options: { + // postcssPluginsFactory contains special logic for 'extracted' ident. + ident: optimize ? 'extracted' : 'embedded', + plugins: postcssPluginsFactory({ projectRoot }), + sourceMap, + } + }; + // bootstrap-sass requires a minimum precision of 8 + const sassLoader = { loader: 'sass-loader', options: { sourceMap, precision: 8 } }; + const lessLoader = { loader: 'less-loader', options: { sourceMap } }; + const stylusLoader = { loader: 'stylus-loader', options: { sourceMap } }; + const componentStylesLoaders = ['raw-loader', componentPostCssLoader]; + // Global styles will be extracted when optimizing. + const globalStylesLoaders = optimize + ? [MiniCssExtractPlugin.loader, RawCssLoader, globalPostCssLoader] + : ['style-loader', 'raw-loader', globalPostCssLoader]; + + // Return a Webpack configuration object. + return { + mode: optimize ? 'production' : 'development', + devtool: optimize ? false : 'source-map', + context: projectRoot, + resolve: { + extensions: ['.ts', '.js'] + }, + entry: { + main: path.resolve(workspaceRoot, 'src/main.ts'), + polyfills: path.resolve(workspaceRoot, 'src/polyfills.ts'), + styles: globalStylesEntryPoints, + }, + output: { + path: path.resolve(workspaceRoot, 'dist'), + filename: `[name].js`, + }, + optimization: { + noEmitOnErrors: true, + runtimeChunk: 'single', + // Uglify and CleanCSS configuration. + minimizer: [ + new UglifyJsPlugin({ + sourceMap, + parallel: true, + cache: true, + uglifyOptions: { + ecma: 5, + warnings: false, + safari10: true, + output: { + ascii_only: true, + comments: false, + webkit: true, + }, + compress: { + // Build Optimizer requires pure_getters to be set to true for best results. + pure_getters: true, + passes: 3, + }, + } + }), + new CleanCssWebpackPlugin({ + test: (file) => /\.(?:css|scss|sass|less|styl)$/.test(file), + sourceMap, + }), + ], + // Chunk splitting configuration. + splitChunks: { + maxAsyncRequests: Infinity, + cacheGroups: { + default: { + chunks: 'async', + minChunks: 2, + priority: 10, + }, + common: { + name: 'common', + chunks: 'async', + minChunks: 2, + enforce: true, + priority: 5, + }, + vendors: false, + // Disable vendor chunk when optimizing for best results with Build Optimizer. + vendor: !optimize && { + name: 'vendor', + chunks: 'initial', + enforce: true, + test: (module, chunks) => { + if (!module.nameForCondition) { + return false; + } + + // Vendor modules are those that have '/node_modules/' in their path and do not + // contain chunks from either the polyfills or global styles entry points. + return /[\\/]node_modules[\\/]/.test(module.nameForCondition()) + && !chunks.some(({ name }) => name === 'polyfills' || ['styles'].includes(name)); + }, + }, + }, + }, + }, + module: { + rules: [ + { test: /\.html$/, loader: 'raw-loader' }, + // AngularCompilerPlugin loader. + { + test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, + // require.resolve is required only because of the monorepo structure here. + loader: require.resolve('@ngtools/webpack') + }, + // Component styles rules. + { + exclude: [globalStylesEntryPoints], + rules: [ + { test: /\.css$/, use: componentStylesLoaders }, + { test: /\.scss$|\.sass$/, use: [...componentStylesLoaders, sassLoader] }, + { test: /\.less$/, use: [...componentStylesLoaders, lessLoader] }, + { test: /\.styl$/, use: [...componentStylesLoaders, stylusLoader] }, + ] + }, + // Global styles rules. + { + include: [globalStylesEntryPoints], + rules: [ + { test: /\.css$/, use: globalStylesLoaders }, + { test: /\.scss$|\.sass$/, use: [...globalStylesLoaders, sassLoader] }, + { test: /\.less$/, use: [...globalStylesLoaders, lessLoader] }, + { test: /\.styl$/, use: [...globalStylesLoaders, stylusLoader] }, + ] + }, + // 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 }, + }, + // The Build Optimizer loader is only active when optimizing. + { + test: { and: [() => optimize, /\.js$/] }, + // require.resolve is required only because of the monorepo structure here. + loader: require.resolve('@angular-devkit/build-optimizer/src/build-optimizer/webpack-loader'), + options: { sourceMap }, + }, + ] + }, + plugins: [ + // AngularCompilerPlugin compiles TypeScript with Angular AOT support. + new AngularCompilerPlugin({ + tsConfigPath: path.resolve(workspaceRoot, 'src/tsconfig.app.json'), + skipCodeGeneration: !optimize, + sourceMap, + }), + // index.html creation plugin. + new IndexHtmlWebpackPlugin({ + input: path.resolve(workspaceRoot, 'src/index.html'), + entrypoints: ['polyfills', 'scripts', 'styles', 'main'], + }), + // Asset configuration. + new CopyWebpackPlugin( + [{ + context: path.resolve(workspaceRoot, 'src/'), + to: '', + from: { glob: 'favicon.ico', dot: true } + }, + { + context: path.resolve(workspaceRoot, 'src/assets/'), + to: 'assets/', + from: { glob: '**/*', dot: true } + }], + { ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'] } + ), + // Global scripts configuration. + new ScriptsWebpackPlugin({ + name: 'scripts', + sourceMap, + filename: 'scripts.js', + // Full paths to scripts to include. + scripts: [ + path.resolve(workspaceRoot, 'src/scripts.js') + ], + basePath: workspaceRoot, + }), + // Extract CSS into its own file when optimizing. + new MiniCssExtractPlugin(), + ], + // Configuration for webpack-dev-server. + devServer: { + historyApiFallback: { + disableDotRule: true, + htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'], + }, + } + }; +} + +module.exports = webpackConfigFactory; + diff --git a/tests/@angular_devkit/build_webpack/angular-app/webpack.config.js b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.js index 36ba73a2eb..9929e59f47 100644 --- a/tests/@angular_devkit/build_webpack/angular-app/webpack.config.js +++ b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.js @@ -1,38 +1,6 @@ -const ngToolsWebpack = require('@ngtools/webpack'); -const path = require('path'); +const configFactory = require('./webpack.config.factory'); - -const workspaceRoot = path.resolve(__dirname, './'); -const projectRoot = path.resolve(__dirname, './'); - -module.exports = { - mode: 'development', - resolve: { - extensions: ['.ts', '.js'] - }, - entry: { - main: path.resolve(projectRoot, './src/main.ts'), - polyfills: path.resolve(projectRoot, './src/polyfills.ts') - }, - output: { - path: path.resolve(workspaceRoot, './dist'), - filename: `[name].js`, - }, - plugins: [ - new ngToolsWebpack.AngularCompilerPlugin({ - tsConfigPath: path.resolve(projectRoot, './src/tsconfig.app.json') - }) - ], - module: { - rules: [ - { test: /\.scss$/, loaders: ['raw-loader', 'sass-loader'] }, - { test: /\.css$/, loader: 'raw-loader' }, - { test: /\.html$/, loader: 'raw-loader' }, - // require.resolve is required only because of the monorepo structure here. - { test: /\.ts$/, loader: require.resolve('@ngtools/webpack') } - ] - }, - devServer: { - historyApiFallback: true - } -}; +module.exports = configFactory({ + sourceMap: true, + optimize: false, +}); diff --git a/tests/@angular_devkit/build_webpack/angular-app/webpack.config.prod.js b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.prod.js new file mode 100644 index 0000000000..1133390150 --- /dev/null +++ b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.prod.js @@ -0,0 +1,6 @@ +const configFactory = require('./webpack.config.factory'); + +module.exports = configFactory({ + sourceMap: false, + optimize: true, +}); diff --git a/tests/@angular_devkit/build_webpack/basic-app/angular.json b/tests/@angular_devkit/build_webpack/basic-app/angular.json index 0e357bdc7d..88157f76fe 100644 --- a/tests/@angular_devkit/build_webpack/basic-app/angular.json +++ b/tests/@angular_devkit/build_webpack/basic-app/angular.json @@ -2,15 +2,11 @@ "$schema": "../../../../packages/angular_devkit/core/src/workspace/workspace-schema.json", "version": 1, "newProjectRoot": "./projects", - "cli": {}, - "schematics": {}, - "architect": {}, "projects": { "app": { - "root": "src", + "root": "", "sourceRoot": "src", "projectType": "application", - "schematics": {}, "architect": { "build": { "builder": "../../../../packages/angular_devkit/build_webpack:webpack", From 0ee5ef6a3a2f72feab21dc90549202496fe0ccfb Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Fri, 18 May 2018 11:30:22 +0100 Subject: [PATCH 8/9] feat(@schematics/angular): add eject schematic --- .../schematics/angular/application/index.ts | 42 +--- packages/schematics/angular/collection.json | 5 + .../eject/files/webpack.config.factory.js | 235 ++++++++++++++++++ .../angular/eject/files/webpack.config.js | 6 + .../eject/files/webpack.config.prod.js | 6 + packages/schematics/angular/eject/index.ts | 210 ++++++++++++++++ .../schematics/angular/eject/index_spec.ts | 157 ++++++++++++ packages/schematics/angular/eject/schema.d.ts | 14 ++ packages/schematics/angular/eject/schema.json | 18 ++ packages/schematics/angular/library/index.ts | 72 ++---- packages/schematics/angular/utility/config.ts | 25 ++ .../angular/utility/package-json.ts | 74 ++++++ 12 files changed, 781 insertions(+), 83 deletions(-) create mode 100644 packages/schematics/angular/eject/files/webpack.config.factory.js create mode 100644 packages/schematics/angular/eject/files/webpack.config.js create mode 100644 packages/schematics/angular/eject/files/webpack.config.prod.js create mode 100644 packages/schematics/angular/eject/index.ts create mode 100644 packages/schematics/angular/eject/index_spec.ts create mode 100644 packages/schematics/angular/eject/schema.d.ts create mode 100644 packages/schematics/angular/eject/schema.json create mode 100644 packages/schematics/angular/utility/package-json.ts diff --git a/packages/schematics/angular/application/index.ts b/packages/schematics/angular/application/index.ts index 80a71d0153..1224003269 100644 --- a/packages/schematics/angular/application/index.ts +++ b/packages/schematics/angular/application/index.ts @@ -30,6 +30,7 @@ import { getWorkspace, } from '../utility/config'; import { latestVersions } from '../utility/latest-versions'; +import { addToPackageJson } from '../utility/package-json'; import { validateProjectName } from '../utility/validation'; import { Schema as ApplicationOptions } from './schema'; @@ -58,36 +59,6 @@ import { Schema as ApplicationOptions } from './schema'; // ); // } -function addDependenciesToPackageJson() { - return (host: Tree) => { - const packageJsonPath = 'package.json'; - - if (!host.exists('package.json')) { return host; } - - const source = host.read('package.json'); - if (!source) { return host; } - - const sourceText = source.toString('utf-8'); - const json = JSON.parse(sourceText); - - if (!json['devDependencies']) { - json['devDependencies'] = {}; - } - - json.devDependencies = { - '@angular/compiler-cli': latestVersions.Angular, - '@angular-devkit/build-angular': latestVersions.DevkitBuildAngular, - 'typescript': latestVersions.TypeScript, - // De-structure last keeps existing user dependencies. - ...json.devDependencies, - }; - - host.overwrite(packageJsonPath, JSON.stringify(json, null, 2)); - - return host; - }; -} - function addAppToWorkspaceFile(options: ApplicationOptions, workspace: WorkspaceSchema): Rule { // TODO: use JsonAST // const workspacePath = '/angular.json'; @@ -280,9 +251,18 @@ export default function (options: ApplicationOptions): Rule { e2eOptions.projectRoot = 'e2e'; } + // New dependencies. + const partialPackageJson = { + devDependencies: { + '@angular/compiler-cli': latestVersions.Angular, + '@angular-devkit/build-angular': latestVersions.DevkitBuildAngular, + 'typescript': latestVersions.TypeScript, + }, + }; + return chain([ addAppToWorkspaceFile(options, workspace), - options.skipPackageJson ? noop() : addDependenciesToPackageJson(), + options.skipPackageJson ? noop() : addToPackageJson('package.json', partialPackageJson), mergeWith( apply(url('./files/src'), [ template({ diff --git a/packages/schematics/angular/collection.json b/packages/schematics/angular/collection.json index 79fe1b9ec4..073480c901 100644 --- a/packages/schematics/angular/collection.json +++ b/packages/schematics/angular/collection.json @@ -99,6 +99,11 @@ "factory": "./library", "schema": "./library/schema.json", "description": "Generate a library project for Angular." + }, + "eject": { + "factory": "./eject", + "schema": "./eject/schema.json", + "description": "Generate a ejected webpack configuration for Angular projects." } } } diff --git a/packages/schematics/angular/eject/files/webpack.config.factory.js b/packages/schematics/angular/eject/files/webpack.config.factory.js new file mode 100644 index 0000000000..80432a5c34 --- /dev/null +++ b/packages/schematics/angular/eject/files/webpack.config.factory.js @@ -0,0 +1,235 @@ +const { AngularCompilerPlugin } = require('@ngtools/webpack'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const path = require('path'); +const webpack = require('webpack'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +// The plugins below are loaded from Angular CLI's build system and may change over time. +// If you update @angular-devkit/build-angular and your standalone Webpack build breaks, please +// revert to the last version of @angular-devkit/build-angular you were using. +// You can also replace them with other plugins and loaders that do similar functions. +const { + CleanCssWebpackPlugin, + IndexHtmlWebpackPlugin, + RawCssLoader, + ScriptsWebpackPlugin, + postcssPluginsFactory +} = require('@angular-devkit/build-angular/plugins/webpack'); + + +// Build a webpack config based on options. +function webpackConfigFactory(options) { + // Set option defaults. + options = { + sourceMap: true, + optimize: true, + ...options, + }; + const { sourceMap, optimize } = options; + + // Global variables. + const workspaceRoot = path.resolve(__dirname, '<%= relativePathToWorkspaceRoot %>'); + const projectRoot = path.resolve(__dirname, './'); + + // Style configurations. + const globalStylesEntryPoints = [ +<%= stylesTpl %> + ]; + const componentPostCssLoader = { + loader: 'postcss-loader', + options: { + ident: 'embedded', + plugins: postcssPluginsFactory({ projectRoot }), + sourceMap, + } + }; + const globalPostCssLoader = { + loader: 'postcss-loader', + options: { + // postcssPluginsFactory contains special logic for 'extracted' ident. + ident: optimize ? 'extracted' : 'embedded', + plugins: postcssPluginsFactory({ projectRoot }), + sourceMap, + } + }; + // bootstrap-sass requires a minimum precision of 8 + const sassLoader = { loader: 'sass-loader', options: { sourceMap, precision: 8 } }; + const lessLoader = { loader: 'less-loader', options: { sourceMap } }; + const stylusLoader = { loader: 'stylus-loader', options: { sourceMap } }; + const componentStylesLoaders = ['raw-loader', componentPostCssLoader]; + // Global styles will be extracted when optimizing. + const globalStylesLoaders = optimize + ? [MiniCssExtractPlugin.loader, RawCssLoader, globalPostCssLoader] + : ['style-loader', 'raw-loader', globalPostCssLoader]; + + // Return a Webpack configuration object. + return { + mode: optimize ? 'production' : 'development', + devtool: optimize ? false : 'source-map', + context: projectRoot, + resolve: { + extensions: ['.ts', '.js'] + }, + entry: { + main: path.resolve(workspaceRoot, '<%= main %>'), + <% if(polyfills) { %>polyfills: path.resolve(workspaceRoot, '<%= polyfills %>'),<% } %> + styles: globalStylesEntryPoints, + }, + output: { + path: path.resolve(workspaceRoot, '<%= outputPath %>'), + filename: '[name].js', + }, + optimization: { + noEmitOnErrors: true, + runtimeChunk: 'single', + // Uglify and CleanCSS configuration. + minimizer: [ + new UglifyJsPlugin({ + sourceMap, + parallel: true, + cache: true, + uglifyOptions: { + ecma: 5, + warnings: false, + safari10: true, + output: { + ascii_only: true, + comments: false, + webkit: true, + }, + compress: { + // Build Optimizer requires pure_getters to be set to true for best results. + pure_getters: true, + passes: 3, + }, + } + }), + new CleanCssWebpackPlugin({ + test: (file) => /\.(?:css|scss|sass|less|styl)$/.test(file), + sourceMap, + }), + ], + // Chunk splitting configuration. + splitChunks: { + maxAsyncRequests: Infinity, + cacheGroups: { + default: { + chunks: 'async', + minChunks: 2, + priority: 10, + }, + common: { + name: 'common', + chunks: 'async', + minChunks: 2, + enforce: true, + priority: 5, + }, + vendors: false, + // Disable vendor chunk when optimizing for best results with Build Optimizer. + vendor: !optimize && { + name: 'vendor', + chunks: 'initial', + enforce: true, + test: (module, chunks) => { + if (!module.nameForCondition) { + return false; + } + + // Vendor modules are those that have '/node_modules/' in their path and do not + // contain chunks from either the polyfills or global styles entry points. + return /[\\/]node_modules[\\/]/.test(module.nameForCondition()) + && !chunks.some(({ name }) => name === 'polyfills' || ['styles'].includes(name)); + }, + }, + }, + }, + }, + module: { + rules: [ + { test: /\.html$/, loader: 'raw-loader' }, + // AngularCompilerPlugin loader. + { + test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, + // require.resolve is required only because of the monorepo structure here. + loader: require.resolve('@ngtools/webpack') + }, + // Component styles rules. + { + exclude: [globalStylesEntryPoints], + rules: [ + { test: /\.css$/, use: componentStylesLoaders }, + { test: /\.scss$|\.sass$/, use: [...componentStylesLoaders, sassLoader] }, + { test: /\.less$/, use: [...componentStylesLoaders, lessLoader] }, + { test: /\.styl$/, use: [...componentStylesLoaders, stylusLoader] }, + ] + }, + // Global styles rules. + { + include: [globalStylesEntryPoints], + rules: [ + { test: /\.css$/, use: globalStylesLoaders }, + { test: /\.scss$|\.sass$/, use: [...globalStylesLoaders, sassLoader] }, + { test: /\.less$/, use: [...globalStylesLoaders, lessLoader] }, + { test: /\.styl$/, use: [...globalStylesLoaders, stylusLoader] }, + ] + }, + // 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 }, + }, + // The Build Optimizer loader is only active when optimizing. + { + test: { and: [() => optimize, /\.js$/] }, + // require.resolve is required only because of the monorepo structure here. + loader: require.resolve('@angular-devkit/build-optimizer/src/build-optimizer/webpack-loader'), + options: { sourceMap }, + }, + ] + }, + plugins: [ + // AngularCompilerPlugin compiles TypeScript with Angular AOT support. + new AngularCompilerPlugin({ + tsConfigPath: path.resolve(workspaceRoot, '<%= tsConfig %>'), + skipCodeGeneration: !optimize, + sourceMap, + }), + // index.html creation plugin. + new IndexHtmlWebpackPlugin({ + input: path.resolve(workspaceRoot, '<%= index %>'), + entrypoints: <%= entryPointsTpl %>, + }), + // Asset configuration. + new CopyWebpackPlugin( + [<%= assetsTpl %>], + { ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'] } + ), + // Global scripts configuration. + new ScriptsWebpackPlugin({ + name: 'scripts', + sourceMap, + filename: 'scripts.js', + // Full paths to scripts to include. + scripts: [ +<%= scriptsTpl %> + ], + basePath: workspaceRoot, + }), + // Extract CSS into its own file when optimizing. + new MiniCssExtractPlugin(), + ], + // Configuration for webpack-dev-server. + devServer: { + historyApiFallback: { + disableDotRule: true, + htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'], + }, + } + }; +} + +module.exports = webpackConfigFactory; + diff --git a/packages/schematics/angular/eject/files/webpack.config.js b/packages/schematics/angular/eject/files/webpack.config.js new file mode 100644 index 0000000000..9929e59f47 --- /dev/null +++ b/packages/schematics/angular/eject/files/webpack.config.js @@ -0,0 +1,6 @@ +const configFactory = require('./webpack.config.factory'); + +module.exports = configFactory({ + sourceMap: true, + optimize: false, +}); diff --git a/packages/schematics/angular/eject/files/webpack.config.prod.js b/packages/schematics/angular/eject/files/webpack.config.prod.js new file mode 100644 index 0000000000..1133390150 --- /dev/null +++ b/packages/schematics/angular/eject/files/webpack.config.prod.js @@ -0,0 +1,6 @@ +const configFactory = require('./webpack.config.factory'); + +module.exports = configFactory({ + sourceMap: false, + optimize: true, +}); diff --git a/packages/schematics/angular/eject/index.ts b/packages/schematics/angular/eject/index.ts new file mode 100644 index 0000000000..511fdebb83 --- /dev/null +++ b/packages/schematics/angular/eject/index.ts @@ -0,0 +1,210 @@ +/** + * @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, + basename, + dirname, + join, + normalize, + relative, + resolve, + strings, +} from '@angular-devkit/core'; +import { + Rule, + SchematicContext, + SchematicsException, + Tree, + apply, + branchAndMerge, + chain, + mergeWith, + move, + template, + url, +} from '@angular-devkit/schematics'; +import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; +import { addBuilderToProject, getWorkspace, getWorkspacePath } from '../utility/config'; +import { addToPackageJson } from '../utility/package-json'; +import { Schema as EjectOptions } from './schema'; + +export default function (options: EjectOptions): Rule { + return (host: Tree, context: SchematicContext) => { + const workspace = getWorkspace(host); + const projectName = options.projectName; + const project = workspace.projects[projectName]; + + if (!project.architect || !project.architect['build'] + || project.architect['build'].builder !== '@angular-devkit/build-angular:browser') { + throw new SchematicsException( + `Could not find default target for the '${projectName}' project. ` + + `Please make sure it contains a target called 'build' that uses the ` + + `'@angular-devkit/build-angular:browser' builder.`, + ); + } + + const workspaceRoot = dirname(normalize(getWorkspacePath(host))); + const builderOptions = project.architect['build'].options; + const projectRoot = join(workspaceRoot, project.root); + const sourceRoot = project.sourceRoot + ? join(workspaceRoot, project.sourceRoot) + : join(projectRoot, 'src'); + const relativePathToWorkspaceRoot = relative(projectRoot, workspaceRoot) || './'; + + // Helper to process styles/scripts array. + // Note: this does not take into account lazy styles/scripts, which should actually get + // their own entry point. + const extraEntryParser = (entry: string | { input: string }) => + typeof entry === 'string' ? entry : entry.input; + + // Helper to process assets array. + const assetsParser = (rawAsset: string | { glob: string, input: string, output: string }) => { + // Normalize asset pattern. + let asset; + if (typeof rawAsset === 'string') { + const assetPath = normalize(rawAsset); + let glob: string, input: Path; + + // If it exists in the host, then it is a file and not a directory. + if (host.exists(assetPath)) { + glob = basename(assetPath); + input = dirname(assetPath); + } else { + glob = '**/*'; + input = assetPath; + } + + const output = relative(sourceRoot, resolve(workspaceRoot, input)); + asset = { glob, input, output }; + } else { + asset = { + glob: rawAsset.glob, + input: normalize(rawAsset.input), + output: normalize(rawAsset.output), + }; + } + + // Convert it into CopyWebpackPlugin options. + const context = asset.input.endsWith('/') ? asset.input : asset.input + '/'; + const to = asset.output.endsWith('/') ? asset.output : asset.output + '/'; + + return { + context, + // Now we remove starting slash to make Webpack place it from the output root. + to: to.replace(/^\//, ''), + glob: asset.glob, + }; + }; + + // Required fields in builder. + const main = builderOptions.main; + const outputPath = builderOptions.outputPath; + const tsConfig = builderOptions.tsConfig; + const index = builderOptions.index; + + if (main === undefined || outputPath === undefined + || tsConfig === undefined || index === undefined) { + throw new SchematicsException( + `The 'build' target of the '${projectName}' project must contain the following options: ` + + `'main', 'outputPath', 'tsConfig' and 'index'. `, + ); + } + + // Optional fields in builder. + const polyfills = builderOptions.polyfills; + const assets: { context: string, to: string, glob: string }[] = + (builderOptions.assets || []).map(assetsParser); + const styles: string[] = (builderOptions.styles || []).map(extraEntryParser); + const scripts: string[] = (builderOptions.scripts || []).map(extraEntryParser); + + // Compose strings to use in templates. + const stylesTpl = styles.map(style => + ` path.resolve(workspaceRoot, '${style}'),`).join('\n'); + const scriptsTpl = scripts.map(script => + ` path.resolve(workspaceRoot, '${script}'),`).join('\n'); + // This one gets ugly. Check the 'should template assets' test to see how it should turn out. + const assetsTpl = assets.map((asset, idx) => `{ + context: path.resolve(workspaceRoot, '${asset.context}'), + to: '${asset.to}', + from: { glob: '${asset.glob}', dot: true }, + }`).join(', '); + + const entryPoints = ['main']; + if (styles) { entryPoints.unshift('styles'); } + if (scripts) { entryPoints.unshift('scripts'); } + if (polyfills) { entryPoints.unshift('polyfills'); } + const entryPointsTpl = `['${entryPoints.join(`', '`)}']`; + + // New webpack builders. + const webpackBuilderName = 'build-webpack'; + const webpackDevServerBuilderName = 'serve-webpack'; + const optionsAndConfigurations = { + options: { webpackConfig: 'webpack.config.js' }, + configurations: { + production: { webpackConfig: 'webpack.config.prod.js' }, + }, + }; + const webpackBuilder = { + builder: '@angular-devkit/build-webpack:webpack', + ...optionsAndConfigurations, + }; + const webpackDevServerBuilder = { + builder: '@angular-devkit/build-webpack:webpack-dev-server', + ...optionsAndConfigurations, + }; + + // New dependencies. + const partialPackageJson = { + devDependencies: { + '@ngtools/webpack': '^6.0.0', + '@angular-devkit/build-webpack': '^6.0.0', + 'copy-webpack-plugin': '^4.5.1', + 'less': '^3.0.4', + 'less-loader': '^4.1.0', + 'mini-css-extract-plugin': '~0.4.0', + 'node-sass': '^4.9.0', + 'postcss-loader': '^2.1.5', + 'raw-loader': '^0.5.1', + 'sass-loader': '^7.0.1', + 'stylus': '^0.54.5', + 'style-loader': '^0.21.0', + 'uglifyjs-webpack-plugin': '^1.2.5', + 'webpack': '~4.8.1', + 'webpack-dev-server': '^3.1.4', + }, + }; + + const templateSource = apply(url('./files'), [ + template({ + ...strings, + projectRoot, + relativePathToWorkspaceRoot, + main, + outputPath, + tsConfig, + index, + polyfills, + assetsTpl, + stylesTpl, + scriptsTpl, + entryPointsTpl, + }), + move(projectRoot), + ]); + + return chain([ + branchAndMerge(mergeWith(templateSource)), + addBuilderToProject(projectName, webpackBuilderName, webpackBuilder), + addBuilderToProject(projectName, webpackDevServerBuilderName, webpackDevServerBuilder), + addToPackageJson('package.json', partialPackageJson), + (_tree: Tree, context: SchematicContext) => { + context.addTask(new NodePackageInstallTask()); + }, + ])(host, context); + }; +} diff --git a/packages/schematics/angular/eject/index_spec.ts b/packages/schematics/angular/eject/index_spec.ts new file mode 100644 index 0000000000..619608a530 --- /dev/null +++ b/packages/schematics/angular/eject/index_spec.ts @@ -0,0 +1,157 @@ +/** + * @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 { tags } from '@angular-devkit/core'; +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import * as path from 'path'; +import { Schema as ApplicationOptions } from '../application/schema'; +import { Schema as WorkspaceOptions } from '../workspace/schema'; +import { Schema as EjectOptions } from './schema'; + + +describe('Eject Schematic', () => { + const schematicRunner = new SchematicTestRunner( + '@schematics/angular', + path.join(__dirname, '../collection.json'), + ); + const defaultOptions: EjectOptions = { + projectName: 'foo', + }; + const workspaceOptions: WorkspaceOptions = { + name: 'workspace', + newProjectRoot: 'projects', + version: '6.0.0', + }; + + const appOptions: ApplicationOptions = { + name: 'foo', + projectRoot: '', + skipPackageJson: false, + }; + + let workspaceTree: UnitTestTree; + beforeEach(() => { + workspaceTree = schematicRunner.runSchematic('workspace', workspaceOptions); + workspaceTree = schematicRunner.runSchematic('application', appOptions, workspaceTree); + // Add a script so we can test that too. + workspaceTree.overwrite('angular.json', workspaceTree.readContent('angular.json') + .replace('"scripts": []', '"scripts": ["src/scripts.js"]')); + }); + + it('should create files', () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const files = tree.files; + expect(files.indexOf('/webpack.config.js')).toBeGreaterThanOrEqual(0); + expect(files.indexOf('/webpack.config.prod.js')).toBeGreaterThanOrEqual(0); + expect(files.indexOf('/webpack.config.factory.js')).toBeGreaterThanOrEqual(0); + }); + + it('should template workspace root', () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const fileContent = tree.readContent('/webpack.config.factory.js'); + expect(fileContent).toContain(`const workspaceRoot = path.resolve(__dirname, './');`); + }); + + it('should template output path', () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const fileContent = tree.readContent('/webpack.config.factory.js'); + expect(fileContent).toContain(tags.trimNewlines` + output: { + path: path.resolve(workspaceRoot, 'dist/foo'), + filename: '[name].js', + }, + `); + }); + + it('should template entry points', () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const fileContent = tree.readContent('/webpack.config.factory.js'); + expect(fileContent).toContain(tags.trimNewlines` + entry: { + main: path.resolve(workspaceRoot, 'src/main.ts'), + polyfills: path.resolve(workspaceRoot, 'src/polyfills.ts'), + styles: globalStylesEntryPoints, + }, + `); + }); + + it('should template index plugin', () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const fileContent = tree.readContent('/webpack.config.factory.js'); + expect(fileContent).toContain(tags.trimNewlines` + new IndexHtmlWebpackPlugin({ + input: path.resolve(workspaceRoot, 'src/index.html'), + entrypoints: ['polyfills', 'scripts', 'styles', 'main'], + }), + `); + }); + + it('should template styles', () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const fileContent = tree.readContent('/webpack.config.factory.js'); + expect(fileContent).toContain(tags.trimNewlines` + const globalStylesEntryPoints = [ + path.resolve(workspaceRoot, 'src/styles.css'), + ]; + `); + }); + + it('should template scripts', () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const fileContent = tree.readContent('/webpack.config.factory.js'); + expect(fileContent).toContain(tags.trimNewlines` + scripts: [ + path.resolve(workspaceRoot, 'src/scripts.js'), + ], + `); + }); + + it('should template assets', () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const fileContent = tree.readContent('/webpack.config.factory.js'); + expect(fileContent).toContain(tags.trimNewlines` + new CopyWebpackPlugin( + [{ + context: path.resolve(workspaceRoot, 'src/'), + to: '', + from: { glob: 'favicon.ico', dot: true }, + }, { + context: path.resolve(workspaceRoot, 'src/assets/'), + to: 'assets/', + from: { glob: '**/*', dot: true }, + }], + { ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'] } + ), + `); + }); + + it(`should add packages to package json devDependencies`, () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const packageJson = JSON.parse(tree.readContent('/package.json')); + expect(packageJson.devDependencies['webpack']).toBeTruthy(); + expect(packageJson.devDependencies['webpack-dev-server']).toBeTruthy(); + }); + + it(`should add builders to workspace`, () => { + const tree = schematicRunner.runSchematic('eject', defaultOptions, workspaceTree); + const workspace = JSON.parse(tree.readContent('/angular.json')); + expect(workspace.projects['foo'].architect['build-webpack']).toEqual({ + builder: '@angular-devkit/build-webpack:webpack', + options: { webpackConfig: 'webpack.config.js' }, + configurations: { + production: { webpackConfig: 'webpack.config.prod.js' }, + }, + }); + expect(workspace.projects['foo'].architect['serve-webpack']).toEqual({ + builder: '@angular-devkit/build-webpack:webpack-dev-server', + options: { webpackConfig: 'webpack.config.js' }, + configurations: { + production: { webpackConfig: 'webpack.config.prod.js' }, + }, + }); + }); +}); diff --git a/packages/schematics/angular/eject/schema.d.ts b/packages/schematics/angular/eject/schema.d.ts new file mode 100644 index 0000000000..9e57d040a9 --- /dev/null +++ b/packages/schematics/angular/eject/schema.d.ts @@ -0,0 +1,14 @@ +/** + * @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 interface Schema { + /** + * The name of the project to eject. + */ + projectName: string; +} diff --git a/packages/schematics/angular/eject/schema.json b/packages/schematics/angular/eject/schema.json new file mode 100644 index 0000000000..9fe2f8888c --- /dev/null +++ b/packages/schematics/angular/eject/schema.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "SchematicsLibrary", + "title": "Eject Options Schema", + "type": "object", + "properties": { + "projectName": { + "type": "string", + "description": "The name of the project to eject.", + "$default": { + "$source": "projectName" + } + } + }, + "required": [ + "projectName" + ] +} \ No newline at end of file diff --git a/packages/schematics/angular/library/index.ts b/packages/schematics/angular/library/index.ts index ab61a65f6e..e0ff8d2871 100644 --- a/packages/schematics/angular/library/index.ts +++ b/packages/schematics/angular/library/index.ts @@ -28,22 +28,11 @@ import { getWorkspace, } from '../utility/config'; import { latestVersions } from '../utility/latest-versions'; +import { addToPackageJson } from '../utility/package-json'; import { validateProjectName } from '../utility/validation'; import { Schema as LibraryOptions } from './schema'; -type PackageJsonPartialType = { - scripts: { - [key: string]: string; - }, - dependencies: { - [key: string]: string; - }, - devDependencies: { - [key: string]: string; - }, -}; - interface UpdateJsonFn { (obj: T): T | void; } @@ -93,45 +82,6 @@ function updateTsConfig(packageName: string, distRoot: string) { }; } -function addDependenciesToPackageJson() { - - return (host: Tree) => { - if (!host.exists('package.json')) { return host; } - - return updateJsonFile(host, 'package.json', (json: PackageJsonPartialType) => { - - - if (!json['dependencies']) { - json['dependencies'] = {}; - } - - json.dependencies = { - '@angular/common': latestVersions.Angular, - '@angular/core': latestVersions.Angular, - '@angular/compiler': latestVersions.Angular, - // De-structure last keeps existing user dependencies. - ...json.dependencies, - }; - - if (!json['devDependencies']) { - json['devDependencies'] = {}; - } - - json.devDependencies = { - '@angular/compiler-cli': latestVersions.Angular, - '@angular-devkit/build-ng-packagr': latestVersions.DevkitBuildNgPackagr, - '@angular-devkit/build-angular': latestVersions.DevkitBuildNgPackagr, - 'ng-packagr': '^3.0.0-rc.2', - 'tsickle': '>=0.25.5', - 'tslib': '^1.7.1', - 'typescript': latestVersions.TypeScript, - // De-structure last keeps existing user dependencies. - ...json.devDependencies, - }; - }); - }; -} - function addAppToWorkspaceFile(options: LibraryOptions, workspace: WorkspaceSchema, projectRoot: string, packageName: string): Rule { @@ -208,6 +158,24 @@ export default function (options: LibraryOptions): Rule { const sourceDir = `${projectRoot}/src/lib`; const relativePathToWorkspaceRoot = projectRoot.split('/').map(x => '..').join('/'); + // New dependencies. + const partialPackageJson = { + dependencies: { + '@angular/common': latestVersions.Angular, + '@angular/core': latestVersions.Angular, + '@angular/compiler': latestVersions.Angular, + }, + devDependencies: { + '@angular/compiler-cli': latestVersions.Angular, + '@angular-devkit/build-ng-packagr': latestVersions.DevkitBuildNgPackagr, + '@angular-devkit/build-angular': latestVersions.DevkitBuildNgPackagr, + 'ng-packagr': '^3.0.0-rc.2', + 'tsickle': '>=0.25.5', + 'tslib': '^1.7.1', + 'typescript': latestVersions.TypeScript, + }, + }; + const templateSource = apply(url('./files'), [ template({ ...strings, @@ -226,7 +194,7 @@ export default function (options: LibraryOptions): Rule { return chain([ branchAndMerge(mergeWith(templateSource)), addAppToWorkspaceFile(options, workspace, projectRoot, packageName), - options.skipPackageJson ? noop() : addDependenciesToPackageJson(), + options.skipPackageJson ? noop() : addToPackageJson('package.json', partialPackageJson), options.skipTsConfig ? noop() : updateTsConfig(packageName, distRoot), schematic('module', { name: options.name, diff --git a/packages/schematics/angular/utility/config.ts b/packages/schematics/angular/utility/config.ts index 730427963c..7b29fa2556 100644 --- a/packages/schematics/angular/utility/config.ts +++ b/packages/schematics/angular/utility/config.ts @@ -547,3 +547,28 @@ export function getAppFromConfig(config: CliConfig, appIndexOrName: string): App return config.apps.filter((app) => app.name === appIndexOrName)[0]; } + +export function addBuilderToProject(projectName: string, builderName: string, builder: {}): Rule { + return (host: Tree, context: SchematicContext) => { + + const workspace = getWorkspace(host); + + if (!workspace.projects[projectName]) { + throw new Error(`Project '${projectName}' does not exist in workspace.`); + } + + const project = workspace.projects[projectName]; + + if (!project.architect) { + project.architect = {}; + } + + if (project.architect[builderName]) { + throw new Error(`Builder '${builderName}' already exists in project.`); + } + + project.architect[builderName] = builder; + + host.overwrite(getWorkspacePath(host), JSON.stringify(workspace, null, 2)); + }; +} diff --git a/packages/schematics/angular/utility/package-json.ts b/packages/schematics/angular/utility/package-json.ts new file mode 100644 index 0000000000..feb505b1b3 --- /dev/null +++ b/packages/schematics/angular/utility/package-json.ts @@ -0,0 +1,74 @@ +/** + * @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 { JsonObject } from '@angular-devkit/core'; +import { Rule, SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics'; + + +export interface PackageJsonPartialType { + scripts?: JsonObject; + dependencies?: JsonObject; + devDependencies?: JsonObject; + optionalDependencies?: JsonObject; + peerDependencies?: JsonObject; +} + +const allowedSections = [ + 'scripts', + 'dependencies', + 'devDependencies', + 'peerDependencies', + 'optionalDependencies', +]; + +export function addToPackageJson(path: string, partialPackageJson: PackageJsonPartialType): Rule { + return (host: Tree, context: SchematicContext) => { + const source = host.read(path); + + if (!source) { + throw new SchematicsException(`Could not find (${path})`); + } + + const sourceText = source.toString('utf-8'); + const packageJson = JSON.parse(sourceText); + + for (const sectionKey of allowedSections) { + const section = (partialPackageJson as JsonObject)[sectionKey] as JsonObject; + if (!section) { + continue; + } + + if (!packageJson[sectionKey]) { + packageJson[sectionKey] = {}; + } + + let sectionModified = false; + + for (const entryKey of Object.keys(section)) { + if (packageJson[sectionKey][entryKey]) { + // Keep existing versions if they are present. + continue; + } + + sectionModified = true; + + // Otherwise add it. + packageJson[sectionKey][entryKey] = section[entryKey]; + } + + // If we modified the section, sort the keys alphabetically. + if (sectionModified) { + const sortedKeys = Object.keys(packageJson[sectionKey]).sort(); + const sortedObject: { [k: string]: string } = {}; + sortedKeys.forEach(k => sortedObject[k] = packageJson[sectionKey][k]); + packageJson[sectionKey] = sortedObject; + } + } + + host.overwrite(path, JSON.stringify(packageJson, null, 2)); + }; +} From 424acd50dde125d1a150f0663e3500dfa6fe484d Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Fri, 18 May 2018 11:30:37 +0100 Subject: [PATCH 9/9] test(@angular-devkit/build-webpack): update test with eject schematic --- .../src/webpack/index_spec_large.ts | 9 +++++--- .../build_webpack/angular-app/angular.json | 4 ++-- .../angular-app/webpack.config.factory.js | 23 ++++++++----------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts index 64fdf04a67..b05bc365f6 100644 --- a/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts +++ b/packages/angular_devkit/build_webpack/src/webpack/index_spec_large.ts @@ -13,10 +13,10 @@ import { angularHost, basicHost } from '../test-utils'; describe('Webpack Builder basic test', () => { - const outputPath = normalize('dist'); - const webpackTargetSpec = { project: 'app', target: 'build' }; - describe('basic app', () => { + const outputPath = normalize('dist'); + const webpackTargetSpec = { project: 'app', target: 'build' }; + beforeEach(done => basicHost.initialize().subscribe(undefined, done.fail, done)); afterEach(done => basicHost.restore().subscribe(undefined, done.fail, done)); @@ -31,6 +31,9 @@ describe('Webpack Builder basic test', () => { }); describe('Angular app', () => { + const outputPath = normalize('dist/foo'); + const webpackTargetSpec = { project: 'app', target: 'build-webpack' }; + beforeEach(done => angularHost.initialize().subscribe(undefined, done.fail, done)); afterEach(done => angularHost.restore().subscribe(undefined, done.fail, done)); diff --git a/tests/@angular_devkit/build_webpack/angular-app/angular.json b/tests/@angular_devkit/build_webpack/angular-app/angular.json index 3a6749581d..061feb616f 100644 --- a/tests/@angular_devkit/build_webpack/angular-app/angular.json +++ b/tests/@angular_devkit/build_webpack/angular-app/angular.json @@ -9,7 +9,7 @@ "projectType": "application", "schematics": {}, "architect": { - "build": { + "build-webpack": { "builder": "../../../../packages/angular_devkit/build_webpack:webpack", "options": { "webpackConfig": "webpack.config.js" @@ -20,7 +20,7 @@ } } }, - "serve": { + "serve-webpack": { "builder": "../../../../packages/angular_devkit/build_webpack:webpack-dev-server", "options": { "webpackConfig": "webpack.config.js" diff --git a/tests/@angular_devkit/build_webpack/angular-app/webpack.config.factory.js b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.factory.js index 8bf2c3b7d2..898f3c84f2 100644 --- a/tests/@angular_devkit/build_webpack/angular-app/webpack.config.factory.js +++ b/tests/@angular_devkit/build_webpack/angular-app/webpack.config.factory.js @@ -1,9 +1,6 @@ const { AngularCompilerPlugin } = require('@ngtools/webpack'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const path = require('path'); -const postcssUrl = require('postcss-url'); -const postcssImports = require('postcss-import'); -const autoprefixer = require('autoprefixer'); const webpack = require('webpack'); const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); @@ -36,7 +33,9 @@ function webpackConfigFactory(options) { const projectRoot = path.resolve(__dirname, './'); // Style configurations. - const globalStylesEntryPoints = [path.resolve(workspaceRoot, 'src/styles.css')]; + const globalStylesEntryPoints = [ + path.resolve(workspaceRoot, 'src/styles.css'), + ]; const componentPostCssLoader = { loader: 'postcss-loader', options: { @@ -78,8 +77,8 @@ function webpackConfigFactory(options) { styles: globalStylesEntryPoints, }, output: { - path: path.resolve(workspaceRoot, 'dist'), - filename: `[name].js`, + path: path.resolve(workspaceRoot, 'dist/foo'), + filename: '[name].js', }, optimization: { noEmitOnErrors: true, @@ -208,12 +207,11 @@ function webpackConfigFactory(options) { [{ context: path.resolve(workspaceRoot, 'src/'), to: '', - from: { glob: 'favicon.ico', dot: true } - }, - { + from: { glob: 'favicon.ico', dot: true }, + }, { context: path.resolve(workspaceRoot, 'src/assets/'), to: 'assets/', - from: { glob: '**/*', dot: true } + from: { glob: '**/*', dot: true }, }], { ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'] } ), @@ -224,7 +222,7 @@ function webpackConfigFactory(options) { filename: 'scripts.js', // Full paths to scripts to include. scripts: [ - path.resolve(workspaceRoot, 'src/scripts.js') + path.resolve(workspaceRoot, 'src/scripts.js'), ], basePath: workspaceRoot, }), @@ -241,5 +239,4 @@ function webpackConfigFactory(options) { }; } -module.exports = webpackConfigFactory; - +module.exports = webpackConfigFactory; \ No newline at end of file