From 4254c4bccefdcf2253f852914ebcd186aeb6bfc1 Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Thu, 24 Apr 2025 16:41:17 -0400 Subject: [PATCH] feat(core): allow executors to specify if they are continuous (#30821) ## Current Behavior The only way to set if a task is continuous is either directly in `project.json` or via Project Graph Plugins. ## Expected Behavior Executors know if they are definitely continuous or not. Plenty of existing continuous tasks are using executors. Executors are now able to define if they are continuous in their `schema.json` files. Thus, existing tasks configured with certain executors will automatically become continuous. ## Related Issue(s) Fixes # --- .../devkit/CreateDependenciesContext.md | 2 +- .../angular/executors/dev-server.json | 1 + .../module-federation-dev-server.json | 1 + .../executors/module-federation-dev-ssr.json | 1 + .../packages/js/executors/verdaccio.json | 1 + .../packages/next/executors/server.json | 1 + .../module-federation-dev-server.json | 1 + .../module-federation-ssr-dev-server.json | 1 + .../module-federation-static-server.json | 1 + .../packages/remix/executors/serve.json | 1 + .../packages/rspack/executors/dev-server.json | 1 + .../module-federation-dev-server.json | 1 + .../module-federation-ssr-dev-server.json | 1 + .../module-federation-static-server.json | 1 + .../rspack/executors/ssr-dev-server.json | 1 + .../storybook/executors/storybook.json | 1 + .../packages/vite/executors/dev-server.json | 1 + .../vite/executors/preview-server.json | 1 + .../packages/web/executors/file-server.json | 1 + .../webpack/executors/dev-server.json | 1 + .../webpack/executors/ssr-dev-server.json | 1 + e2e/angular/src/config.test.ts | 11 +--- .../src/builders/dev-server/schema.json | 1 + .../module-federation-dev-server/schema.json | 1 + .../schema.json | 1 + .../cypress/src/utils/start-dev-server.ts | 7 ++- .../src/executors/read-target-options.ts | 5 +- packages/jest/src/plugins/plugin.ts | 3 +- .../js/src/executors/verdaccio/schema.json | 1 + .../next/src/executors/server/schema.json | 1 + .../nx/src/command-line/run/executor-utils.ts | 10 ++++ packages/nx/src/command-line/run/run.ts | 4 +- packages/nx/src/config/misc-interfaces.ts | 1 + packages/nx/src/devkit-internals.ts | 5 +- .../src/plugins/package-json/create-nodes.ts | 7 ++- .../src/project-graph/plugins/public-api.ts | 2 +- .../utils/normalize-project-nodes.ts | 5 +- .../utils/project-configuration-utils.spec.ts | 7 ++- .../utils/project-configuration-utils.ts | 57 ++++++++++++++++--- .../nx/src/tasks-runner/batch/run-batch.ts | 7 ++- .../nx/src/tasks-runner/create-task-graph.ts | 2 +- packages/nx/src/tasks-runner/run-command.ts | 2 +- packages/nx/src/tasks-runner/utils.ts | 7 ++- packages/nx/src/utils/package-json.spec.ts | 50 ++++++++++++---- packages/nx/src/utils/package-json.ts | 24 +++++++- .../module-federation-dev-server/schema.json | 1 + .../schema.json | 1 + .../schema.json | 1 + .../remix/src/executors/serve/schema.json | 1 + .../src/executors/dev-server/schema.json | 1 + .../module-federation-dev-server/schema.json | 1 + .../schema.json | 1 + .../schema.json | 1 + .../src/executors/ssr-dev-server/schema.json | 1 + .../src/executors/storybook/schema.json | 1 + .../vite/src/executors/dev-server/schema.json | 1 + .../src/executors/preview-server/schema.json | 1 + .../web/src/executors/file-server/schema.json | 1 + .../src/executors/dev-server/schema.json | 1 + .../src/executors/ssr-dev-server/schema.json | 1 + 60 files changed, 205 insertions(+), 53 deletions(-) diff --git a/docs/generated/devkit/CreateDependenciesContext.md b/docs/generated/devkit/CreateDependenciesContext.md index ee04503fbf..2b863e2454 100644 --- a/docs/generated/devkit/CreateDependenciesContext.md +++ b/docs/generated/devkit/CreateDependenciesContext.md @@ -51,7 +51,7 @@ The `nx.json` configuration from the workspace • `Readonly` **projects**: `Record`\<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\> -The configuration of each project in the workspace. +The configuration of each project in the workspace keyed by project name. --- diff --git a/docs/generated/packages/angular/executors/dev-server.json b/docs/generated/packages/angular/executors/dev-server.json index 133167c989..838ec08c7e 100644 --- a/docs/generated/packages/angular/executors/dev-server.json +++ b/docs/generated/packages/angular/executors/dev-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/angular/src/builders/dev-server/dev-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "$schema": "http://json-schema.org/draft-07/schema", "title": "Schema for Webpack Dev Server", diff --git a/docs/generated/packages/angular/executors/module-federation-dev-server.json b/docs/generated/packages/angular/executors/module-federation-dev-server.json index 5c8f7b3cdf..d27cfdf967 100644 --- a/docs/generated/packages/angular/executors/module-federation-dev-server.json +++ b/docs/generated/packages/angular/executors/module-federation-dev-server.json @@ -4,6 +4,7 @@ "schema": { "$schema": "http://json-schema.org/draft-07/schema", "title": "Schema for Module Federation Dev Server", + "continuous": true, "outputCapture": "direct-nodejs", "description": "Serves host [Module Federation](https://module-federation.io/) applications ([webpack](https://webpack.js.org/)-based) allowing to specify which remote applications should be served with the host.", "type": "object", diff --git a/docs/generated/packages/angular/executors/module-federation-dev-ssr.json b/docs/generated/packages/angular/executors/module-federation-dev-ssr.json index 72f8ef6db7..50c7824466 100644 --- a/docs/generated/packages/angular/executors/module-federation-dev-ssr.json +++ b/docs/generated/packages/angular/executors/module-federation-dev-ssr.json @@ -4,6 +4,7 @@ "schema": { "$schema": "http://json-schema.org/draft-07/schema", "title": "Module Federation SSR Dev Server Target", + "continuous": true, "outputCapture": "direct-nodejs", "description": "The module-federation-ssr-dev-server executor is reserved exclusively for use with host SSR Module Federation applications. It allows the user to specify which remote applications should be served with the host.", "type": "object", diff --git a/docs/generated/packages/js/executors/verdaccio.json b/docs/generated/packages/js/executors/verdaccio.json index 48d1b6907b..3e39353d36 100644 --- a/docs/generated/packages/js/executors/verdaccio.json +++ b/docs/generated/packages/js/executors/verdaccio.json @@ -6,6 +6,7 @@ "version": 2, "title": "Verdaccio Local Registry", "description": "Start a local registry with Verdaccio.", + "continuous": true, "cli": "nx", "type": "object", "properties": { diff --git a/docs/generated/packages/next/executors/server.json b/docs/generated/packages/next/executors/server.json index b24c459b32..1102e1e085 100644 --- a/docs/generated/packages/next/executors/server.json +++ b/docs/generated/packages/next/executors/server.json @@ -3,6 +3,7 @@ "implementation": "/packages/next/src/executors/server/server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "pipe", "cli": "nx", "title": "Next Serve", diff --git a/docs/generated/packages/react/executors/module-federation-dev-server.json b/docs/generated/packages/react/executors/module-federation-dev-server.json index 7684b5b2f7..045625e9bb 100644 --- a/docs/generated/packages/react/executors/module-federation-dev-server.json +++ b/docs/generated/packages/react/executors/module-federation-dev-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/react/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation Dev Server", "description": "Serve a web application.", diff --git a/docs/generated/packages/react/executors/module-federation-ssr-dev-server.json b/docs/generated/packages/react/executors/module-federation-ssr-dev-server.json index a7b1e53a04..cb4cf50394 100644 --- a/docs/generated/packages/react/executors/module-federation-ssr-dev-server.json +++ b/docs/generated/packages/react/executors/module-federation-ssr-dev-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/react/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation SSR Dev Server", "description": "Serve a SSR Consumer (host) application along with its known Producers (remotes).", diff --git a/docs/generated/packages/react/executors/module-federation-static-server.json b/docs/generated/packages/react/executors/module-federation-static-server.json index 28c73a60de..9f1be0ea40 100644 --- a/docs/generated/packages/react/executors/module-federation-static-server.json +++ b/docs/generated/packages/react/executors/module-federation-static-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/react/src/executors/module-federation-static-server/module-federation-static-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation Static Dev Server", "description": "Serve a Consumer (host) application statically along with its Producers (remotes).", diff --git a/docs/generated/packages/remix/executors/serve.json b/docs/generated/packages/remix/executors/serve.json index c86d2b2e77..48abdb1a94 100644 --- a/docs/generated/packages/remix/executors/serve.json +++ b/docs/generated/packages/remix/executors/serve.json @@ -3,6 +3,7 @@ "implementation": "/packages/remix/src/executors/serve/serve.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "pipe", "cli": "nx", "title": "Remix Serve", diff --git a/docs/generated/packages/rspack/executors/dev-server.json b/docs/generated/packages/rspack/executors/dev-server.json index fd9399c7db..993c427b08 100644 --- a/docs/generated/packages/rspack/executors/dev-server.json +++ b/docs/generated/packages/rspack/executors/dev-server.json @@ -6,6 +6,7 @@ "version": 2, "title": "Rspack dev-server executor", "description": "Run @rspack/dev-server to serve a project.", + "continuous": true, "type": "object", "properties": { "buildTarget": { diff --git a/docs/generated/packages/rspack/executors/module-federation-dev-server.json b/docs/generated/packages/rspack/executors/module-federation-dev-server.json index 14ef282051..feb86376a9 100644 --- a/docs/generated/packages/rspack/executors/module-federation-dev-server.json +++ b/docs/generated/packages/rspack/executors/module-federation-dev-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/rspack/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Rspack Module Federation Dev Server", "description": "Serve a module federation application.", diff --git a/docs/generated/packages/rspack/executors/module-federation-ssr-dev-server.json b/docs/generated/packages/rspack/executors/module-federation-ssr-dev-server.json index 984c7a4674..aaa42cb87d 100644 --- a/docs/generated/packages/rspack/executors/module-federation-ssr-dev-server.json +++ b/docs/generated/packages/rspack/executors/module-federation-ssr-dev-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/rspack/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation SSR Dev Server", "description": "Serve a SSR Consumer (host) application along with its known Producers (remotes).", diff --git a/docs/generated/packages/rspack/executors/module-federation-static-server.json b/docs/generated/packages/rspack/executors/module-federation-static-server.json index fab2e13b5a..2c3d952d1d 100644 --- a/docs/generated/packages/rspack/executors/module-federation-static-server.json +++ b/docs/generated/packages/rspack/executors/module-federation-static-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/rspack/src/executors/module-federation-static-server/module-federation-static-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation Static Dev Server", "description": "Serve a Consumer (host) application statically along with it's Producers (remotes).", diff --git a/docs/generated/packages/rspack/executors/ssr-dev-server.json b/docs/generated/packages/rspack/executors/ssr-dev-server.json index cd0f60eca2..195f5550f2 100644 --- a/docs/generated/packages/rspack/executors/ssr-dev-server.json +++ b/docs/generated/packages/rspack/executors/ssr-dev-server.json @@ -2,6 +2,7 @@ "name": "ssr-dev-server", "implementation": "/packages/rspack/src/executors/ssr-dev-server/ssr-dev-server.impl.ts", "schema": { + "continuous": true, "outputCapture": "direct-nodejs", "title": "Rspack SSR Dev Server", "description": "Serve a SSR application using rspack.", diff --git a/docs/generated/packages/storybook/executors/storybook.json b/docs/generated/packages/storybook/executors/storybook.json index dc136a96ea..d68c208b2e 100644 --- a/docs/generated/packages/storybook/executors/storybook.json +++ b/docs/generated/packages/storybook/executors/storybook.json @@ -3,6 +3,7 @@ "implementation": "/packages/storybook/src/executors/storybook/storybook.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Storybook Dev Builder", "cli": "nx", diff --git a/docs/generated/packages/vite/executors/dev-server.json b/docs/generated/packages/vite/executors/dev-server.json index 7cba326d7d..b3495c3937 100644 --- a/docs/generated/packages/vite/executors/dev-server.json +++ b/docs/generated/packages/vite/executors/dev-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/vite/src/executors/dev-server/dev-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Vite Dev Server", "cli": "nx", diff --git a/docs/generated/packages/vite/executors/preview-server.json b/docs/generated/packages/vite/executors/preview-server.json index 155c06d5ac..a21702d8ac 100644 --- a/docs/generated/packages/vite/executors/preview-server.json +++ b/docs/generated/packages/vite/executors/preview-server.json @@ -7,6 +7,7 @@ "cli": "nx", "title": "Vite Preview Server", "description": "Preview Server for Vite.", + "continuous": true, "type": "object", "presets": [ { "name": "Default minimum setup", "keys": ["buildTarget"] }, diff --git a/docs/generated/packages/web/executors/file-server.json b/docs/generated/packages/web/executors/file-server.json index 861e46bdf8..c6023aa24a 100644 --- a/docs/generated/packages/web/executors/file-server.json +++ b/docs/generated/packages/web/executors/file-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/web/src/executors/file-server/file-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "File Server", "description": "Serve a web application from a folder. This executor is a wrapper around the [http-server](https://www.npmjs.com/package/http-server) package.", diff --git a/docs/generated/packages/webpack/executors/dev-server.json b/docs/generated/packages/webpack/executors/dev-server.json index 0af520cc77..880279f918 100644 --- a/docs/generated/packages/webpack/executors/dev-server.json +++ b/docs/generated/packages/webpack/executors/dev-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/webpack/src/executors/dev-server/dev-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Webpack dev server", "description": "Serve an application using webpack.", diff --git a/docs/generated/packages/webpack/executors/ssr-dev-server.json b/docs/generated/packages/webpack/executors/ssr-dev-server.json index df39c24c41..6d648feb7f 100644 --- a/docs/generated/packages/webpack/executors/ssr-dev-server.json +++ b/docs/generated/packages/webpack/executors/ssr-dev-server.json @@ -3,6 +3,7 @@ "implementation": "/packages/webpack/src/executors/ssr-dev-server/ssr-dev-server.impl.ts", "schema": { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Webpack SSR Dev Server", "description": "Serve a SSR application using webpack.", diff --git a/e2e/angular/src/config.test.ts b/e2e/angular/src/config.test.ts index 95e0d4c099..f7f0c3df96 100644 --- a/e2e/angular/src/config.test.ts +++ b/e2e/angular/src/config.test.ts @@ -135,16 +135,9 @@ const angularV1Json = (appName: string) => `{ "projectType": "application", "architect": { "e2e": { - "builder": "@nx/cypress:cypress", + "builder": "@nx/playwright:playwright", "options": { - "cypressConfig": "${appName}-e2e/cypress.json", - "devServerTarget": "${appName}:serve:development", - "testingType": "e2e" - }, - "configurations": { - "production": { - "devServerTarget": "${appName}:serve:production" - } + "config": "${appName}-e2e/playwright.config.js" } }, "lint": { diff --git a/packages/angular/src/builders/dev-server/schema.json b/packages/angular/src/builders/dev-server/schema.json index e4a2f1c4bf..5ad0b11878 100644 --- a/packages/angular/src/builders/dev-server/schema.json +++ b/packages/angular/src/builders/dev-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "$schema": "http://json-schema.org/draft-07/schema", "title": "Schema for Webpack Dev Server", diff --git a/packages/angular/src/executors/module-federation-dev-server/schema.json b/packages/angular/src/executors/module-federation-dev-server/schema.json index 287f2664ea..8ab1793525 100644 --- a/packages/angular/src/executors/module-federation-dev-server/schema.json +++ b/packages/angular/src/executors/module-federation-dev-server/schema.json @@ -1,6 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema", "title": "Schema for Module Federation Dev Server", + "continuous": true, "outputCapture": "direct-nodejs", "description": "Serves host [Module Federation](https://module-federation.io/) applications ([webpack](https://webpack.js.org/)-based) allowing to specify which remote applications should be served with the host.", "type": "object", diff --git a/packages/angular/src/executors/module-federation-ssr-dev-server/schema.json b/packages/angular/src/executors/module-federation-ssr-dev-server/schema.json index 5c5c209918..ac8ec682e9 100644 --- a/packages/angular/src/executors/module-federation-ssr-dev-server/schema.json +++ b/packages/angular/src/executors/module-federation-ssr-dev-server/schema.json @@ -1,6 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema", "title": "Module Federation SSR Dev Server Target", + "continuous": true, "outputCapture": "direct-nodejs", "description": "The module-federation-ssr-dev-server executor is reserved exclusively for use with host SSR Module Federation applications. It allows the user to specify which remote applications should be served with the host.", "type": "object", diff --git a/packages/cypress/src/utils/start-dev-server.ts b/packages/cypress/src/utils/start-dev-server.ts index cc90716cb4..be4147be15 100644 --- a/packages/cypress/src/utils/start-dev-server.ts +++ b/packages/cypress/src/utils/start-dev-server.ts @@ -12,7 +12,10 @@ import { import { join } from 'path'; import { CypressExecutorOptions } from '../executors/cypress/cypress.impl'; import * as detectPort from 'detect-port'; -import { getExecutorInformation } from 'nx/src/command-line/run/executor-utils'; +import { + getExecutorInformation, + parseExecutor, +} from 'nx/src/command-line/run/executor-utils'; import { existsSync, writeFileSync } from 'fs'; export async function* startDevServer( @@ -190,7 +193,7 @@ ${e.message || e}`); context.projectsConfigurations?.projects?.[target.project]; const targetConfig = projectConfig.targets[target.target]; - const [collection, executor] = targetConfig.executor.split(':'); + const [collection, executor] = parseExecutor(targetConfig.executor); const { schema } = getExecutorInformation( collection, executor, diff --git a/packages/devkit/src/executors/read-target-options.ts b/packages/devkit/src/executors/read-target-options.ts index 50490adf25..37e97e6869 100644 --- a/packages/devkit/src/executors/read-target-options.ts +++ b/packages/devkit/src/executors/read-target-options.ts @@ -6,6 +6,7 @@ import { calculateDefaultProjectName, combineOptionsForExecutor, getExecutorInformation, + parseExecutor, } from 'nx/src/devkit-internals'; /** @@ -29,7 +30,9 @@ export function readTargetOptions( throw new Error(`Unable to find target ${target} for project ${project}`); } - const [nodeModule, executorName] = targetConfiguration.executor.split(':'); + const [nodeModule, executorName] = parseExecutor( + targetConfiguration.executor + ); const { schema } = getExecutorInformation( nodeModule, executorName, diff --git a/packages/jest/src/plugins/plugin.ts b/packages/jest/src/plugins/plugin.ts index b1fb1638ea..4bb0539350 100644 --- a/packages/jest/src/plugins/plugin.ts +++ b/packages/jest/src/plugins/plugin.ts @@ -33,6 +33,7 @@ import { dirname, isAbsolute, join, relative, resolve } from 'path'; import { getInstalledJestMajorVersion } from '../utils/version-utils'; import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context'; import { normalize, sep } from 'node:path'; +import { getNxRequirePaths } from 'nx/src/utils/installation-directory'; const pmc = getPackageManagerCommand(); @@ -654,7 +655,7 @@ function resolveJestPath(projectRoot: string, workspaceRoot: string): string { } resolvedJestPaths[projectRoot] = require.resolve('jest', { - paths: [projectRoot, workspaceRoot, __dirname], + paths: [projectRoot, ...getNxRequirePaths(workspaceRoot), __dirname], }); return resolvedJestPaths[projectRoot]; diff --git a/packages/js/src/executors/verdaccio/schema.json b/packages/js/src/executors/verdaccio/schema.json index 796931c11d..3e99860c44 100644 --- a/packages/js/src/executors/verdaccio/schema.json +++ b/packages/js/src/executors/verdaccio/schema.json @@ -3,6 +3,7 @@ "version": 2, "title": "Verdaccio Local Registry", "description": "Start a local registry with Verdaccio.", + "continuous": true, "cli": "nx", "type": "object", "properties": { diff --git a/packages/next/src/executors/server/schema.json b/packages/next/src/executors/server/schema.json index 4b0a3a3e16..1cdca7dace 100644 --- a/packages/next/src/executors/server/schema.json +++ b/packages/next/src/executors/server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "pipe", "cli": "nx", "title": "Next Serve", diff --git a/packages/nx/src/command-line/run/executor-utils.ts b/packages/nx/src/command-line/run/executor-utils.ts index d473e73261..eb4c64d926 100644 --- a/packages/nx/src/command-line/run/executor-utils.ts +++ b/packages/nx/src/command-line/run/executor-utils.ts @@ -24,6 +24,7 @@ export function normalizeExecutorSchema( version, outputCapture: schema.outputCapture ?? version < 2 ? 'direct-nodejs' : 'pipe', + continuous: schema.continuous ?? false, properties: !schema.properties || typeof schema.properties !== 'object' ? {} @@ -36,12 +37,21 @@ function cacheKey(nodeModule: string, executor: string, root: string) { return `${root}:${nodeModule}:${executor}`; } +export function parseExecutor( + executorString: string +): [module: string, name: string] { + return executorString.split(':') as [string, string]; +} + const cachedExecutorInformation = {}; export function getExecutorInformation( nodeModule: string, executor: string, root: string, + /** + * A map of projects keyed by project name + */ projects: Record ): ExecutorConfig & { isNgCompat: boolean; isNxExecutor: boolean } { try { diff --git a/packages/nx/src/command-line/run/run.ts b/packages/nx/src/command-line/run/run.ts index b0800c2981..942e55d1e3 100644 --- a/packages/nx/src/command-line/run/run.ts +++ b/packages/nx/src/command-line/run/run.ts @@ -18,7 +18,7 @@ import { getLastValueFromAsyncIterableIterator, isAsyncIterator, } from '../../utils/async-iterator'; -import { getExecutorInformation } from './executor-utils'; +import { getExecutorInformation, parseExecutor } from './executor-utils'; import { createPseudoTerminal, PseudoTerminal, @@ -83,7 +83,7 @@ async function parseExecutorAndTarget( throw new Error(`Cannot find target '${target}' for project '${project}'`); } - const [nodeModule, executor] = targetConfig.executor.split(':'); + const [nodeModule, executor] = parseExecutor(targetConfig.executor); const { schema, implementationFactory } = getExecutorInformation( nodeModule, executor, diff --git a/packages/nx/src/config/misc-interfaces.ts b/packages/nx/src/config/misc-interfaces.ts index 82e5f1194e..42a4fecf0b 100644 --- a/packages/nx/src/config/misc-interfaces.ts +++ b/packages/nx/src/config/misc-interfaces.ts @@ -110,6 +110,7 @@ export interface ExecutorConfig { schema: { version?: number; outputCapture?: OutputCaptureMethod; + continuous?: boolean; } & Schema; hasherFactory?: () => CustomHasher; implementationFactory: () => Executor; diff --git a/packages/nx/src/devkit-internals.ts b/packages/nx/src/devkit-internals.ts index 406c34e6dc..e62f83d718 100644 --- a/packages/nx/src/devkit-internals.ts +++ b/packages/nx/src/devkit-internals.ts @@ -4,7 +4,10 @@ * These may not be available in certain version of Nx, so be sure to check them first. */ export { createTempNpmDirectory } from './utils/package-manager'; -export { getExecutorInformation } from './command-line/run/executor-utils'; +export { + getExecutorInformation, + parseExecutor, +} from './command-line/run/executor-utils'; export { readNxJson as readNxJsonFromDisk } from './config/nx-json'; export { calculateDefaultProjectName } from './config/calculate-default-project-name'; export { retrieveProjectConfigurationsWithAngularProjects } from './project-graph/utils/retrieve-workspace-files'; diff --git a/packages/nx/src/plugins/package-json/create-nodes.ts b/packages/nx/src/plugins/package-json/create-nodes.ts index d11e0f4d17..d3c1502ebf 100644 --- a/packages/nx/src/plugins/package-json/create-nodes.ts +++ b/packages/nx/src/plugins/package-json/create-nodes.ts @@ -214,7 +214,12 @@ export function buildProjectConfigurationFromPackageJson( root: projectRoot, name, ...packageJson.nx, - targets: readTargetsFromPackageJson(packageJson, nxJson), + targets: readTargetsFromPackageJson( + packageJson, + nxJson, + projectRoot, + workspaceRoot + ), tags: getTagsFromPackageJson(packageJson), metadata: getMetadataFromPackageJson( packageJson, diff --git a/packages/nx/src/project-graph/plugins/public-api.ts b/packages/nx/src/project-graph/plugins/public-api.ts index 50815d8afb..51c4f73305 100644 --- a/packages/nx/src/project-graph/plugins/public-api.ts +++ b/packages/nx/src/project-graph/plugins/public-api.ts @@ -99,7 +99,7 @@ export interface CreateDependenciesContext { readonly externalNodes: ProjectGraph['externalNodes']; /** - * The configuration of each project in the workspace. + * The configuration of each project in the workspace keyed by project name. */ readonly projects: Record; diff --git a/packages/nx/src/project-graph/utils/normalize-project-nodes.ts b/packages/nx/src/project-graph/utils/normalize-project-nodes.ts index 9ca4b67fe0..d2acdce62d 100644 --- a/packages/nx/src/project-graph/utils/normalize-project-nodes.ts +++ b/packages/nx/src/project-graph/utils/normalize-project-nodes.ts @@ -1,9 +1,6 @@ import { ProjectGraphProjectNode } from '../../config/project-graph'; import { ProjectGraphBuilder } from '../project-graph-builder'; -import { - ProjectConfiguration, - TargetConfiguration, -} from '../../config/workspace-json-project-json'; +import { ProjectConfiguration } from '../../config/workspace-json-project-json'; import { findMatchingProjects } from '../../utils/find-matching-projects'; import { CreateDependenciesContext } from '../plugins'; diff --git a/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts b/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts index f51d82501d..14f363db3e 100644 --- a/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts +++ b/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts @@ -18,6 +18,7 @@ import { NxPluginV2 } from '../plugins'; import { LoadedNxPlugin } from '../plugins/loaded-nx-plugin'; import { dirname } from 'path'; import { isProjectConfigurationsError } from '../error-types'; +import { workspaceRoot } from '../../utils/workspace-root'; describe('project-configuration-utils', () => { describe('target merging', () => { @@ -1658,7 +1659,7 @@ describe('project-configuration-utils', () => { foo: { command: 'echo {projectRoot}' }, }, }; - expect(normalizeTarget(config.targets.foo, config)) + expect(normalizeTarget(config.targets.foo, config, workspaceRoot, {})) .toMatchInlineSnapshot(` { "configurations": {}, @@ -1701,8 +1702,8 @@ describe('project-configuration-utils', () => { }; const originalConfig = JSON.stringify(config, null, 2); - normalizeTarget(config.targets.foo, config); - normalizeTarget(config.targets.bar, config); + normalizeTarget(config.targets.foo, config, workspaceRoot, {}); + normalizeTarget(config.targets.bar, config, workspaceRoot, {}); expect(JSON.stringify(config, null, 2)).toEqual(originalConfig); }); }); diff --git a/packages/nx/src/project-graph/utils/project-configuration-utils.ts b/packages/nx/src/project-graph/utils/project-configuration-utils.ts index ee7f731fdc..3b3a6a3554 100644 --- a/packages/nx/src/project-graph/utils/project-configuration-utils.ts +++ b/packages/nx/src/project-graph/utils/project-configuration-utils.ts @@ -33,6 +33,10 @@ import { import { CreateNodesResult } from '../plugins/public-api'; import { isGlobPattern } from '../../utils/globs'; import { DelayedSpinner } from '../../utils/delayed-spinner'; +import { + getExecutorInformation, + parseExecutor, +} from '../../command-line/run/executor-utils'; export type SourceInformation = [file: string | null, plugin: string]; export type ConfigurationSourceMaps = Record< @@ -447,7 +451,7 @@ export async function createProjectConfigurationsWithPlugins( spinner?.cleanup(); const { projectRootMap, externalNodes, rootMap, configurationSourceMaps } = - mergeCreateNodesResults(results, nxJson, errors); + mergeCreateNodesResults(results, nxJson, root, errors); performance.mark('build-project-configs:end'); performance.measure( @@ -484,6 +488,7 @@ function mergeCreateNodesResults( pluginIndex?: number ])[][], nxJsonConfiguration: NxJsonConfiguration, + workspaceRoot: string, errors: ( | AggregateCreateNodesError | MergeNodesError @@ -539,6 +544,7 @@ function mergeCreateNodesResults( try { validateAndNormalizeProjectRootMap( + workspaceRoot, projectRootMap, nxJsonConfiguration, configurationSourceMaps @@ -643,6 +649,7 @@ export function readProjectConfigurationsFromRootMap( } function validateAndNormalizeProjectRootMap( + workspaceRoot: string, projectRootMap: Record, nxJsonConfiguration: NxJsonConfiguration, sourceMaps: ConfigurationSourceMaps = {} @@ -678,7 +685,13 @@ function validateAndNormalizeProjectRootMap( } } - normalizeTargets(project, sourceMaps, nxJsonConfiguration); + normalizeTargets( + project, + sourceMaps, + nxJsonConfiguration, + workspaceRoot, + projects + ); } if (conflicts.size > 0) { @@ -693,12 +706,19 @@ function validateAndNormalizeProjectRootMap( function normalizeTargets( project: ProjectConfiguration, sourceMaps: ConfigurationSourceMaps, - nxJsonConfiguration: NxJsonConfiguration<'*' | string[]> + nxJsonConfiguration: NxJsonConfiguration, + workspaceRoot: string, + /** + * Project configurations keyed by project name + */ + projects: Record ) { for (const targetName in project.targets) { project.targets[targetName] = normalizeTarget( project.targets[targetName], - project + project, + workspaceRoot, + projects ); const projectSourceMaps = sourceMaps[project.root]; @@ -717,7 +737,7 @@ function normalizeTargets( project.targets[targetName] = mergeTargetDefaultWithTargetDefinition( targetName, project, - normalizeTarget(targetDefaults, project), + normalizeTarget(targetDefaults, project, workspaceRoot, projects), projectSourceMaps ); } @@ -1161,14 +1181,16 @@ function resolveCommandSyntacticSugar( } /** - * Expand's `command` syntactic sugar and replaces tokens in options. + * Expand's `command` syntactic sugar, replaces tokens in options, and adds information from executor schema. * @param target The target to normalize * @param project The project that the target belongs to * @returns The normalized target configuration */ export function normalizeTarget( target: TargetConfiguration, - project: ProjectConfiguration + project: ProjectConfiguration, + workspaceRoot: string, + projectsMap: Record ) { target = { ...target, @@ -1195,5 +1217,26 @@ export function normalizeTarget( target.parallelism ??= true; + if (target.executor && !('continuous' in target)) { + try { + const [executorNodeModule, executorName] = parseExecutor(target.executor); + + const { schema } = getExecutorInformation( + executorNodeModule, + executorName, + workspaceRoot, + projectsMap + ); + + if (schema.continuous) { + target.continuous ??= schema.continuous; + } + } catch (e) { + // If the executor is not found, we assume that it is not a valid executor. + // This means that we should not set the continuous property. + // We could throw an error here, but it would be better to just ignore it. + } + } + return target; } diff --git a/packages/nx/src/tasks-runner/batch/run-batch.ts b/packages/nx/src/tasks-runner/batch/run-batch.ts index a8dd250d82..6f39ef6fef 100644 --- a/packages/nx/src/tasks-runner/batch/run-batch.ts +++ b/packages/nx/src/tasks-runner/batch/run-batch.ts @@ -12,7 +12,10 @@ import { ExecutorContext } from '../../config/misc-interfaces'; import { readProjectsConfigurationFromProjectGraph } from '../../project-graph/project-graph'; import { readNxJson } from '../../config/configuration'; import { isAsyncIterator } from '../../utils/async-iterator'; -import { getExecutorInformation } from '../../command-line/run/executor-utils'; +import { + getExecutorInformation, + parseExecutor, +} from '../../command-line/run/executor-utils'; import { ProjectConfiguration } from '../../config/workspace-json-project-json'; import { ProjectGraph } from '../../config/project-graph'; @@ -20,7 +23,7 @@ function getBatchExecutor( executorName: string, projects: Record ) { - const [nodeModule, exportName] = executorName.split(':'); + const [nodeModule, exportName] = parseExecutor(executorName); return getExecutorInformation( nodeModule, exportName, diff --git a/packages/nx/src/tasks-runner/create-task-graph.ts b/packages/nx/src/tasks-runner/create-task-graph.ts index 84083c63d7..ca55ede5ae 100644 --- a/packages/nx/src/tasks-runner/create-task-graph.ts +++ b/packages/nx/src/tasks-runner/create-task-graph.ts @@ -521,7 +521,7 @@ export function getNonDummyDeps( } } -export function createTaskId( +function createTaskId( project: string, target: string, configuration: string | undefined diff --git a/packages/nx/src/tasks-runner/run-command.ts b/packages/nx/src/tasks-runner/run-command.ts index 97b0a18902..ba249eeba8 100644 --- a/packages/nx/src/tasks-runner/run-command.ts +++ b/packages/nx/src/tasks-runner/run-command.ts @@ -40,7 +40,7 @@ import { processSyncGeneratorResultErrors, } from '../utils/sync-generators'; import { workspaceRoot } from '../utils/workspace-root'; -import { createTaskGraph, createTaskId } from './create-task-graph'; +import { createTaskGraph } from './create-task-graph'; import { isTuiEnabled } from './is-tui-enabled'; import { CompositeLifeCycle, diff --git a/packages/nx/src/tasks-runner/utils.ts b/packages/nx/src/tasks-runner/utils.ts index 5acc7265db..93007d6a64 100644 --- a/packages/nx/src/tasks-runner/utils.ts +++ b/packages/nx/src/tasks-runner/utils.ts @@ -1,7 +1,10 @@ import { minimatch } from 'minimatch'; import { relative } from 'node:path'; import { join } from 'node:path/posix'; -import { getExecutorInformation } from '../command-line/run/executor-utils'; +import { + getExecutorInformation, + parseExecutor, +} from '../command-line/run/executor-utils'; import { CustomHasher, ExecutorConfig } from '../config/misc-interfaces'; import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph'; import { Task, TaskGraph } from '../config/task-graph'; @@ -429,7 +432,7 @@ export function getExecutorForTask( projectGraph: ProjectGraph ): ExecutorConfig & { isNgCompat: boolean; isNxExecutor: boolean } { const executor = getExecutorNameForTask(task, projectGraph); - const [nodeModule, executorName] = executor.split(':'); + const [nodeModule, executorName] = parseExecutor(executor); return getExecutorInformation( nodeModule, diff --git a/packages/nx/src/utils/package-json.spec.ts b/packages/nx/src/utils/package-json.spec.ts index 1e2967fe95..768cfb6e55 100644 --- a/packages/nx/src/utils/package-json.spec.ts +++ b/packages/nx/src/utils/package-json.spec.ts @@ -48,7 +48,12 @@ describe('readTargetsFromPackageJson', () => { }, }, }; - const result1 = readTargetsFromPackageJson(packageJson, nxJson1); + const result1 = readTargetsFromPackageJson( + packageJson, + nxJson1, + workspaceRoot, + '/root' + ); expect(result1['nx-release-publish']).toMatchInlineSnapshot(` { "dependsOn": [ @@ -69,7 +74,12 @@ describe('readTargetsFromPackageJson', () => { }, }, }; - const result2 = readTargetsFromPackageJson(packageJson, nxJson2); + const result2 = readTargetsFromPackageJson( + packageJson, + nxJson2, + workspaceRoot, + '/root' + ); expect(result2['nx-release-publish']).toMatchInlineSnapshot(` { "dependsOn": [ @@ -83,7 +93,12 @@ describe('readTargetsFromPackageJson', () => { }); it('should read targets from project.json and package.json', () => { - const result = readTargetsFromPackageJson(packageJson, {}); + const result = readTargetsFromPackageJson( + packageJson, + {}, + workspaceRoot, + '/root' + ); expect(result).toMatchInlineSnapshot(` { "build": { @@ -123,7 +138,9 @@ describe('readTargetsFromPackageJson', () => { }, }, }, - {} + {}, + workspaceRoot, + '/root' ); expect(result).toEqual({ build: { ...packageJsonBuildTarget, outputs: ['custom'] }, @@ -148,9 +165,10 @@ describe('readTargetsFromPackageJson', () => { includedScripts: ['test'], }, }, - {} + {}, + workspaceRoot, + '/root' ); - expect(result).toMatchInlineSnapshot(` { "nx-release-publish": { @@ -190,7 +208,9 @@ describe('readTargetsFromPackageJson', () => { }, }, }, - {} + {}, + workspaceRoot, + '/root' ); expect(result.build).toMatchInlineSnapshot(` { @@ -228,7 +248,9 @@ describe('readTargetsFromPackageJson', () => { }, }, }, - {} + {}, + workspaceRoot, + '/root' ); expect(result.build).toMatchInlineSnapshot(` { @@ -261,7 +283,9 @@ describe('readTargetsFromPackageJson', () => { }, }, }, - {} + {}, + workspaceRoot, + '/root' ); expect(result.build).toMatchInlineSnapshot(` { @@ -289,7 +313,9 @@ describe('readTargetsFromPackageJson', () => { }, }, }, - {} + {}, + workspaceRoot, + '/root' ); expect(result.build).toMatchInlineSnapshot(` { @@ -356,7 +382,9 @@ describe('readTargetsFromPackageJson', () => { includedScripts: [], }, }, - {} + {}, + workspaceRoot, + '/root' ); expect(result.test).toMatchInlineSnapshot(` { diff --git a/packages/nx/src/utils/package-json.ts b/packages/nx/src/utils/package-json.ts index 6dff53f52f..9a4a6280df 100644 --- a/packages/nx/src/utils/package-json.ts +++ b/packages/nx/src/utils/package-json.ts @@ -10,8 +10,8 @@ import { mergeTargetConfigurations } from '../project-graph/utils/project-config import { readJsonFile } from './fileutils'; import { getNxRequirePaths } from './installation-directory'; import { - PackageManagerCommands, getPackageManagerCommand, + PackageManagerCommands, } from './package-manager'; export interface NxProjectPackageJsonConfiguration @@ -186,7 +186,9 @@ export function getTagsFromPackageJson(packageJson: PackageJson): string[] { export function readTargetsFromPackageJson( packageJson: PackageJson, - nxJson: NxJsonConfiguration + nxJson: NxJsonConfiguration, + projectRoot: string, + workspaceRoot: string ) { const { scripts, nx, private: isPrivate } = packageJson ?? {}; const res: Record = {}; @@ -210,7 +212,11 @@ export function readTargetsFromPackageJson( * Any targetDefaults for the nx-release-publish target set by the user should * be merged with the implicit target. */ - if (!isPrivate && !res['nx-release-publish']) { + if ( + !isPrivate && + !res['nx-release-publish'] && + hasNxJsPlugin(projectRoot, workspaceRoot) + ) { const nxReleasePublishTargetDefaults = nxJson?.targetDefaults?.['nx-release-publish'] ?? {}; res['nx-release-publish'] = { @@ -230,6 +236,18 @@ export function readTargetsFromPackageJson( return res; } +function hasNxJsPlugin(projectRoot: string, workspaceRoot: string) { + try { + // nx-ignore-next-line + require.resolve('@nx/js', { + paths: [projectRoot, ...getNxRequirePaths(workspaceRoot), __dirname], + }); + return true; + } catch { + return false; + } +} + /** * Uses `require.resolve` to read the package.json for a module. * diff --git a/packages/react/src/executors/module-federation-dev-server/schema.json b/packages/react/src/executors/module-federation-dev-server/schema.json index e455106be4..b04b6ae7c0 100644 --- a/packages/react/src/executors/module-federation-dev-server/schema.json +++ b/packages/react/src/executors/module-federation-dev-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation Dev Server", "description": "Serve a web application.", diff --git a/packages/react/src/executors/module-federation-ssr-dev-server/schema.json b/packages/react/src/executors/module-federation-ssr-dev-server/schema.json index 8efca45fda..19b771d89d 100644 --- a/packages/react/src/executors/module-federation-ssr-dev-server/schema.json +++ b/packages/react/src/executors/module-federation-ssr-dev-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation SSR Dev Server", "description": "Serve a SSR Consumer (host) application along with its known Producers (remotes).", diff --git a/packages/react/src/executors/module-federation-static-server/schema.json b/packages/react/src/executors/module-federation-static-server/schema.json index 8113034e2e..2962665a4f 100644 --- a/packages/react/src/executors/module-federation-static-server/schema.json +++ b/packages/react/src/executors/module-federation-static-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation Static Dev Server", "description": "Serve a Consumer (host) application statically along with its Producers (remotes).", diff --git a/packages/remix/src/executors/serve/schema.json b/packages/remix/src/executors/serve/schema.json index 1e8eff1573..4cff94783c 100644 --- a/packages/remix/src/executors/serve/schema.json +++ b/packages/remix/src/executors/serve/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "pipe", "cli": "nx", "title": "Remix Serve", diff --git a/packages/rspack/src/executors/dev-server/schema.json b/packages/rspack/src/executors/dev-server/schema.json index f636780ae0..170d942038 100644 --- a/packages/rspack/src/executors/dev-server/schema.json +++ b/packages/rspack/src/executors/dev-server/schema.json @@ -3,6 +3,7 @@ "version": 2, "title": "Rspack dev-server executor", "description": "Run @rspack/dev-server to serve a project.", + "continuous": true, "type": "object", "properties": { "buildTarget": { diff --git a/packages/rspack/src/executors/module-federation-dev-server/schema.json b/packages/rspack/src/executors/module-federation-dev-server/schema.json index 93f9e7e60d..8343de11ef 100644 --- a/packages/rspack/src/executors/module-federation-dev-server/schema.json +++ b/packages/rspack/src/executors/module-federation-dev-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Rspack Module Federation Dev Server", "description": "Serve a module federation application.", diff --git a/packages/rspack/src/executors/module-federation-ssr-dev-server/schema.json b/packages/rspack/src/executors/module-federation-ssr-dev-server/schema.json index 303fc881fe..8233fba44e 100644 --- a/packages/rspack/src/executors/module-federation-ssr-dev-server/schema.json +++ b/packages/rspack/src/executors/module-federation-ssr-dev-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation SSR Dev Server", "description": "Serve a SSR Consumer (host) application along with its known Producers (remotes).", diff --git a/packages/rspack/src/executors/module-federation-static-server/schema.json b/packages/rspack/src/executors/module-federation-static-server/schema.json index 0b04141043..783a56c0ac 100644 --- a/packages/rspack/src/executors/module-federation-static-server/schema.json +++ b/packages/rspack/src/executors/module-federation-static-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Module Federation Static Dev Server", "description": "Serve a Consumer (host) application statically along with it's Producers (remotes).", diff --git a/packages/rspack/src/executors/ssr-dev-server/schema.json b/packages/rspack/src/executors/ssr-dev-server/schema.json index fc22ad14d2..c1a91466bd 100644 --- a/packages/rspack/src/executors/ssr-dev-server/schema.json +++ b/packages/rspack/src/executors/ssr-dev-server/schema.json @@ -1,4 +1,5 @@ { + "continuous": true, "outputCapture": "direct-nodejs", "title": "Rspack SSR Dev Server", "description": "Serve a SSR application using rspack.", diff --git a/packages/storybook/src/executors/storybook/schema.json b/packages/storybook/src/executors/storybook/schema.json index a8fe380485..8075dab012 100644 --- a/packages/storybook/src/executors/storybook/schema.json +++ b/packages/storybook/src/executors/storybook/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Storybook Dev Builder", "cli": "nx", diff --git a/packages/vite/src/executors/dev-server/schema.json b/packages/vite/src/executors/dev-server/schema.json index cb8294ad60..25e3c8e7a1 100644 --- a/packages/vite/src/executors/dev-server/schema.json +++ b/packages/vite/src/executors/dev-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Vite Dev Server", "cli": "nx", diff --git a/packages/vite/src/executors/preview-server/schema.json b/packages/vite/src/executors/preview-server/schema.json index c519fd277a..0e3fcafee8 100644 --- a/packages/vite/src/executors/preview-server/schema.json +++ b/packages/vite/src/executors/preview-server/schema.json @@ -4,6 +4,7 @@ "cli": "nx", "title": "Vite Preview Server", "description": "Preview Server for Vite.", + "continuous": true, "type": "object", "presets": [ { diff --git a/packages/web/src/executors/file-server/schema.json b/packages/web/src/executors/file-server/schema.json index 175c9b68e0..cfd46b9695 100644 --- a/packages/web/src/executors/file-server/schema.json +++ b/packages/web/src/executors/file-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "File Server", "description": "Serve a web application from a folder. This executor is a wrapper around the [http-server](https://www.npmjs.com/package/http-server) package.", diff --git a/packages/webpack/src/executors/dev-server/schema.json b/packages/webpack/src/executors/dev-server/schema.json index 92db09b2dc..626132d691 100644 --- a/packages/webpack/src/executors/dev-server/schema.json +++ b/packages/webpack/src/executors/dev-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Webpack dev server", "description": "Serve an application using webpack.", diff --git a/packages/webpack/src/executors/ssr-dev-server/schema.json b/packages/webpack/src/executors/ssr-dev-server/schema.json index 34b3b05085..b72095b7b3 100644 --- a/packages/webpack/src/executors/ssr-dev-server/schema.json +++ b/packages/webpack/src/executors/ssr-dev-server/schema.json @@ -1,5 +1,6 @@ { "version": 2, + "continuous": true, "outputCapture": "direct-nodejs", "title": "Webpack SSR Dev Server", "description": "Serve a SSR application using webpack.",