This PR removes the `/nx-api` pages from `nx-dev`. They are already redirected from `/nx-api` to either `/technologies` or `/reference/core-api` URLs. e.g. `/nx-api/nx` goes to `/reference/core-api/nx` and `/nx-api/react` goes to `/technologies/react/api` **Changes**: - Remove old `nx-api.json` from being generated in `scripts/documentation/generators/generate-manifests.ts` -- this was used to generate the sitemap - Remove `pages/nx-api` from Next.js app since we don't need them - Remove workaround from link checker `scripts/documentation/internal-link-checker.ts` -- the angular rspack/rsbuild and other workarounds are gone now that they are proper docs in `map.json` - Update Powerpack/Remote Cache reference docs to exclude API documents (since they are duplicated in the Intro page) -- `nx-dev/models-document/src/lib/mappings.ts` - All content in `docs` have been updated with new URL structure **Note:** Redirects are already handled, and Claude Code was used to verify the updated `docs/` URLs (see report below). The twelve 404s links were updated by hand. ## Verification Report https://gist.github.com/jaysoo/c7863fe7e091cb77929d1976165c357a
3.4 KiB
| title | description |
|---|---|
| Compose Executors | Learn how to compose and chain Nx executors together, including how to invoke other targets and executors from within your custom executors. |
Compose executors
An executor is just a function, so you can import and invoke it directly, as follows:
import printAllCaps from 'print-all-caps';
export default async function (
options: Schema,
context: ExecutorContext
): Promise<{ success: true }> {
// do something before
await printAllCaps({ message: 'All caps' });
// do something after
}
This only works when you know what executor you want to invoke. Sometimes, however, you need to invoke a target. For instance, the e2e target is often configured like this:
{
"e2e": {
"builder": "@nx/cypress:cypress",
"options": {
"cypressConfig": "apps/myapp-e2e/cypress.json",
"tsConfig": "apps/myapp-e2e/tsconfig.e2e.json",
"devServerTarget": "myapp:serve"
}
}
}
In this case we need to invoke the target configured in devSeverTarget. We can do it as follows:
async function* startDevServer(
opts: CypressExecutorOptions,
context: ExecutorContext
) {
const { project, target, configuration } = parseTargetString(
opts.devServerTarget
);
for await (const output of await runExecutor<{
success: boolean;
baseUrl?: string;
}>(
{ project, target, configuration },
{
watch: opts.watch,
},
context
)) {
if (!output.success && !opts.watch)
throw new Error('Could not compile application files');
yield opts.baseUrl || (output.baseUrl as string);
}
}
The runExecutor utility will find the target in the configuration, find the executor, construct the options (as if you invoked it in the terminal) and invoke the executor. Note that runExecutor always returns an iterable instead of a promise.
Devkit helper functions
| Property | Description |
|---|---|
| logger | Wraps console to add some formatting |
| getPackageManagerCommand | Returns commands for the package manager used in the workspace |
| parseTargetString | Parses a target string into {project, target, configuration} |
| readTargetOptions | Reads and combines options for a given target |
| runExecutor | Constructs options and invokes an executor |
See more helper functions in the Devkit API Docs
Using RxJS observables
The Nx devkit only uses language primitives (promises and async iterables). It doesn't use RxJS observables, but you can use them and convert them to a Promise or an async iterable.
You can convert Observables to a Promise with toPromise.
import { of } from 'rxjs';
export default async function (opts) {
return of({ success: true }).toPromise();
}
You can use the rxjs-for-await library to convert an Observable into an async iterable.
import { of } from 'rxjs';
import { eachValueFrom } from 'rxjs-for-await';
export default async function (opts) {
return eachValueFrom(of({ success: true }));
}