From 06f5624b714e9980a4d5aa5b500d984bb8de3d95 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Wed, 20 Feb 2019 17:55:17 -0800 Subject: [PATCH] feat(@angular-devkit/build-webpack): add API builder for dev server It outputs the port and address that it is bound to. --- packages/_/devkit/package/schema.d.ts | 13 --- .../build_webpack/builders.json | 7 ++ .../src/webpack-dev-server/index.ts | 2 +- .../src/webpack-dev-server/index2.ts | 101 ++++++++++++++++++ .../src/webpack-dev-server/schema.json | 3 +- 5 files changed, 111 insertions(+), 15 deletions(-) delete mode 100644 packages/_/devkit/package/schema.d.ts create mode 100644 packages/angular_devkit/build_webpack/src/webpack-dev-server/index2.ts diff --git a/packages/_/devkit/package/schema.d.ts b/packages/_/devkit/package/schema.d.ts deleted file mode 100644 index 0f2b32ac37a9..000000000000 --- a/packages/_/devkit/package/schema.d.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 - */ - -export interface Schema { - name: string; - description: string; - displayName: string; -} diff --git a/packages/angular_devkit/build_webpack/builders.json b/packages/angular_devkit/build_webpack/builders.json index 5d60a54aa247..2e025ba55e02 100644 --- a/packages/angular_devkit/build_webpack/builders.json +++ b/packages/angular_devkit/build_webpack/builders.json @@ -7,7 +7,14 @@ "schema": "./src/webpack/schema.json", "description": "Build a webpack app." }, + "dev-server": { + "implementation": "./src/webpack-dev-server/index2", + "class": "./src/webpack-dev-server", + "schema": "./src/webpack-dev-server/schema.json", + "description": "Serve a webpack app." + }, "webpack-dev-server": { + "implementation": "./src/webpack-dev-server/index2", "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/src/webpack-dev-server/index.ts b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index.ts index d99bfeddf460..0b5c7734d073 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 @@ -19,7 +19,7 @@ import { concatMap } from 'rxjs/operators'; import * as webpack from 'webpack'; import * as WebpackDevServer from 'webpack-dev-server'; import { LoggingCallback, defaultLoggingCb } from '../webpack'; -import { WebpackDevServerBuilderSchema } from './schema'; +import { Schema as WebpackDevServerBuilderSchema } from './schema'; export interface DevServerResult { port: number; diff --git a/packages/angular_devkit/build_webpack/src/webpack-dev-server/index2.ts b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index2.ts new file mode 100644 index 000000000000..541520d7ab40 --- /dev/null +++ b/packages/angular_devkit/build_webpack/src/webpack-dev-server/index2.ts @@ -0,0 +1,101 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect/src/index2'; +import { getSystemPath, json, normalize, resolve } from '@angular-devkit/core'; +import * as net from 'net'; +import { Observable, from, of } from 'rxjs'; +import { switchMap } from 'rxjs/operators'; +import * as webpack from 'webpack'; +import * as WebpackDevServer from 'webpack-dev-server'; +import { ArchitectPlugin } from '../plugins/architect'; +import { WebpackFactory, WebpackLoggingCallback } from '../webpack/index2'; +import { Schema as WebpackDevServerBuilderSchema } from './schema'; + +const webpackMerge = require('webpack-merge'); + + +export type DevServerBuildResult = BuilderOutput & { + port: number; + family: string; + address: string; +}; + +export function runWebpackDevServer( + config: webpack.Configuration, + context: BuilderContext, + options: { + devServerConfig?: WebpackDevServer.Configuration, + logging?: WebpackLoggingCallback, + webpackFactory?: WebpackFactory, + } = {}, +): Observable { + const createWebpack = options.webpackFactory || (config => of(webpack(config))); + const log: WebpackLoggingCallback = options.logging + || ((stats, config) => context.logger.info(stats.toString(config.stats))); + + config = webpackMerge(config, { + plugins: [ + new ArchitectPlugin(context), + ], + }); + + const devServerConfig = options.devServerConfig || config.devServer || {}; + if (devServerConfig.stats) { + config.stats = devServerConfig.stats as webpack.Stats.ToStringOptionsObject; + } + // Disable stats reporting by the devserver, we have our own logger. + devServerConfig.stats = false; + + return createWebpack(config).pipe( + switchMap(webpackCompiler => new Observable(obs => { + const server = new WebpackDevServer(webpackCompiler, devServerConfig); + let result: DevServerBuildResult; + + webpackCompiler.hooks.done.tap('build-webpack', (stats) => { + // Log stats. + log(stats, config); + + obs.next({ + ...result, + success: !stats.hasErrors(), + } as DevServerBuildResult); + }); + + server.listen( + devServerConfig.port === undefined ? 8080 : devServerConfig.port, + devServerConfig.host === undefined ? 'localhost' : devServerConfig.host, + function (this: net.Server, err) { + if (err) { + obs.error(err); + } else { + result = { + success: true, + port: this.address().port, + family: this.address().family, + address: this.address().address, + }; + } + }, + ); + + // Teardown logic. Close the server when unsubscribed from. + return () => server.close(); + })), + ); +} + + +export default createBuilder< + json.JsonObject & WebpackDevServerBuilderSchema, DevServerBuildResult +>((options, context) => { + const configPath = resolve(normalize(context.workspaceRoot), normalize(options.webpackConfig)); + + return from(import(getSystemPath(configPath))).pipe( + switchMap((config: webpack.Configuration) => runWebpackDevServer(config, context)), + ); +}); 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 index f61d0fa9b680..697106775979 100644 --- a/packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.json +++ b/packages/angular_devkit/build_webpack/src/webpack-dev-server/schema.json @@ -1,4 +1,5 @@ { + "$schema": "http://json-schema.org/schema", "title": "Webpack Dev-Server Builder", "description": "Webpack Dev-Server Builder schema for Architect.", "type": "object", @@ -12,4 +13,4 @@ "required": [ "webpackConfig" ] -} \ No newline at end of file +}