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
103 lines
3.4 KiB
Markdown
103 lines
3.4 KiB
Markdown
---
|
|
title: Compose Executors
|
|
description: 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:
|
|
|
|
```typescript
|
|
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:
|
|
|
|
```json {% fileName="project.json" %}
|
|
{
|
|
"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:
|
|
|
|
```typescript
|
|
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](/reference/core-api/devkit/documents/nx_devkit#functions)
|
|
|
|
## 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`.
|
|
|
|
```typescript
|
|
import { of } from 'rxjs';
|
|
|
|
export default async function (opts) {
|
|
return of({ success: true }).toPromise();
|
|
}
|
|
```
|
|
|
|
You can use the [`rxjs-for-await`](https://www.npmjs.com/package/rxjs-for-await) library to convert an `Observable` into an async iterable.
|
|
|
|
```typescript
|
|
import { of } from 'rxjs';
|
|
import { eachValueFrom } from 'rxjs-for-await';
|
|
|
|
export default async function (opts) {
|
|
return eachValueFrom(of({ success: true }));
|
|
}
|
|
```
|