diff --git a/packages/nx/src/project-graph/plugins/get-plugins.ts b/packages/nx/src/project-graph/plugins/get-plugins.ts index ac4063041ceabf..9dfd9143f0e1f3 100644 --- a/packages/nx/src/project-graph/plugins/get-plugins.ts +++ b/packages/nx/src/project-graph/plugins/get-plugins.ts @@ -13,6 +13,7 @@ import { cleanupPluginTSTranspiler, pluginTranspilerIsRegistered, } from './transpiler'; +import { isIsolationEnabled } from './isolation/enabled'; /** * Stuff for specified NX Plugins. @@ -97,23 +98,6 @@ export function cleanupPlugins() { * Stuff for generic loading */ -function isIsolationEnabled() { - // Explicitly enabled, regardless of further conditions - if (process.env.NX_ISOLATE_PLUGINS === 'true') { - return true; - } - if ( - // Explicitly disabled - process.env.NX_ISOLATE_PLUGINS === 'false' || - // Isolation is disabled on WASM builds currently. - IS_WASM - ) { - return false; - } - // Default value - return true; -} - const loadingMethod = isIsolationEnabled() ? loadNxPluginInIsolation : loadNxPlugin; diff --git a/packages/nx/src/project-graph/plugins/isolation/enabled.ts b/packages/nx/src/project-graph/plugins/isolation/enabled.ts new file mode 100644 index 00000000000000..471d01ed28133b --- /dev/null +++ b/packages/nx/src/project-graph/plugins/isolation/enabled.ts @@ -0,0 +1,18 @@ +import { IS_WASM } from 'nx/src/native'; + +export function isIsolationEnabled() { + // Explicitly enabled, regardless of further conditions + if (process.env.NX_ISOLATE_PLUGINS === 'true') { + return true; + } + if ( + // Explicitly disabled + process.env.NX_ISOLATE_PLUGINS === 'false' || + // Isolation is disabled on WASM builds currently. + IS_WASM + ) { + return false; + } + // Default value + return true; +} diff --git a/packages/nx/src/project-graph/plugins/isolation/messaging.ts b/packages/nx/src/project-graph/plugins/isolation/messaging.ts index 50c6b50d3c0998..f3e2ffb5e70e57 100644 --- a/packages/nx/src/project-graph/plugins/isolation/messaging.ts +++ b/packages/nx/src/project-graph/plugins/isolation/messaging.ts @@ -129,6 +129,7 @@ export interface PluginWorkerPreRunMessageResult { | { tx: string; success: true; + mutations: NodeJS.ProcessEnv; } | { success: false; diff --git a/packages/nx/src/project-graph/plugins/isolation/plugin-pool.ts b/packages/nx/src/project-graph/plugins/isolation/plugin-pool.ts index b06871f7623a7b..69ad20eb224f85 100644 --- a/packages/nx/src/project-graph/plugins/isolation/plugin-pool.ts +++ b/packages/nx/src/project-graph/plugins/isolation/plugin-pool.ts @@ -287,7 +287,7 @@ function createWorkerHandler( preRunResult: ({ tx, ...result }) => { const { resolver, rejector } = pending.get(tx); if (result.success) { - resolver(); + resolver(result.mutations); } else if (result.success === false) { rejector(result.error); } diff --git a/packages/nx/src/project-graph/plugins/isolation/plugin-worker.ts b/packages/nx/src/project-graph/plugins/isolation/plugin-worker.ts index 32d7caa6b4610d..4c554ea04b7e52 100644 --- a/packages/nx/src/project-graph/plugins/isolation/plugin-worker.ts +++ b/packages/nx/src/project-graph/plugins/isolation/plugin-worker.ts @@ -147,10 +147,10 @@ const server = createServer((socket) => { }, preRun: async ({ tx, context }) => { try { - await plugin.preRun?.(context); + const mutations = await plugin.preRun?.(context); return { type: 'preRunResult', - payload: { success: true, tx }, + payload: { success: true, tx, mutations }, }; } catch (e) { return { diff --git a/packages/nx/src/project-graph/plugins/loaded-nx-plugin.ts b/packages/nx/src/project-graph/plugins/loaded-nx-plugin.ts index 68b5e15db800e8..a6ab834d2b49ed 100644 --- a/packages/nx/src/project-graph/plugins/loaded-nx-plugin.ts +++ b/packages/nx/src/project-graph/plugins/loaded-nx-plugin.ts @@ -16,7 +16,7 @@ import type { ProjectsMetadata, } from './public-api'; import { createNodesFromFiles } from './utils'; -import type { TaskResults } from '../../tasks-runner/life-cycle'; +import { isIsolationEnabled } from './isolation/enabled'; export class LoadedNxPlugin { readonly name: string; @@ -38,7 +38,7 @@ export class LoadedNxPlugin { graph: ProjectGraph, context: CreateMetadataContext ) => Promise; - readonly preRun?: (context: PreRunContext) => Promise; + readonly preRun?: (context: PreRunContext) => Promise; readonly postRun?: (context: PostRunContext) => Promise; readonly options?: unknown; @@ -114,18 +114,40 @@ export class LoadedNxPlugin { } if (plugin.preRun) { - this.preRun = async (context: PreRunContext) => + this.preRun = async (context: PreRunContext) => { + const updates = {}; + const originalEnv = process.env; + let revokeFn: () => void; + if (isIsolationEnabled()) { + const { proxy, revoke } = Proxy.revocable( + process.env, + { + set: (target, key: string, value) => { + target[key] = value; + updates[key] = value; + return true; + }, + } + ); + process.env = proxy; + revokeFn = revoke; + } plugin.preRun(this.options, context); - } - if (plugin.postRun) { - this.postRun = async (context: PostRunContext) => - plugin.postRun(this.options, context); + if (revokeFn) { + revokeFn(); + } + process.env = originalEnv; + for (const key in updates) { + process.env[key] = updates[key]; + } + return updates; + }; + + if (plugin.postRun) { + this.postRun = async (context: PostRunContext) => + plugin.postRun(this.options, context); + } } } } - -export type CreateNodesResultWithContext = CreateNodesResult & { - file: string; - pluginName: string; -}; diff --git a/packages/nx/src/project-graph/plugins/run-hooks.ts b/packages/nx/src/project-graph/plugins/run-hooks.ts index 92effee80c89b0..12ce1295bdd876 100644 --- a/packages/nx/src/project-graph/plugins/run-hooks.ts +++ b/packages/nx/src/project-graph/plugins/run-hooks.ts @@ -1,18 +1,19 @@ import type { PostRunContext, PreRunContext } from './public-api'; import type { LoadedNxPlugin } from './loaded-nx-plugin'; +import { isIsolationEnabled } from './isolation/enabled'; export async function runPreRun( plugins: LoadedNxPlugin[], pluginContext: PreRunContext ) { performance.mark(`preRun:start`); - await Promise.all( + const envs = await Promise.all( plugins .filter((p) => p.preRun) .map(async (plugin) => { performance.mark(`${plugin.name}:preRun:start`); try { - await plugin.preRun(pluginContext); + return await plugin.preRun(pluginContext); } finally { performance.mark(`${plugin.name}:preRun:end`); performance.measure( @@ -23,6 +24,13 @@ export async function runPreRun( } }) ); + if (isIsolationEnabled()) { + for (const env of envs) { + for (const key in env) { + process.env[key] = env[key]; + } + } + } performance.mark(`preRun:end`); performance.measure(`preRun`, `preRun:start`, `preRun:end`); } diff --git a/packages/nx/src/tasks-runner/run-command.ts b/packages/nx/src/tasks-runner/run-command.ts index c06739ed5edc5b..29b5514eeb6940 100644 --- a/packages/nx/src/tasks-runner/run-command.ts +++ b/packages/nx/src/tasks-runner/run-command.ts @@ -195,7 +195,12 @@ export async function runCommand( projectsToRun, currentProjectGraph, { nxJson }, - nxArgs, + { + ...nxArgs, + skipNxCache: + process.env.NX_SKIP_NX_CACHE === 'true' || + process.env.DISABLE_NX_CACHE === 'true', + }, overrides, initiatingProject, extraTargetDependencies, diff --git a/packages/nx/src/tasks-runner/task-orchestrator.ts b/packages/nx/src/tasks-runner/task-orchestrator.ts index 76b1114590ab07..565b90ec3b7aae 100644 --- a/packages/nx/src/tasks-runner/task-orchestrator.ts +++ b/packages/nx/src/tasks-runner/task-orchestrator.ts @@ -230,7 +230,6 @@ export class TaskOrchestrator { task: Task; status: 'local-cache' | 'local-cache-kept-existing' | 'remote-cache'; }> { - task.startTime = Date.now(); const cachedResult = await this.cache.get(task); if (!cachedResult || cachedResult.code !== 0) return null; @@ -241,7 +240,6 @@ export class TaskOrchestrator { if (shouldCopyOutputsFromCache) { await this.cache.copyFilesFromCache(task.hash, cachedResult, outputs); } - task.endTime = Date.now(); const status = cachedResult.remote ? 'remote-cache' : shouldCopyOutputsFromCache @@ -545,6 +543,10 @@ export class TaskOrchestrator { // region Lifecycle private async preRunSteps(tasks: Task[], metadata: TaskMetadata) { + const now = Date.now(); + for (const task of tasks) { + task.startTime = now; + } await this.options.lifeCycle.startTasks(tasks, metadata); } @@ -558,7 +560,9 @@ export class TaskOrchestrator { doNotSkipCache: boolean, { groupId }: { groupId: number } ) { + const now = Date.now(); for (const task of tasks) { + task.endTime = now; await this.recordOutputsHash(task); }