From 76de5a9daaea5044264135c0ef5684ffb7482d59 Mon Sep 17 00:00:00 2001 From: Mike Hartington Date: Tue, 25 Jun 2019 10:08:45 -0400 Subject: [PATCH 1/2] feat(): new builder (#132) * init new builder API * chore(): updates * chore(): updates * chore(): update * chore(): update * chore(): clean up deps * chore(): update from feedback * chore(): fix build issues * chore(): finally understand deps * chore(): match angular schematics --- builders.json | 6 +- builders/cordova-build/index.ts | 124 +++++---------------------- builders/cordova-serve/index.ts | 96 ++++++--------------- builders/cordova-serve/log-server.ts | 1 - builders/cordova-serve/schema.d.ts | 6 +- builders/utils/index.ts | 123 ++++++++++++++++++++++++++ collection.json | 20 ++++- package.json | 20 ++--- 8 files changed, 204 insertions(+), 192 deletions(-) create mode 100644 builders/utils/index.ts diff --git a/builders.json b/builders.json index 2ac72c3..bbd7298 100644 --- a/builders.json +++ b/builders.json @@ -1,12 +1,14 @@ { "builders": { "cordova-build": { - "class": "./builders/cordova-build", + "implementation": "./builders/cordova-build/index", "schema": "./builders/cordova-build/schema.json", "description": "Perform a browser build with Cordova assets." }, + + "cordova-serve": { - "class": "./builders/cordova-serve", + "implementation": "./builders/cordova-serve/index", "schema": "./builders/cordova-serve/schema.json", "description": "Run the dev-server with Cordova assets." } diff --git a/builders/cordova-build/index.ts b/builders/cordova-build/index.ts index 5efa204..4e35b86 100644 --- a/builders/cordova-build/index.ts +++ b/builders/cordova-build/index.ts @@ -1,109 +1,25 @@ -import { BuildEvent, Builder, BuilderConfiguration, BuilderContext, BuilderDescription } from '@angular-devkit/architect'; -import { BrowserBuilderSchema } from '@angular-devkit/build-angular/src/browser/schema'; -import { getSystemPath, join, normalize } from '@angular-devkit/core'; -import { writeFileSync } from 'fs'; -import { Observable, of } from 'rxjs'; -import { concatMap, tap } from 'rxjs/operators'; +import { BuilderContext, createBuilder, targetFromTargetString } from '@angular-devkit/architect'; +import { json } from '@angular-devkit/core'; -import { CordovaBuildBuilderSchema } from './schema'; - -export { CordovaBuildBuilderSchema }; - -export class CordovaBuildBuilder implements Builder { - constructor(public context: BuilderContext) {} - - run(builderConfig: BuilderConfiguration): Observable { - const [ project, target, configuration ] = builderConfig.options.browserTarget.split(':'); - const browserTargetSpec = { project, target, configuration, overrides: {} }; - - let browserConfig = this.context.architect.getBuilderConfiguration(browserTargetSpec); - let browserDescription: BuilderDescription; - - return of(null).pipe( - concatMap(() => this.context.architect.getBuilderDescription(browserConfig)), - tap(description => browserDescription = description), - concatMap(() => this.context.architect.validateBuilderOptions(browserConfig, browserDescription)), - tap(config => browserConfig = config), - tap(() => this.validateBuilderConfig(builderConfig.options)), - tap(() => this.prepareBrowserConfig(builderConfig.options, browserConfig.options)), - concatMap(() => of(this.context.architect.getBuilder(browserDescription, this.context))), - concatMap(builder => builder.run(browserConfig)) - ); - } - - // Mutates builderOptions - validateBuilderConfig(builderOptions: CordovaBuildBuilderSchema) { - // if we're mocking cordova.js, don't build cordova bundle - if (builderOptions.cordovaMock) { - builderOptions.cordovaAssets = false; - } - - if (builderOptions.cordovaAssets && !builderOptions.platform) { - throw new Error('The `--platform` option is required with `--cordova-assets`'); - } - } - - // Mutates browserOptions - prepareBrowserConfig(options: CordovaBuildBuilderSchema, browserOptions: BrowserBuilderSchema) { - const cordovaBasePath = normalize(options.cordovaBasePath ? options.cordovaBasePath : '.'); +import { prepareBrowserConfig, validateBuilderConfig } from '../utils'; - if (typeof options.sourceMap !== 'undefined') { - browserOptions.sourceMap = options.sourceMap; - } - - // We always need to output the build to `www` because it is a hard - // requirement of Cordova. - browserOptions.outputPath = join(cordovaBasePath, normalize('www')); - - // Cordova CLI will error if `www` is missing. The Angular CLI deletes it - // by default. Let's keep it around. - browserOptions.deleteOutputPath = false; - - if (options.consolelogs) { - // Write the config to a file, and then include that in the bundle so it loads on window - const configPath = getSystemPath(join(normalize(__dirname), '../../assets', normalize('consolelog-config.js'))); - writeFileSync(configPath, `window.Ionic = window.Ionic || {}; Ionic.ConsoleLogServerConfig = { wsPort: ${options.consolelogsPort} }`); - - browserOptions.scripts.push({ - input: configPath, - bundleName: 'consolelogs', - lazy: false, - }); - - browserOptions.scripts.push({ - input: getSystemPath(join(normalize(__dirname), '../../assets', normalize('consolelogs.js'))), - bundleName: 'consolelogs', - lazy: false, - }); - } - - if (options.cordovaMock) { - browserOptions.scripts.push({ - input: getSystemPath(join(normalize(__dirname), '../../assets', normalize('cordova.js'))), - bundleName: 'cordova', - lazy: false, - }); - } else if (options.cordovaAssets) { - const platformWWWPath = join(cordovaBasePath, normalize(`platforms/${options.platform}/platform_www`)); - - // Add Cordova www assets that were generated whenever platform(s) and - // plugin(s) are added. This includes `cordova.js`, - // `cordova_plugins.js`, and all plugin JS. - browserOptions.assets.push({ - glob: '**/*', - input: getSystemPath(platformWWWPath), - output: './', - }); +import { CordovaBuildBuilderSchema } from './schema'; - // Register `cordova.js` as a global script so it is included in - // `index.html`. - browserOptions.scripts.push({ - input: getSystemPath(join(platformWWWPath, normalize('cordova.js'))), - bundleName: 'cordova', - lazy: false, - }); - } - } +export async function buildCordova( + options: CordovaBuildBuilderSchema, + context: BuilderContext +) { + context.reportStatus(`running cordova build...`); + // Get angular browser build target + const browserTargetSpec = targetFromTargetString(options.browserTarget); + // Get browser build options + const browserBuildTargetOptions = await context.getTargetOptions(browserTargetSpec); + + const formattedOptions = validateBuilderConfig(options); + const newOptions = prepareBrowserConfig(formattedOptions, browserBuildTargetOptions); + + const browserBuild = await context.scheduleTarget(browserTargetSpec, newOptions); + return browserBuild.result; } -export default CordovaBuildBuilder; +export default createBuilder(buildCordova); diff --git a/builders/cordova-serve/index.ts b/builders/cordova-serve/index.ts index 9bb85b9..6402195 100644 --- a/builders/cordova-serve/index.ts +++ b/builders/cordova-serve/index.ts @@ -1,82 +1,42 @@ -import { BuildEvent, Builder, BuilderConfiguration, BuilderContext, BuilderDescription } from '@angular-devkit/architect'; -import { NormalizedBrowserBuilderSchema } from '@angular-devkit/build-angular/src/browser/schema'; -import { DevServerBuilder, DevServerBuilderOptions } from '@angular-devkit/build-angular/src/dev-server'; -import { Path, virtualFs } from '@angular-devkit/core'; -import * as fs from 'fs'; -import { Observable, from, of } from 'rxjs'; -import { concatMap, tap } from 'rxjs/operators'; +import { BuilderContext, BuilderOutput, createBuilder, targetFromTargetString } from '@angular-devkit/architect'; +import { json } from '@angular-devkit/core'; -import { CordovaBuildBuilder, CordovaBuildBuilderSchema } from '../cordova-build'; +import { prepareBrowserConfig } from '../utils'; import { createConsoleLogServer } from './log-server'; import { CordovaServeBuilderSchema } from './schema'; -export class CordovaServeBuilder implements Builder { - constructor(public context: BuilderContext) {} +export type CordovaDevServerBuilderOptions = CordovaServeBuilderSchema & json.JsonObject; - run(builderConfig: BuilderConfiguration): Observable { - const { options: cordovaServeOptions } = builderConfig; - const { devServerTarget, port, host, ssl } = cordovaServeOptions; - const [ project, target, configuration ] = devServerTarget.split(':'); +export async function serveCordova( + options: CordovaServeBuilderSchema, + context: BuilderContext +): Promise { + return new Promise(async () => { + context.reportStatus(`running cordova serve...`); + const { devServerTarget, cordovaBuildTarget, port, host, ssl } = options; - const devServerTargetSpec = { project, target, configuration, overrides: { port, host, ssl } }; - const devServerBuilderConfig = this.context.architect.getBuilderConfiguration(devServerTargetSpec); + // Getting the original browser build options + const cordovaBuildTargetSpec = targetFromTargetString(cordovaBuildTarget); + const cordovaBuildTargetOptions = await context.getTargetOptions(cordovaBuildTargetSpec) as { browserTarget: string }; + const browserBuildTargetSpec = targetFromTargetString(cordovaBuildTargetOptions.browserTarget); - let devServerDescription: BuilderDescription; - let cordovaBuildConfig: BuilderConfiguration; + // What we actually need.... + const browserBuildTargetOptions = await context.getTargetOptions(browserBuildTargetSpec); - return of(null).pipe( - concatMap(() => this.context.architect.getBuilderDescription(devServerBuilderConfig)), - tap(description => devServerDescription = description), - concatMap(() => this.context.architect.validateBuilderOptions(devServerBuilderConfig, devServerDescription)), - concatMap(() => this._getCordovaBuildConfig(cordovaServeOptions)), - tap(config => cordovaBuildConfig = config), - concatMap(() => of(new CordovaDevServerBuilder(this.context, cordovaBuildConfig.options))), - concatMap(builder => builder.run(devServerBuilderConfig)) - ); - } + // Modifying those options to pass in cordova-speicfic stuff + prepareBrowserConfig(options, browserBuildTargetOptions); - protected _getCordovaBuildConfig(cordovaServeOptions: CordovaServeBuilderSchema): Observable> { - const { - platform, - cordovaBasePath, - cordovaAssets, - cordovaMock, - consolelogs, - consolelogsPort, - sourceMap, - } = cordovaServeOptions; - - const [ project, target, configuration ] = cordovaServeOptions.cordovaBuildTarget.split(':'); - const cordovaBuildTargetSpec = { project, target, configuration, overrides: { platform, cordovaBasePath, cordovaAssets, cordovaMock, consolelogs, consolelogsPort, sourceMap } }; - const cordovaBuildTargetConfig = this.context.architect.getBuilderConfiguration(cordovaBuildTargetSpec); - - return this.context.architect.getBuilderDescription(cordovaBuildTargetConfig).pipe( - concatMap(cordovaBuildDescription => this.context.architect.validateBuilderOptions(cordovaBuildTargetConfig, cordovaBuildDescription)) - ); - } -} - -class CordovaDevServerBuilder extends DevServerBuilder { - constructor(context: BuilderContext, public cordovaBuildOptions: CordovaBuildBuilderSchema) { - super(context); - } - - run(builderConfig: BuilderConfiguration): Observable { - if (this.cordovaBuildOptions.consolelogs && this.cordovaBuildOptions.consolelogsPort) { - return from(createConsoleLogServer(builderConfig.options.host, this.cordovaBuildOptions.consolelogsPort)) - .pipe(_ => super.run(builderConfig)); + if (options.consolelogs && options.consolelogsPort) { + await createConsoleLogServer(host, options.consolelogsPort); } - return super.run(builderConfig); - } - buildWebpackConfig(root: Path, projectRoot: Path, host: virtualFs.Host, browserOptions: NormalizedBrowserBuilderSchema) { - const builder = new CordovaBuildBuilder(this.context); - builder.validateBuilderConfig(this.cordovaBuildOptions); - builder.prepareBrowserConfig(this.cordovaBuildOptions, browserOptions); + const devServerTargetSpec = targetFromTargetString(devServerTarget); + const devServerTargetOptions = await context.getTargetOptions(devServerTargetSpec); - return super.buildWebpackConfig(root, projectRoot, host, browserOptions); - } + return context + .scheduleTarget(devServerTargetSpec, { host, port, ssl }, devServerTargetOptions) + .then(buildEvent => ({ ...buildEvent })); + }); } - -export default CordovaServeBuilder; +export default createBuilder(serveCordova); diff --git a/builders/cordova-serve/log-server.ts b/builders/cordova-serve/log-server.ts index e7d9c63..b204cc6 100644 --- a/builders/cordova-serve/log-server.ts +++ b/builders/cordova-serve/log-server.ts @@ -54,7 +54,6 @@ export async function createConsoleLogServer(host: string, port: number): Promis // pretty print objects and arrays (no newlines for arrays) msg.data = msg.data.map(d => JSON.stringify(d, undefined, d && d.length ? '' : ' ')); - if (status) { process.stdout.write(`[${status('console.' + msg.type)}]: ${msg.data.join(' ')}\n`); } else { diff --git a/builders/cordova-serve/schema.d.ts b/builders/cordova-serve/schema.d.ts index fb5db01..bb7e44d 100644 --- a/builders/cordova-serve/schema.d.ts +++ b/builders/cordova-serve/schema.d.ts @@ -2,9 +2,9 @@ export interface CordovaServeBuilderSchema { cordovaBuildTarget: string; devServerTarget: string; platform?: string; - port?: number; - host?: string; - ssl?: boolean; + port: number; + host: string; + ssl: boolean; cordovaBasePath?: string; sourceMap?: boolean; cordovaAssets?: boolean; diff --git a/builders/utils/index.ts b/builders/utils/index.ts new file mode 100644 index 0000000..b6b6471 --- /dev/null +++ b/builders/utils/index.ts @@ -0,0 +1,123 @@ +import { getSystemPath, join, normalize } from '@angular-devkit/core'; +import { writeFileSync } from 'fs'; + +import { CordovaBuildBuilderSchema } from '../cordova-build/schema'; +import { CordovaServeBuilderSchema } from '../cordova-serve/schema'; + +export function validateBuilderConfig( + builderOptions: CordovaBuildBuilderSchema +) { + // if we're mocking cordova.js, don't build cordova bundle + const newOptions = { ...builderOptions }; + if (newOptions.cordovaMock) { + newOptions.cordovaAssets = true; + } + + if (builderOptions.cordovaAssets && !builderOptions.platform) { + throw new Error( + 'The `--platform` option is required with `--cordova-assets`' + ); + } + return newOptions; +} + +export function prepareBrowserConfig( + options: CordovaBuildBuilderSchema | CordovaServeBuilderSchema | any, + browserOptions: any +) { + const optionsStarter = { ...browserOptions }; + const cordovaBasePath = normalize( + options.cordovaBasePath ? options.cordovaBasePath : '.' + ); + + if (typeof options.sourceMap !== 'undefined') { + optionsStarter.sourceMap = options.sourceMap; + } + + // We always need to output the build to `www` because it is a hard + // requirement of Cordova. + if ('outputPath' in options) { + optionsStarter.outputPath = join(cordovaBasePath, normalize('www')); + } + + // Cordova CLI will error if `www` is missing. The Angular CLI deletes it + // by default. Let's keep it around. + if ('deleteOutputPath' in options) { + optionsStarter.deleteOutputPath = false; + } + + if (options.consolelogs) { + // Write the config to a file, and then include that in the bundle so it loads on window + const configPath = getSystemPath( + join( + normalize(__dirname), + '../../assets', + normalize('consolelog-config.js') + ) + ); + writeFileSync( + configPath, + `window.Ionic = window.Ionic || {}; Ionic.ConsoleLogServerConfig = { wsPort: ${ + options.consolelogsPort + } }` + ); + if (optionsStarter.scripts) { + optionsStarter.scripts.push({ + input: configPath, + bundleName: 'consolelogs', + lazy: false, + }); + optionsStarter.scripts.push({ + input: getSystemPath( + join( + normalize(__dirname), + '../../assets', + normalize('consolelogs.js') + ) + ), + bundleName: 'consolelogs', + lazy: false, + }); + } + } + + if (options.cordovaMock) { + if (browserOptions.scripts) { + browserOptions.scripts.push({ + input: getSystemPath( + join(normalize(__dirname), '../../assets', normalize('cordova.js')) + ), + bundleName: 'cordova', + lazy: false, + }); + } + } else if (options.cordovaAssets) { + const platformWWWPath = join( + cordovaBasePath, + normalize(`platforms/${options.platform}/platform_www`) + ); + + // Add Cordova www assets that were generated whenever platform(s) and + // plugin(s) are added. This includes `cordova.js`, + // `cordova_plugins.js`, and all plugin JS. + if (optionsStarter.assets) { + optionsStarter.assets.push({ + glob: '**/*', + input: getSystemPath(platformWWWPath), + output: './', + }); + } + + // Register `cordova.js` as a global script so it is included in + // `index.html`. + if (optionsStarter.scripts) { + optionsStarter.scripts.push({ + input: getSystemPath(join(platformWWWPath, normalize('cordova.js'))), + bundleName: 'cordova', + lazy: false, + }); + } + } + + return optionsStarter; +} diff --git a/collection.json b/collection.json index b15aba4..9293289 100644 --- a/collection.json +++ b/collection.json @@ -6,16 +6,16 @@ "description": "Create an Ionic page.", "schema": "./schematics/page/schema.json" }, - "class": { - "aliases": ["cl"], - "extends": "@schematics/angular:class" - }, "component": { "aliases": ["c"], "factory": "./schematics/component", "description": "Create an Angular component.", "schema": "./schematics/component/schema.json" }, + "class": { + "aliases": ["cl"], + "extends": "@schematics/angular:class" + }, "directive": { "aliases": ["d"], "extends": "@schematics/angular:directive" @@ -54,6 +54,18 @@ "library": { "aliases": ["lib"], "extends": "@schematics/angular:library" + }, + "serviceWorker": { + "aliases": ["service-worker"], + "extends": "@schematics/angular:serviceWorker" + }, + "appShell": { + "aliases": ["app-shell"], + "extends": "@schematics/angular:appShell" + }, + "webWorker": { + "aliases": ["web-worker"], + "extends": "@schematics/angular:webWorker" } } } diff --git a/package.json b/package.json index 09bf756..e2fe9ba 100644 --- a/package.json +++ b/package.json @@ -30,16 +30,16 @@ "ionicframework" ], "dependencies": { - "@schematics/angular": "^7.0.3", + "@schematics/angular": "^8.0.0", "tslib": "^1.9.0", - "typescript": "~3.3.3333", + "typescript": "3.4.3", "ws": "^6.1.4" }, "devDependencies": { - "@angular-devkit/architect": "0.13.6", - "@angular-devkit/build-angular": "0.13.6", - "@angular-devkit/core": "7.3.6", - "@angular-devkit/schematics": "7.3.6", + "@angular-devkit/architect": ">=0.800.0", + "@angular-devkit/build-angular": ">=0.800.0", + "@angular-devkit/core": ">=8.0.0", + "@angular-devkit/schematics": ">=8.0.0", "@semantic-release/changelog": "^3.0.0", "@semantic-release/git": "^7.0.4", "@semantic-release/github": "^5.0.6", @@ -59,10 +59,10 @@ "typescript-tslint-plugin": "0.3.1" }, "peerDependencies": { - "@angular-devkit/architect": ">=0.7.2", - "@angular-devkit/build-angular": ">=0.7.2", - "@angular-devkit/core": ">=0.7.2 <8.0.0", - "@angular-devkit/schematics": ">=0.7.2 <8.0.0" + "@angular-devkit/architect": ">=0.800.0", + "@angular-devkit/build-angular": ">=0.800.0", + "@angular-devkit/core": ">=8.0.0", + "@angular-devkit/schematics": ">=8.0.0" }, "builders": "./builders.json", "schematics": "./collection.json", From 8e45ef63e65648eb8df916d9a03b51bfea802da5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2019 14:10:56 +0000 Subject: [PATCH 2/2] build(deps-dev): update typescript-tslint-plugin requirement Updates the requirements on [typescript-tslint-plugin](https://github.com/microsoft/typescript-tslint-plugin) to permit the latest version. - [Release notes](https://github.com/microsoft/typescript-tslint-plugin/releases) - [Changelog](https://github.com/microsoft/typescript-tslint-plugin/blob/master/CHANGELOG.md) - [Commits](https://github.com/microsoft/typescript-tslint-plugin/commits) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e2fe9ba..6ab38ed 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "semantic-release": "^15.9.17", "tslint": "^5.12.0", "tslint-ionic-rules": "0.0.21", - "typescript-tslint-plugin": "0.3.1" + "typescript-tslint-plugin": "0.5.2" }, "peerDependencies": { "@angular-devkit/architect": ">=0.800.0",