UNPKG

@nx/js

Version:

The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects.

179 lines (178 loc) • 8.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.tscBatchExecutor = tscBatchExecutor; const devkit_1 = require("@nx/devkit"); const fs_1 = require("fs"); const async_iterator_1 = require("nx/src/utils/async-iterator"); const update_package_json_1 = require("../../utils/package-json/update-package-json"); const tsc_impl_1 = require("./tsc.impl"); const lib_1 = require("./lib"); const batch_1 = require("./lib/batch"); const create_entry_points_1 = require("../../utils/package-json/create-entry-points"); async function* tscBatchExecutor(taskGraph, inputs, overrides, context) { const tasksOptions = (0, batch_1.normalizeTasksOptions)(inputs, context); let shouldWatch = false; Object.values(tasksOptions).forEach((taskOptions) => { if (taskOptions.clean) { (0, fs_1.rmSync)(taskOptions.outputPath, { force: true, recursive: true }); } if (taskOptions.watch) { shouldWatch = true; } }); const taskInMemoryTsConfigMap = (0, lib_1.getProcessedTaskTsConfigs)(Object.keys(taskGraph.tasks), tasksOptions, context); const tsConfigTaskInfoMap = (0, batch_1.createTaskInfoPerTsConfigMap)(tasksOptions, context, Object.keys(taskGraph.tasks), taskInMemoryTsConfigMap); const tsCompilationContext = createTypescriptCompilationContext(tsConfigTaskInfoMap, taskInMemoryTsConfigMap, context); const logger = { error: (message, tsConfig) => { process.stderr.write(message); if (tsConfig) { tsConfigTaskInfoMap[tsConfig].terminalOutput += message; } }, info: (message, tsConfig) => { process.stdout.write(message); if (tsConfig) { tsConfigTaskInfoMap[tsConfig].terminalOutput += message; } }, warn: (message, tsConfig) => { process.stdout.write(message); if (tsConfig) { tsConfigTaskInfoMap[tsConfig].terminalOutput += message; } }, }; const processTaskPostCompilation = (tsConfig) => { if (tsConfigTaskInfoMap[tsConfig]) { const taskInfo = tsConfigTaskInfoMap[tsConfig]; taskInfo.assetsHandler.processAllAssetsOnceSync(); (0, update_package_json_1.updatePackageJson)({ ...taskInfo.options, additionalEntryPoints: (0, create_entry_points_1.createEntryPoints)(taskInfo.options.additionalEntryPoints, context.root), format: [(0, tsc_impl_1.determineModuleFormatFromTsConfig)(tsConfig)], }, taskInfo.context, taskInfo.projectGraphNode, taskInfo.buildableProjectNodeDependencies); taskInfo.endTime = Date.now(); } }; const typescriptCompilation = (0, lib_1.compileTypescriptSolution)(tsCompilationContext, shouldWatch, logger, { beforeProjectCompilationCallback: (tsConfig) => { if (tsConfigTaskInfoMap[tsConfig]) { tsConfigTaskInfoMap[tsConfig].startTime = Date.now(); } }, afterProjectCompilationCallback: processTaskPostCompilation, }); if (shouldWatch && !(0, devkit_1.isDaemonEnabled)()) { devkit_1.output.warn({ title: 'Nx Daemon is not enabled. Assets and package.json files will not be updated on file changes.', }); } if (shouldWatch && (0, devkit_1.isDaemonEnabled)()) { const taskInfos = Object.values(tsConfigTaskInfoMap); const watchAssetsChangesDisposer = await (0, batch_1.watchTaskProjectsFileChangesForAssets)(taskInfos); const watchProjectsChangesDisposer = await (0, batch_1.watchTaskProjectsPackageJsonFileChanges)(taskInfos, (changedTaskInfos) => { for (const t of changedTaskInfos) { (0, update_package_json_1.updatePackageJson)({ ...t.options, additionalEntryPoints: (0, create_entry_points_1.createEntryPoints)(t.options.additionalEntryPoints, context.root), format: [(0, tsc_impl_1.determineModuleFormatFromTsConfig)(t.options.tsConfig)], }, t.context, t.projectGraphNode, t.buildableProjectNodeDependencies); } }); const handleTermination = async (exitCode) => { watchAssetsChangesDisposer(); watchProjectsChangesDisposer(); process.exit(exitCode); }; process.on('SIGINT', () => handleTermination(128 + 2)); process.on('SIGTERM', () => handleTermination(128 + 15)); return yield* mapAsyncIterable(typescriptCompilation, async (iterator) => { // drain the iterator, we don't use the results await (0, async_iterator_1.getLastValueFromAsyncIterableIterator)(iterator); return { value: undefined, done: true }; }); } const toBatchExecutorTaskResult = (tsConfig, success) => ({ task: tsConfigTaskInfoMap[tsConfig].task, result: { success: success, terminalOutput: tsConfigTaskInfoMap[tsConfig].terminalOutput, startTime: tsConfigTaskInfoMap[tsConfig].startTime, endTime: tsConfigTaskInfoMap[tsConfig].endTime, }, }); let isCompilationDone = false; const taskTsConfigsToReport = new Set(Object.keys(taskGraph.tasks).map((t) => taskInMemoryTsConfigMap[t].path)); let tasksToReportIterator; const processSkippedTasks = () => { const { value: tsConfig, done } = tasksToReportIterator.next(); if (done) { return { value: undefined, done: true }; } tsConfigTaskInfoMap[tsConfig].startTime = Date.now(); processTaskPostCompilation(tsConfig); return { value: toBatchExecutorTaskResult(tsConfig, true), done: false }; }; return yield* mapAsyncIterable(typescriptCompilation, async (iterator) => { if (isCompilationDone) { return processSkippedTasks(); } const { value, done } = await iterator.next(); if (done) { if (taskTsConfigsToReport.size > 0) { /** * TS compilation is done but we still have tasks to report. This can * happen if, for example, a project is identified as affected, but * no file in the TS project is actually changed or if running a * task with `--skip-nx-cache` and the outputs are already there. There * can still be changes to assets or other files we need to process. * * Switch to handle the iterator for the tasks we still need to report. */ isCompilationDone = true; tasksToReportIterator = taskTsConfigsToReport.values(); return processSkippedTasks(); } return { value: undefined, done: true }; } taskTsConfigsToReport.delete(value.tsConfig); return { value: toBatchExecutorTaskResult(value.tsConfig, value.success), done: false, }; }); } exports.default = tscBatchExecutor; async function* mapAsyncIterable(iterable, nextFn) { return yield* { [Symbol.asyncIterator]() { const iterator = iterable[Symbol.asyncIterator].call(iterable); return { async next() { return await nextFn(iterator); }, }; }, }; } function createTypescriptCompilationContext(tsConfigTaskInfoMap, taskInMemoryTsConfigMap, context) { const tsCompilationContext = Object.entries(tsConfigTaskInfoMap).reduce((acc, [tsConfig, taskInfo]) => { acc[tsConfig] = { project: taskInfo.context.projectName, tsConfig: taskInfo.tsConfig, transformers: taskInfo.options.transformers, }; return acc; }, {}); Object.entries(taskInMemoryTsConfigMap).forEach(([task, tsConfig]) => { if (!tsCompilationContext[tsConfig.path]) { tsCompilationContext[tsConfig.path] = { project: (0, devkit_1.parseTargetString)(task, context).project, transformers: [], tsConfig: tsConfig, }; } }); return tsCompilationContext; }