diff --git a/.eslintrc.json b/.eslintrc.json index 06cc47d..73843a7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -30,6 +30,19 @@ "files": ["*.js", "*.jsx"], "extends": ["plugin:@nrwl/nx/javascript"], "rules": {} + }, + { + "files": ["**/*.ts"], + "excludedFiles": ["./src/migrations/**"], + "rules": { + "no-restricted-imports": [ + "error", + "@nrwl/workspace", + "@angular-devkit/core", + "@angular-devkit/architect", + "@angular-devkit/schematics" + ] + } } ] } diff --git a/packages/nx-electron/executors.json b/packages/nx-electron/executors.json index 5a29a8d..2a484f3 100644 --- a/packages/nx-electron/executors.json +++ b/packages/nx-electron/executors.json @@ -2,22 +2,22 @@ "$schema": "http://json-schema.org/schema", "executors": { "build": { - "implementation": "./src/executors/build/executor", + "implementation": "./src/executors/build/executor.compat", "schema": "./src/executors/build/schema.json", "description": "Build an Electron application" }, "execute": { - "implementation": "./src/executors/execute/executor", + "implementation": "./src/executors/execute/executor.compat", "schema": "./src/executors/execute/schema.json", "description": "Execute an Electron application" }, "package": { - "implementation": "./src/executors/package/executor", + "implementation": "./src/executors/package/executor.compat", "schema": "./src/executors/package/schema.json", "description": "Package an Electron application" }, "make": { - "implementation": "./src/executors/package/executor", + "implementation": "./src/executors/package/executor.compat", "schema": "./src/executors/package/schema.json", "description": "Make an Electron application" } diff --git a/packages/nx-electron/package-lock.json b/packages/nx-electron/package-lock.json index 5f7b316..87c2df8 100644 --- a/packages/nx-electron/package-lock.json +++ b/packages/nx-electron/package-lock.json @@ -16,6 +16,21 @@ "requires": { "@angular-devkit/core": "12.2.13", "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "@angular-devkit/build-webpack": { @@ -25,6 +40,21 @@ "requires": { "@angular-devkit/architect": "0.1202.13", "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "@angular-devkit/core": { @@ -38,6 +68,21 @@ "magic-string": "0.25.7", "rxjs": "6.6.7", "source-map": "0.7.3" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "@angular-devkit/schematics": { @@ -48,6 +93,21 @@ "@angular-devkit/core": "12.2.13", "ora": "5.4.1", "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "@babel/code-frame": { @@ -5590,13 +5650,18 @@ } }, "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz", + "integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==", "requires": { - "tslib": "^1.9.0" + "tslib": "~2.1.0" } }, + "rxjs-for-await": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rxjs-for-await/-/rxjs-for-await-1.0.0.tgz", + "integrity": "sha512-MJhvf1vtQaljd5wlzsasvOjcohVogzkHkUI0gFE9nGhZ15/fT2vR1CjkLEh37oRqWwpv11vHo5D+sLM+Aw9Y8g==" + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -6619,9 +6684,9 @@ } }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" }, "tty-browserify": { "version": "0.0.0", diff --git a/packages/nx-electron/package.json b/packages/nx-electron/package.json index ecc0473..e6c2f65 100644 --- a/packages/nx-electron/package.json +++ b/packages/nx-electron/package.json @@ -67,6 +67,8 @@ "fork-ts-checker-webpack-plugin": "^6.1.0", "license-webpack-plugin": "^2.3.11", "rimraf": "^3.0.2", + "rxjs": "^7.4.0", + "rxjs-for-await": "^1.0.0", "source-map-support": "^0.5.19", "strip-json-comments": "^3.1.1", "terser-webpack-plugin": "^4.2.3", diff --git a/packages/nx-electron/src/executors/build/executor.compat.ts b/packages/nx-electron/src/executors/build/executor.compat.ts new file mode 100644 index 0000000..f4f4132 --- /dev/null +++ b/packages/nx-electron/src/executors/build/executor.compat.ts @@ -0,0 +1,10 @@ +import { convertNxExecutor, ExecutorContext } from '@nrwl/devkit'; + +import executor from './executor'; + +function executorAdapter(options: any, context: ExecutorContext): + Promise<{ success: boolean; }> | AsyncIterableIterator<{ success: boolean; }> { + return executor(options, context); +} + +export default convertNxExecutor(executorAdapter); \ No newline at end of file diff --git a/packages/nx-electron/src/executors/build/executor.ts b/packages/nx-electron/src/executors/build/executor.ts index d815a3f..ea76b88 100644 --- a/packages/nx-electron/src/executors/build/executor.ts +++ b/packages/nx-electron/src/executors/build/executor.ts @@ -1,13 +1,11 @@ import { join, resolve } from 'path'; -import { from, Observable } from 'rxjs'; -import { concatMap, map, tap } from 'rxjs/operators'; - -import { BuilderContext, createBuilder } from '@angular-devkit/architect'; -import { BuildResult, runWebpack } from '@angular-devkit/build-webpack'; -import { JsonObject } from '@angular-devkit/core'; +import { map, tap } from 'rxjs/operators'; +import { eachValueFrom } from 'rxjs-for-await'; +import { ExecutorContext } from '@nrwl/devkit'; +import { runWebpack } from '@nrwl/workspace/src/utilities/run-webpack'; import { readCachedProjectGraph } from '@nrwl/workspace/src/core/project-graph'; -import { calculateProjectDependencies, checkDependentProjectsHaveBeenBuilt, createTmpTsConfig } from '@nrwl/workspace/src/utils/buildable-libs-utils'; +import { calculateProjectDependencies, checkDependentProjectsHaveBeenBuilt, createTmpTsConfig } from '@nrwl/workspace/src/utilities/buildable-libs-utils'; import { getElectronWebpackConfig } from '../../utils/electron.config'; import { normalizeBuildOptions } from '../../utils/normalize'; @@ -15,80 +13,74 @@ import { BuildBuilderOptions } from '../../utils/types'; import { getSourceRoot } from '../../utils/workspace'; import { MAIN_OUTPUT_FILENAME } from '../../utils/config'; import { generatePackageJson } from '../../utils/generate-package-json'; +import webpack from 'webpack'; try { require('dotenv').config(); } catch (e) {} +export type ElectronBuildEvent = { + outfile: string; + success: boolean; +}; + export interface BuildElectronBuilderOptions extends BuildBuilderOptions { optimization?: boolean; sourceMap?: boolean; + buildLibsFromSource?: boolean; + generatePackageJson?: boolean; implicitDependencies: Array; externalDependencies: 'all' | 'none' | Array; } -export type ElectronBuildEvent = BuildResult & { - outfile: string; -}; +export interface NormalizedBuildElectronBuilderOptions extends BuildElectronBuilderOptions { + webpackConfig: string; +} -export default createBuilder(run); -function run( options: JsonObject & BuildElectronBuilderOptions, context: BuilderContext): Observable { +export function executor(rawOptions: BuildElectronBuilderOptions, context: ExecutorContext): AsyncIterableIterator { + const { sourceRoot, projectRoot } = getSourceRoot(context); + const normalizedOptions = normalizeBuildOptions( rawOptions, context.root, sourceRoot, projectRoot); const projGraph = readCachedProjectGraph(); - if (!options.buildLibsFromSource) { - const { target, dependencies } = calculateProjectDependencies( projGraph, context); + if (!normalizedOptions.buildLibsFromSource) { + const { target, dependencies } = + calculateProjectDependencies(projGraph, context.root, context.projectName, context.targetName, context.configurationName); - options.tsConfig = createTmpTsConfig( - join(context.workspaceRoot, options.tsConfig), - context.workspaceRoot, - target.data.root, - dependencies - ); + normalizedOptions.tsConfig = createTmpTsConfig(normalizedOptions.tsConfig, context.root, target.data.root, dependencies); - if (!checkDependentProjectsHaveBeenBuilt(context, dependencies)) { + if (!checkDependentProjectsHaveBeenBuilt(context.root, context.projectName, context.targetName, dependencies)) { return { success: false } as any; } } - return from(getSourceRoot(context)).pipe( - map(({ sourceRoot, projectRoot }) => - normalizeBuildOptions(options, context.workspaceRoot, sourceRoot, projectRoot) - ), - tap((normalizedOptions) => { - if (normalizedOptions.generatePackageJson) { - generatePackageJson( - context.target.project, - projGraph, - normalizedOptions - ); - } - }), - map(options => { - let config = getElectronWebpackConfig(options); - if (options.webpackConfig) { - config = require(options.webpackConfig)(config, { - options, - configuration: context.target.configuration - }); - } - config.entry['preload'] = join(options.sourceRoot, 'app/api/preload.ts'); - return config; - }), - concatMap(config => - runWebpack(config, context, { - logging: stats => { - context.logger.info(stats.toString(config.stats)); - } + if (normalizedOptions.generatePackageJson) { + generatePackageJson(context.projectName, projGraph, normalizedOptions); + } + + let config = getElectronWebpackConfig(normalizedOptions); + if (normalizedOptions.webpackConfig) { + config = require(normalizedOptions.webpackConfig)(config, { + normalizedOptions, + configuration: context.configurationName, + }); + } + config.entry['preload'] = join(normalizedOptions.sourceRoot, 'app/api/preload.ts'); + + + return eachValueFrom( + runWebpack(config, webpack).pipe( + tap((stats) => { + console.info(stats.toString(config.stats)); + }), + map((stats) => { + return { + success: !stats.hasErrors(), + outfile: resolve(context.root, normalizedOptions.outputPath, MAIN_OUTPUT_FILENAME) + } as ElectronBuildEvent; }) - ), - map((buildEvent: BuildResult) => { - buildEvent.outfile = resolve( - context.workspaceRoot, - options.outputPath, - MAIN_OUTPUT_FILENAME - ); - return buildEvent as ElectronBuildEvent; - }) + ) ); } + +export default executor; diff --git a/packages/nx-electron/src/executors/build/schema.json b/packages/nx-electron/src/executors/build/schema.json index c9cabd7..c77fb92 100644 --- a/packages/nx-electron/src/executors/build/schema.json +++ b/packages/nx-electron/src/executors/build/schema.json @@ -2,6 +2,7 @@ "title": "Electron Application Build Target", "description": "Electron application build target options for Build Facade", "type": "object", + "cli": "nx", "properties": { "main": { "type": "string", diff --git a/packages/nx-electron/src/executors/execute/executor.compat.ts b/packages/nx-electron/src/executors/execute/executor.compat.ts new file mode 100644 index 0000000..ef83be7 --- /dev/null +++ b/packages/nx-electron/src/executors/execute/executor.compat.ts @@ -0,0 +1,5 @@ +import { convertNxExecutor } from '@nrwl/devkit'; + +import executor from './executor'; + +export default convertNxExecutor(executor); \ No newline at end of file diff --git a/packages/nx-electron/src/executors/execute/executor.ts b/packages/nx-electron/src/executors/execute/executor.ts index f3cf585..323b5dc 100644 --- a/packages/nx-electron/src/executors/execute/executor.ts +++ b/packages/nx-electron/src/executors/execute/executor.ts @@ -1,14 +1,10 @@ -import { BuilderContext, createBuilder, BuilderOutput, targetFromTargetString, scheduleTargetAndForget } from '@angular-devkit/architect'; +import { runExecutor, stripIndents, parseTargetString, ExecutorContext, logger, readTargetOptions } from '@nrwl/devkit'; import { ChildProcess, spawn } from 'child_process'; +import { promisify } from 'util'; import electron from 'electron'; import treeKill from 'tree-kill'; -import { Observable, bindCallback, of, zip, from } from 'rxjs'; -import { concatMap, tap, mapTo, first, map, filter } from 'rxjs/operators'; - import { ElectronBuildEvent } from '../build/executor'; -import { stripIndents } from '@angular-devkit/core/src/utils/literals'; -import { JsonObject } from '@angular-devkit/core'; try { require('dotenv').config(); @@ -18,65 +14,66 @@ export const enum InspectType { Inspect = 'inspect', InspectBrk = 'inspect-brk', InspectBrkNode = 'inspect-brk-node', - //InspectBrkElectron = 'inspect-brk-electron' + InspectBrkElectron = 'inspect-brk-electron' } -export interface ElectronExecuteBuilderOptions extends JsonObject { +export interface ElectronExecuteBuilderOptions { inspect: boolean | InspectType; port: number; args: string[]; waitUntilTargets: string[]; + buildTargetOptions: Record; buildTarget: string; + watch: boolean; } -export default createBuilder( - electronExecuteBuilderHandler -); +let subProcess: ChildProcess = null; + +export async function* executor(options: ElectronExecuteBuilderOptions, context: ExecutorContext) { + process.on('SIGTERM', () => { + subProcess?.kill(); + process.exit(128 + 15); + }); -let subProcess: ChildProcess; + process.on('exit', (code) => { + process.exit(code); + }); -export function electronExecuteBuilderHandler(options: ElectronExecuteBuilderOptions, context: BuilderContext): Observable { - return runWaitUntilTargets(options, context).pipe( - concatMap(v => { - if (!v.success) { - context.logger.error( - `One of the tasks specified in waitUntilTargets failed` + if (options.waitUntilTargets && options.waitUntilTargets.length > 0) { + const results = await runWaitUntilTargets(options, context); + for (const [i, result] of results.entries()) { + if (!result.success) { + console.log('throw'); + throw new Error( + `Wait until target failed: ${options.waitUntilTargets[i]}.` ); - return of({ success: false }); } + } + } - return startBuild(options, context).pipe( - concatMap((event: ElectronBuildEvent) => { - if (event.success) { - return restartProcess(event.outfile, options, context).pipe( - mapTo(event) - ); - } else { - context.logger.error( - 'There was an error with the build. See above.' - ); - context.logger.info(`${event.outfile} was not restarted.`); - return of(event); - } - }) - ); - }) - ); + for await (const event of startBuild(options, context)) { + if (!event.success) { + logger.error('There was an error with the build. See above.'); + logger.info(`${event.outfile} was not restarted.`); + } + await handleBuildEvent(event, options); + yield event; + } } -function runProcess(file: string, options: ElectronExecuteBuilderOptions, context: BuilderContext) { +function runProcess(event: ElectronBuildEvent, options: ElectronExecuteBuilderOptions) { if (subProcess) { throw new Error('Already running'); } - subProcess = spawn(String(electron), normalizeArgs(file, options)); + subProcess = spawn(String(electron), normalizeArgs(event.outfile, options)); subProcess.stdout.on('data', (data) => { - context.logger.info(data.toString()); + logger.info(data.toString()); }); subProcess.stderr.on('data', (data) => { - context.logger.error(data.toString()); + logger.error(data.toString()); }); } @@ -97,50 +94,41 @@ function normalizeArgs(file: string, options: ElectronExecuteBuilderOptions) { return args; } -function restartProcess(file: string, options: ElectronExecuteBuilderOptions, context: BuilderContext) { - return killProcess(context).pipe( - tap(() => { - runProcess(file, options, context); - }) - ); +async function handleBuildEvent(event: ElectronBuildEvent, options: ElectronExecuteBuilderOptions) { + if ((!event.success || options.watch) && subProcess) { + await killProcess(); + } + + runProcess(event, options); } -function killProcess(context: BuilderContext): Observable { +async function killProcess() { if (!subProcess) { - return of(undefined); + return; } - const observableTreeKill = bindCallback(treeKill); - return observableTreeKill(subProcess.pid, 'SIGTERM').pipe( - tap(error => { - subProcess = null; - - if (error) { - if (Array.isArray(error) && error[0] && error[2]) { - const errorMessage = error[2]; - context.logger.error(errorMessage); - } else if (error.message) { - context.logger.error(error.message); - } - } - }) - ); + const promisifiedTreeKill: (pid: number, signal: string) => Promise = + promisify(treeKill); + try { + await promisifiedTreeKill(subProcess.pid, 'SIGTERM'); + } catch (err) { + if (Array.isArray(err) && err[0] && err[2]) { + const errorMessage = err[2]; + logger.error(errorMessage); + } else if (err.message) { + logger.error(err.message); + } + } finally { + subProcess = null; + } } -function startBuild(options: ElectronExecuteBuilderOptions, context: BuilderContext): Observable { - const target = targetFromTargetString(options.buildTarget); - - return from( - Promise.all([ - context.getTargetOptions(target), - context.getBuilderNameForTarget(target) - ]).then(([options, builderName]) => - context.validateOptions(options, builderName) - ) - ).pipe( - tap(options => { - if (options.optimization) { - context.logger.warn(stripIndents` +async function* startBuild(options: ElectronExecuteBuilderOptions, context: ExecutorContext) { + const buildTarget = parseTargetString(options.buildTarget); + const buildOptions = readTargetOptions(buildTarget, context); + + if (buildOptions['optimization']) { + logger.warn(stripIndents` ************************************************ This is a simple process manager for use in testing or debugging Electron applications locally. @@ -148,32 +136,38 @@ function startBuild(options: ElectronExecuteBuilderOptions, context: BuilderCont You should look into proper means of deploying your electron application to production. ************************************************`); - } - }), - concatMap( - () => - scheduleTargetAndForget(context, target, { - watch: true - }) - ) + } + + yield* await runExecutor( + buildTarget, + { + ...options.buildTargetOptions, + watch: options.watch, + }, + context ); } -function runWaitUntilTargets(options: ElectronExecuteBuilderOptions, context: BuilderContext): Observable { - if (!options.waitUntilTargets || options.waitUntilTargets.length === 0) { - return of({ success: true }); - } - - return zip( - ...options.waitUntilTargets.map(b => { - return scheduleTargetAndForget(context, targetFromTargetString(b)).pipe( - // filter(e => e.success !== undefined), // todo fix - // first() - ); - }) - ).pipe( - map(results => { - return { success: !results.some(r => !r.success) }; +function runWaitUntilTargets( + options: ElectronExecuteBuilderOptions, + context: ExecutorContext +): Promise<{ success: boolean }[]> { + return Promise.all( + options.waitUntilTargets.map(async (waitUntilTarget) => { + const target = parseTargetString(waitUntilTarget); + const output = await runExecutor(target, {}, context); + return new Promise<{ success: boolean }>(async (resolve) => { + let event = await output.next(); + // Resolve after first event + resolve(event.value as { success: boolean }); + + // Continue iterating + while (!event.done) { + event = await output.next(); + } + }); }) ); } + +export default executor; diff --git a/packages/nx-electron/src/executors/execute/schema.json b/packages/nx-electron/src/executors/execute/schema.json index 3eb8695..2e699c1 100644 --- a/packages/nx-electron/src/executors/execute/schema.json +++ b/packages/nx-electron/src/executors/execute/schema.json @@ -2,11 +2,22 @@ "title": "Schema for Executing Electron apps", "description": "Electron execution options", "type": "object", + "cli": "nx", "properties": { "buildTarget": { "type": "string", "description": "The target to run to build you the app" }, + "buildTargetOptions": { + "type": "object", + "description": "Additional options to pass into the build target.", + "default": {} + }, + "watch": { + "type": "boolean", + "description": "Run build when files change", + "default": true + }, "waitUntilTargets": { "type": "array", "description": "The targets to run to before starting the electron app", diff --git a/packages/nx-electron/src/executors/package/executor.compat.ts b/packages/nx-electron/src/executors/package/executor.compat.ts new file mode 100644 index 0000000..66b8687 --- /dev/null +++ b/packages/nx-electron/src/executors/package/executor.compat.ts @@ -0,0 +1,12 @@ +import { convertNxExecutor, ExecutorContext } from '@nrwl/devkit'; + +import executor from './executor'; + +function executorAdapter(options: any, context: ExecutorContext): + Promise<{ success: boolean; }> | AsyncIterableIterator<{ success: boolean; }> { + return executor(options, context).toPromise() + .then(output => { success: output.success }) + .catch(error => { success: false }); +} + +export default convertNxExecutor(executorAdapter); \ No newline at end of file diff --git a/packages/nx-electron/src/executors/package/executor.ts b/packages/nx-electron/src/executors/package/executor.ts index 50171b9..9a1c00b 100644 --- a/packages/nx-electron/src/executors/package/executor.ts +++ b/packages/nx-electron/src/executors/package/executor.ts @@ -1,5 +1,4 @@ -import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect'; -import { JsonObject } from '@angular-devkit/core'; +import { ExecutorContext, logger, stripIndents } from '@nrwl/devkit'; import { build, Configuration, PublishOptions, Platform, Arch, createTargets, FileSet, CliOptions } from 'electron-builder'; import { writeFile, statSync, readFileSync } from 'fs'; @@ -13,7 +12,6 @@ import { Observable, from, of } from 'rxjs'; import { map, tap, concatMap, catchError } from 'rxjs/operators'; import { platform } from 'os'; -import { stripIndents } from '@angular-devkit/core/src/utils/literals'; import stripJsonComments from 'strip-json-comments'; try { @@ -34,24 +32,23 @@ export interface PackageElectronBuilderOptions extends Configuration { publishPolicy?: PublishOptions["publish"]; } -export interface PackageElectronBuilderOutput extends BuilderOutput { +export interface PackageElectronBuilderOutput { target?: any; + success: boolean; outputPath: string | string[]; } -export default createBuilder(run); - -function run(rawOptions: JsonObject & PackageElectronBuilderOptions, context: BuilderContext): Observable { - return from(getSourceRoot(context)).pipe( +export function executor(rawOptions: PackageElectronBuilderOptions, context: ExecutorContext): Observable { + return from(of(getSourceRoot(context))).pipe( tap(_ => { - context.logger.warn(stripIndents` + logger.warn(stripIndents` ********************************************************* DO NOT FORGET TO REBUILD YOUR FRONTEND & BACKEND PROJECTS FOR PRODUCTION BEFORE PACKAGING / MAKING YOUR ARTIFACT! *********************************************************`); }), map(({ sourceRoot, projectRoot }) => - normalizePackagingOptions(rawOptions, context.workspaceRoot, sourceRoot) + normalizePackagingOptions(rawOptions, context.root, sourceRoot) ), map(options => mergePresetOptions(options) @@ -117,7 +114,7 @@ function _createTargets(platforms: Platform[], type: string, arch: string): Map< return createTargets(platforms, null, arch); } -function _createBaseConfig(options: PackageElectronBuilderOptions, context: BuilderContext): Configuration { +function _createBaseConfig(options: PackageElectronBuilderOptions, context: ExecutorContext): Configuration { const files: Array = options.files ? (Array.isArray(options.files) ? options.files : [options.files] ): Array() const outputPath = options.prepackageOnly ? @@ -126,7 +123,7 @@ function _createBaseConfig(options: PackageElectronBuilderOptions, context: Buil return { directories: { ...options.directories, - output: join(context.workspaceRoot, outputPath) + output: join(context.root, outputPath) }, files: files.concat([ { @@ -168,7 +165,7 @@ function _createConfigFromOptions(options: PackageElectronBuilderOptions, baseCo return config; } -function _normalizeBuilderOptions(targets: Map>, config: Configuration, rawOptions: JsonObject & PackageElectronBuilderOptions): CliOptions { +function _normalizeBuilderOptions(targets: Map>, config: Configuration, rawOptions: PackageElectronBuilderOptions): CliOptions { let normalizedOptions: CliOptions = { config, publish: rawOptions.publishPolicy || null }; if (rawOptions.prepackageOnly) { @@ -199,3 +196,5 @@ function addMissingDefaultOptions(options: PackageElectronBuilderOptions): Packa return options; } + +export default executor; diff --git a/packages/nx-electron/src/executors/package/schema.json b/packages/nx-electron/src/executors/package/schema.json index 3516fea..135bb50 100644 --- a/packages/nx-electron/src/executors/package/schema.json +++ b/packages/nx-electron/src/executors/package/schema.json @@ -2,6 +2,7 @@ "title": "Electron Application Packaging Target", "description": "Electron application packaging target options for Build Facade", "type": "object", + "cli": "nx", "properties": { "name": { "description": "The name of the electron application.", diff --git a/packages/nx-electron/src/utils/config.ts b/packages/nx-electron/src/utils/config.ts index a44ab2a..90d04bf 100644 --- a/packages/nx-electron/src/utils/config.ts +++ b/packages/nx-electron/src/utils/config.ts @@ -1,19 +1,19 @@ -import { Configuration, ProgressPlugin, DefinePlugin, Stats, Plugin } from 'webpack'; +import { Configuration, ProgressPlugin, DefinePlugin, Stats, Plugin, WebpackPluginInstance } from 'webpack'; import * as ts from 'typescript'; import { join } from 'path'; import { LicenseWebpackPlugin } from 'license-webpack-plugin'; -import CircularDependencyPlugin = require('circular-dependency-plugin'); import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); import TsConfigPathsPlugin from 'tsconfig-paths-webpack-plugin'; import CopyWebpackPlugin from 'copy-webpack-plugin'; -import { readTsConfig } from '@nrwl/workspace'; +import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import { BuildBuilderOptions } from './types'; export const MAIN_OUTPUT_FILENAME = 'main.js'; export const INDEX_OUTPUT_FILENAME = 'index.js'; export const DEFAULT_APPS_DIR = 'apps'; +export const OUT_FILENAME_TEMPLATE = '[name].js'; export function getBaseWebpackPartial(options: BuildBuilderOptions): Configuration { const { options: compilerOptions } = readTsConfig(options.tsConfig); @@ -22,31 +22,43 @@ export function getBaseWebpackPartial(options: BuildBuilderOptions): Configurati compilerOptions.target !== ts.ScriptTarget.ES5; const mainFields = [...(supportsEs2015 ? ['es2015'] : []), 'module', 'main']; const extensions = ['.ts', '.tsx', '.mjs', '.js', '.jsx']; - const webpackConfig: Configuration = { + + const additionalEntryPoints = options.additionalEntryPoints?.reduce( + (obj, current) => ({ ...obj, [current.entryName]: current.entryPath }), {} as { [entryName: string]: string }) ?? {}; + + const webpackConfig: Configuration = { entry: { - ...options.webpackEntries, - main: options.main + main: [options.main], + ...additionalEntryPoints, }, devtool: options.sourceMap ? 'source-map' : false, mode: options.optimization ? 'production' : 'development', output: { path: options.outputPath, - filename: '[name].js' + filename: + options.additionalEntryPoints?.length > 0 + ? OUT_FILENAME_TEMPLATE + : options.outputFileName, + hashFunction: 'xxhash64', + // Disabled for performance + pathinfo: false, }, module: { + // Enabled for performance + // unsafeCache: true, rules: [ { - test: /\.(j|t)sx?$/, - loader: `ts-loader`, + test: /\.([jt])sx?$/, + loader: require.resolve(`ts-loader`), exclude: /node_modules/, options: { configFile: options.tsConfig, transpileOnly: true, // https://github.com/TypeStrong/ts-loader/pull/685 - experimentalWatchApi: true - } - } - ] + experimentalWatchApi: true, + }, + }, + ], }, resolve: { extensions, @@ -65,7 +77,11 @@ export function getBaseWebpackPartial(options: BuildBuilderOptions): Configurati }, plugins: [ new ForkTsCheckerWebpackPlugin({ - typescript: { configFile: options.tsConfig } + typescript: { + enabled: true, + configFile: options.tsConfig, + memoryLimit: options.memoryLimit || 2018 + } }), new DefinePlugin({ __BUILD_VERSION__: JSON.stringify(require(join(options.root, "package.json")).version), @@ -79,7 +95,7 @@ export function getBaseWebpackPartial(options: BuildBuilderOptions): Configurati stats: getStatsConfig(options) }; - const extraPlugins: Plugin[] = []; + const extraPlugins: WebpackPluginInstance[] = []; if (options.progress) { extraPlugins.push(new ProgressPlugin()); @@ -94,44 +110,54 @@ export function getBaseWebpackPartial(options: BuildBuilderOptions): Configurati }, perChunkOutput: false, outputFilename: `3rdpartylicenses.txt` - }) as any + }) as unknown as WebpackPluginInstance ); } // process asset entries - if (options.assets && options.assets.length >= 1) { - const copyWebpackPluginPatterns = options.assets.map((asset: any) => { - return { - context: asset.input, - // Now we remove starting slash to make Webpack place it from the output root. - to: asset.output, - globOptions: { - ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'].concat(asset.ignore || []), - dot: true - }, - from: asset.glob, - }; + if (Array.isArray(options.assets) && options.assets.length > 0) { + const copyWebpackPluginInstance = new CopyWebpackPlugin({ + patterns: options.assets.map((asset) => { + return { + context: asset.input, + // Now we remove starting slash to make Webpack place it from the output root. + to: asset.output, + from: asset.glob, + globOptions: { + ignore: [ + '.gitkeep', + '**/.DS_Store', + '**/Thumbs.db', + ...(asset.ignore ?? []), + ], + dot: true, + }, + }; + }), }); - const copyWebpackPluginOptions = { - ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'] - }; - - const copyWebpackPluginInstance = new CopyWebpackPlugin({ - patterns: copyWebpackPluginPatterns, - // options: copyWebpackPluginOptions + new CopyWebpackPlugin({ + patterns: options.assets.map((asset: any) => { + return { + context: asset.input, + // Now we remove starting slash to make Webpack place it from the output root. + to: asset.output, + from: asset.glob, + globOptions: { + ignore: [ + '.gitkeep', + '**/.DS_Store', + '**/Thumbs.db', + ...(asset.ignore ?? []), + ], + dot: true, + }, + }; + }), }); extraPlugins.push(copyWebpackPluginInstance); } - if (options.showCircularDependencies) { - extraPlugins.push( - new CircularDependencyPlugin({ - exclude: /[\\\/]node_modules[\\\/]/ - }) - ); - } - webpackConfig.plugins = [...webpackConfig.plugins, ...extraPlugins]; return webpackConfig; diff --git a/packages/nx-electron/src/utils/electron.config.ts b/packages/nx-electron/src/utils/electron.config.ts index 7fd60a3..46c057e 100644 --- a/packages/nx-electron/src/utils/electron.config.ts +++ b/packages/nx-electron/src/utils/electron.config.ts @@ -1,5 +1,6 @@ +import { appRootPath } from '@nrwl/tao/src/utils/app-root'; import { Configuration } from 'webpack'; -import mergeWebpack from 'webpack-merge'; +import { merge } from 'webpack-merge'; import nodeExternals from 'webpack-node-externals'; import TerserPlugin from 'terser-webpack-plugin'; @@ -50,22 +51,23 @@ function getElectronPartial(options: BuildElectronBuilderOptions): Configuration } if (options.externalDependencies === 'all') { - webpackConfig.externals = [nodeExternals()]; + const modulesDir = `${appRootPath}/node_modules`; + webpackConfig.externals = [nodeExternals({ modulesDir })]; } else if (Array.isArray(options.externalDependencies)) { webpackConfig.externals = [ - function(context, request, callback: Function) { - if (options.externalDependencies.includes(request)) { + function (context, callback: Function) { + if (options.externalDependencies.includes(context.request)) { // not bundled - return callback(null, 'commonjs ' + request); + return callback(null, `commonjs ${context.request}`); } // bundled callback(); - } + }, ]; } return webpackConfig; } export function getElectronWebpackConfig(options: BuildElectronBuilderOptions) { - return mergeWebpack(getBaseWebpackPartial(options), getElectronPartial(options)); // was array + return merge([getBaseWebpackPartial(options), getElectronPartial(options)]); } diff --git a/packages/nx-electron/src/utils/normalize.ts b/packages/nx-electron/src/utils/normalize.ts index b3cf653..ca419f9 100644 --- a/packages/nx-electron/src/utils/normalize.ts +++ b/packages/nx-electron/src/utils/normalize.ts @@ -1,10 +1,15 @@ -import { normalize } from '@angular-devkit/core'; import { resolve, dirname, relative, basename } from 'path'; -import { BuildBuilderOptions, FileReplacement } from './types'; -import { Configuration as ElectronPackagerOptions } from 'electron-builder'; +import { AdditionalEntryPoint} from './types'; +import { BuildElectronBuilderOptions, NormalizedBuildElectronBuilderOptions} from '../executors/build/executor'; +import { PackageElectronBuilderOptions } from '../executors/package/executor'; import { statSync } from 'fs'; -export function normalizeBuildOptions(options: T, root: string, sourceRoot: string, projectRoot: string): T { +export interface FileReplacement { + replace: string; + with: string; +} + +export function normalizeBuildOptions( options: BuildElectronBuilderOptions, root: string, sourceRoot: string, projectRoot: string): NormalizedBuildElectronBuilderOptions { return { ...options, root, @@ -15,13 +20,16 @@ export function normalizeBuildOptions(options: T, tsConfig: resolve(root, options.tsConfig), fileReplacements: normalizeFileReplacements(root, options.fileReplacements), assets: normalizeAssets(options.assets, root, sourceRoot), - webpackConfig: options.webpackConfig - ? resolve(root, options.webpackConfig) - : options.webpackConfig + webpackConfig: options.webpackConfig ? resolve(root, options.webpackConfig) : options.webpackConfig, + additionalEntryPoints: normalizeAdditionalEntries( + root, + options.additionalEntryPoints ?? [] + ), + outputFileName: options.outputFileName ?? 'main.js', }; } -export function normalizePackagingOptions(options: T, root: string, sourceRoot: string): T { +export function normalizePackagingOptions(options: T, root: string, sourceRoot: string): T { return { ...options, root, @@ -29,11 +37,17 @@ export function normalizePackagingOptions(opt }; } -function normalizeAssets(assets: any[], root: string, sourceRoot: string): any[] { - return assets.map(asset => { +function normalizeAssets( + assets: any[], + root: string, + sourceRoot: string +): any[] { + if (!Array.isArray(assets)) { + return []; + } + return assets.map((asset) => { if (typeof asset === 'string') { - const assetPath = normalize(asset); - const resolvedAssetPath = resolve(root, assetPath); + const resolvedAssetPath = resolve(root, asset); const resolvedSourceRoot = resolve(root, sourceRoot); if (!resolvedAssetPath.startsWith(resolvedSourceRoot)) { @@ -51,7 +65,7 @@ function normalizeAssets(assets: any[], root: string, sourceRoot: string): any[] return { input, output, - glob + glob, }; } else { if (asset.output.startsWith('..')) { @@ -60,21 +74,44 @@ function normalizeAssets(assets: any[], root: string, sourceRoot: string): any[] ); } - const assetPath = normalize(asset.input); - const resolvedAssetPath = resolve(root, assetPath); + const resolvedAssetPath = resolve(root, asset.input); return { ...asset, input: resolvedAssetPath, // Now we remove starting slash to make Webpack place it from the output root. - output: asset.output.replace(/^\//, '') + output: asset.output.replace(/^\//, ''), }; } }); } -function normalizeFileReplacements(root: string, fileReplacements: FileReplacement[]): FileReplacement[] { - return fileReplacements.map(fileReplacement => ({ +function normalizeFileReplacements( + root: string, + fileReplacements: FileReplacement[] +): FileReplacement[] { + return fileReplacements.map((fileReplacement) => ({ replace: resolve(root, fileReplacement.replace), - with: resolve(root, fileReplacement.with) + with: resolve(root, fileReplacement.with), })); } + +function normalizePluginPath(path: string, root: string) { + try { + return require.resolve(path); + } catch { + return resolve(root, path); + } +} + +function normalizeAdditionalEntries( + root: string, + additionalEntries: AdditionalEntryPoint[] +) { + return additionalEntries.map( + ({ entryName, entryPath }) => + ({ + entryName, + entryPath: resolve(root, entryPath), + } as AdditionalEntryPoint) + ); +} \ No newline at end of file diff --git a/packages/nx-electron/src/utils/testing.angular.ts b/packages/nx-electron/src/utils/testing.angular.ts deleted file mode 100644 index 7acf522..0000000 --- a/packages/nx-electron/src/utils/testing.angular.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { join } from 'path'; - -import { externalSchematic, Rule, Tree } from '@angular-devkit/schematics'; -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; -import { names } from '@nrwl/devkit'; -import { toFileName } from '@nrwl/workspace'; -import { createEmptyWorkspace } from '@nrwl/workspace/testing'; - -const testRunner = new SchematicTestRunner( - '@nrwl/angular', - join(__dirname, '../../collection.json') -); - -export function runSchematic( - schematicName: string, - options: SchemaOptions, - tree: Tree -) { - return testRunner.runSchematicAsync(schematicName, options, tree).toPromise(); -} - -export function runExternalSchematic( - collectionName: string, - schematicName: string, - options: SchemaOptions, - tree: Tree -) { - return testRunner - .runExternalSchematicAsync(collectionName, schematicName, options, tree) - .toPromise(); -} - -export function callRule(rule: Rule, tree: Tree): Promise { - return testRunner.callRule(rule, tree).toPromise(); -} - -export interface AppConfig { - appName: string; // name of app - appModule: string; // app/app.module.ts in the above sourceDir -} - -export interface LibConfig { - name: string; - module: string; - barrel: string; -} - -var appConfig: AppConfig; // configure built in createApp() -var libConfig: LibConfig; - -export function getAppConfig(): AppConfig { - return appConfig; -} - -export function getLibConfig(): LibConfig { - return libConfig; -} - -export function createApp( - tree: Tree, - appName: string, - routing: boolean = true -): Tree { - appName = toFileName(appName); - // save for getAppDir() lookup by external *.spec.ts tests - appConfig = { - appName, - appModule: `/apps/${appName}/src/app/app.module.ts` - }; - - tree.create( - appConfig.appModule, - ` - import { NgModule } from '@angular/core'; - import { BrowserModule } from '@angular/platform-browser'; - ${routing ? "import { RouterModule } from '@angular/router'" : ''}; - import { AppComponent } from './app.component'; - @NgModule({ - imports: [BrowserModule, ${routing ? 'RouterModule.forRoot([])' : ''}], - declarations: [AppComponent], - bootstrap: [AppComponent] - }) - export class AppModule {} - ` - ); - tree.create( - `/apps/${appName}/src/main.ts`, - ` - import { enableProdMode } from '@angular/core'; - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - - import { AppModule } from './app/app.module'; - import { environment } from './environments/environment'; - - if (environment.production) { - enableProdMode(); - } - - platformBrowserDynamic() - .bootstrapModule(AppModule) - .catch(err => console.log(err)); - ` - ); - tree.create( - `/apps/${appName}/tsconfig.app.json`, - JSON.stringify({ - include: ['**/*.ts'] - }) - ); - tree.create( - `/apps/${appName}-e2e/tsconfig.e2e.json`, - JSON.stringify({ - include: ['../**/*.ts'] - }) - ); - tree.overwrite( - '/workspace.json', - JSON.stringify({ - newProjectRoot: '', - version: 1, - projects: { - [appName]: { - root: `apps/${appName}`, - sourceRoot: `apps/${appName}/src`, - architect: { - build: { - options: { - main: `apps/${appName}/src/main.ts` - } - }, - serve: { - options: {} - } - } - } - } - }) - ); - return tree; -} - -export function createLib(tree: Tree, libName: string): Tree { - const { name, className, fileName, propertyName } = names(libName); - - libConfig = { - name, - module: `/libs/${propertyName}/src/lib/${fileName}.module.ts`, - barrel: `/libs/${propertyName}/src/index.ts` - }; - - tree.create( - libConfig.module, - ` - import { NgModule } from '@angular/core'; - import { CommonModule } from '@angular/common'; - @NgModule({ - imports: [ - CommonModule - ], - providers: [] - }) - export class ${className}Module { } - ` - ); - tree.create( - libConfig.barrel, - ` - export * from './lib/${fileName}.module'; - ` - ); - return tree; -} - -export async function createTestUILib(libName: string): Promise { - let appTree = Tree.empty(); - appTree = createEmptyWorkspace(appTree); - appTree = await callRule( - externalSchematic('@nrwl/angular', 'library', { - name: libName - }), - appTree - ); - appTree = await callRule( - externalSchematic('@schematics/angular', 'component', { - name: 'test-button', - project: libName - }), - appTree - ); - appTree.overwrite( - `libs/${libName}/src/lib/test-button/test-button.component.ts`, - ` -import { Component, OnInit, Input } from '@angular/core'; - -export type ButtonStyle = 'default' | 'primary' | 'accent'; - -@Component({ - selector: 'proj-test-button', - templateUrl: './test-button.component.html', - styleUrls: ['./test-button.component.css'] -}) -export class TestButtonComponent implements OnInit { - @Input('buttonType') type = 'button'; - @Input() style: ButtonStyle = 'default'; - @Input() age: number; - @Input() isOn = false; - - constructor() { } - - ngOnInit() { - } - -} -` - ); - appTree.overwrite( - `libs/${libName}/src/lib/test-button/test-button.component.html`, - `` - ); - appTree = await callRule( - externalSchematic('@schematics/angular', 'component', { - name: 'test-other', - project: libName - }), - appTree - ); - return appTree; -} diff --git a/packages/nx-electron/src/utils/testing.ts b/packages/nx-electron/src/utils/testing.ts deleted file mode 100644 index 7208485..0000000 --- a/packages/nx-electron/src/utils/testing.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { join } from 'path'; -import { schema } from '@angular-devkit/core'; -import { Rule, Tree } from '@angular-devkit/schematics'; -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; -import { Architect } from '@angular-devkit/architect'; -import { TestingArchitectHost } from '@angular-devkit/architect/testing'; - -import { MockBuilderContext } from '@nrwl/workspace/testing'; - -const testRunner = new SchematicTestRunner( - '@nrwl/node', - join(__dirname, '../../collection.json') -); - -testRunner.registerCollection( - '@nrwl/jest', - join(__dirname, '../../../jest/collection.json') -); - -testRunner.registerCollection( - '@nrwl/workspace', - join(__dirname, '../../../workspace/collection.json') -); - -export function runSchematic( - schematicName: string, - options: T, - tree: Tree -) { - return testRunner.runSchematicAsync(schematicName, options, tree).toPromise(); -} - -export function callRule(rule: Rule, tree: Tree): Promise { - return testRunner.callRule(rule, tree).toPromise(); -} - -export async function getTestArchitect() { - const architectHost = new TestingArchitectHost('/root', '/root'); - const registry = new schema.CoreSchemaRegistry(); - registry.addPostTransform(schema.transforms.addUndefinedDefaults); - - const architect = new Architect(architectHost, registry); - - await architectHost.addBuilderFromPackage(join(__dirname, '../..')); - - return [architect, architectHost] as [Architect, TestingArchitectHost]; -} - -export async function getMockContext() { - const [architect, architectHost] = await getTestArchitect(); - - const context = new MockBuilderContext(architect, architectHost); - await context.addBuilderFromPackage(join(__dirname, '../..')); - - return context; -} diff --git a/packages/nx-electron/src/utils/types.ts b/packages/nx-electron/src/utils/types.ts index 60128a5..3fd0e7d 100644 --- a/packages/nx-electron/src/utils/types.ts +++ b/packages/nx-electron/src/utils/types.ts @@ -1,6 +1,3 @@ -import { Path } from '@angular-devkit/core'; -import { Entry } from 'webpack'; - export interface FileReplacement { replace: string; with: string; @@ -18,6 +15,11 @@ export interface SourceMapOptions { hidden: boolean; } +export interface AdditionalEntryPoint { + entryName: string; + entryPath: string; +} + export interface BuildBuilderOptions { main: string; outputPath: string; @@ -25,7 +27,7 @@ export interface BuildBuilderOptions { watch?: boolean; sourceMap?: boolean | SourceMapOptions; optimization?: boolean | OptimizationOptions; - showCircularDependencies?: boolean; + maxWorkers?: number; memoryLimit?: number; poll?: number; @@ -39,9 +41,13 @@ export interface BuildBuilderOptions { verbose?: boolean; webpackConfig?: string; - webpackEntries?: Entry; root?: string; - sourceRoot?: Path; - projectRoot?: string; + sourceRoot?: string; + projectRoot?: string; + + // tsPlugins?: TsPluginEntry[]; + + additionalEntryPoints?: AdditionalEntryPoint[]; + outputFileName?: string; } diff --git a/packages/nx-electron/src/utils/workspace.ts b/packages/nx-electron/src/utils/workspace.ts index 953581b..0382471 100644 --- a/packages/nx-electron/src/utils/workspace.ts +++ b/packages/nx-electron/src/utils/workspace.ts @@ -1,19 +1,12 @@ -import { BuilderContext } from '@angular-devkit/architect'; -import { workspaces, normalize } from '@angular-devkit/core'; -import { NxScopedHost } from '@nrwl/devkit/ngcli-adapter'; +import { ExecutorContext } from "@nrwl/devkit"; -export async function getSourceRoot(context: BuilderContext): Promise<{ sourceRoot: string; projectRoot: string }> { - const workspaceHost = workspaces.createWorkspaceHost(new NxScopedHost(normalize(context.workspaceRoot))); - const { workspace } = await workspaces.readWorkspace('', workspaceHost); - const { project } = context.target; - const { sourceRoot, root } = workspace.projects.get(project); + +export function getSourceRoot(context: ExecutorContext): { sourceRoot: string; projectRoot: string } { + const { sourceRoot, root } = context.workspace.projects[context.projectName]; if (sourceRoot && root) { return { sourceRoot, projectRoot: root }; } - context.reportStatus('Error'); - const message = `${project} does not have a sourceRoot or root. Please define both.`; - context.logger.error(message); - throw new Error(message); + throw new Error('Project does not have a sourceRoot or root. Please define both.'); } \ No newline at end of file