Skip to content

Commit c99056f

Browse files
docs: add swc, devtools docs
1 parent ece3495 commit c99056f

40 files changed

+564
-48
lines changed

content/controllers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ This method will return a 200 status code and the associated response, which in
6767

6868
> warning **Warning** Nest detects when the handler is using either `@Res()` or `@Next()`, indicating you have chosen the library-specific option. If both approaches are used at the same time, the Standard approach is **automatically disabled** for this single route and will no longer work as expected. To use both approaches at the same time (for example, by injecting the response object to only set cookies/headers but still leave the rest to the framework), you must set the `passthrough` option to `true` in the `@Res({{ '{' }} passthrough: true {{ '}' }})` decorator.
6969
70-
<app-banner-enterprise></app-banner-enterprise>
70+
<app-banner-devtools></app-banner-devtools>
7171

7272
#### Request object
7373

content/devtools/ci-cd.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
### CI/CD integration
2+
3+
> info **Hint** This chapter covers the Nest Devtools integration with the Nest framework. If you are looking for the Devtools application, please visit the [Devtools](https://devtools.nestjs.com) website.
4+
5+
CI/CD integration is available for users with the **[Enterprise](/settings)** plan.
6+
7+
#### Publishing graphs
8+
9+
Let's first configure the application bootstrap file (`main.ts`) to use the `GraphPublisher` class (exported from the `@nestjs/devtools-integration` - see previous chapter for more details), as follows:
10+
11+
```typescript
12+
async function bootstrap() {
13+
const shouldPublishGraph = process.env.PUBLISH_GRAPH === "true";
14+
15+
const app = await NestFactory.create(AppModule, {
16+
snapshot: true,
17+
preview: shouldPublishGraph,
18+
});
19+
20+
if (shouldPublishGraph) {
21+
await app.init();
22+
23+
const publishOptions = { ... } // NOTE: this options object will vary depending on the CI/CD provider you're using
24+
const graphPublisher = new GraphPublisher(app);
25+
await graphPublisher.publish(publishOptions);
26+
27+
await app.close();
28+
} else {
29+
await app.listen(3000);
30+
}
31+
}
32+
```
33+
34+
As we can see, we're using the `GraphPublisher` here to publish our serialized graph to the centralized registry. The `PUBLISH_GRAPH` is a custom environment variable that will let us control whether the graph should be published (CI/CD workflow), or not (regular application bootstrap). Also, we set the `preview` attribute here to `true`. With this flag enabled, our application will bootstrap in the preview mode - which basically means that constructors (and lifecycle hooks) of all controllers, enhancers, and providers in our application will not be executed. Note - this isn't **required**, but makes things simpler for us since in this case we won't really have to connect to the database etc. when running our application in the CI/CD pipeline.
35+
36+
The `publishOptions` object will vary depending on the CI/CD provider you're using. We will provide you with instructions for the most popular CI/CD providers below, in later sections.
37+
38+
Once the graph is successfully published, you'll see the following output in your workflow view:
39+
40+
<figure><img src="/assets/devtools/graph-published-terminal.png" /></figure>
41+
42+
Every time our graph is published, we should see a new entry in the project's corresponding page:
43+
44+
<figure><img src="/assets/devtools/project.png" /></figure>
45+
46+
#### Reports
47+
48+
Devtools generate a report for every build **IF** there's a corresponding snapshot already stored in the centralized registry. So for example, if you create a PR against the `master` branch for which the graph was already published - then the application will be able to detect differences and generate a report. Otherwise, the report will not be generated.
49+
50+
To see reports, navigate to the project's corresponding page (see organizations).
51+
52+
<figure><img src="/assets/devtools/report.png" /></figure>
53+
54+
#### Build preview
55+
56+
For every published graph we can go back in time and preview how it looked before by clicking at the **Preview** button. Furthermore, if the report was generated, we should see the differences higlighted on our graph:
57+
58+
- green nodes represent added elements
59+
- light white nodes represent updated elements
60+
- red nodes represent deleted elements
61+
62+
See screenshot below:
63+
64+
<figure><img src="/assets/devtools/nodes-selection.png" /></figure>
65+
66+
#### Integrations: Github Actions
67+
68+
First let's start from creating a new Github workflow in the `.github/workflows` directory in our project and call it, for example, `publish-graph.yml`. Inside this file, let's use the following definition:
69+
70+
```yaml
71+
name: Devtools
72+
73+
on:
74+
push:
75+
branches:
76+
- master
77+
pull_request:
78+
branches:
79+
- '*'
80+
81+
jobs:
82+
publish:
83+
if: github.actor!= 'dependabot[bot]'
84+
name: Publish graph
85+
runs-on: ubuntu-latest
86+
steps:
87+
- uses: actions/checkout@v3
88+
- uses: actions/setup-node@v3
89+
with:
90+
node-version: '16'
91+
cache: 'npm'
92+
- name: Install dependencies
93+
run: npm ci
94+
- name: Setup Environment (PR)
95+
if: {{ '${{' }} github.event_name == 'pull_request' {{ '}}' }}
96+
shell: bash
97+
run: |
98+
echo "COMMIT_SHA={{ '${{' }} github.event.pull_request.head.sha {{ '}}' }}" >>\${GITHUB_ENV}
99+
- name: Setup Environment (Push)
100+
if: {{ '${{' }} github.event_name == 'push' {{ '}}' }}
101+
shell: bash
102+
run: |
103+
echo "COMMIT_SHA=\${GITHUB_SHA}" >> \${GITHUB_ENV}
104+
- name: Publish
105+
run: PUBLISH_GRAPH=true npm run start
106+
env:
107+
DEVTOOLS_API_KEY: CHANGE_THIS_TO_YOUR_API_KEY
108+
REPOSITORY_NAME: {{ '${{' }} github.event.repository.name {{ '}}' }}
109+
BRANCH_NAME: {{ '${{' }} github.head_ref || github.ref_name {{ '}}' }}
110+
TARGET_SHA: {{ '${{' }} github.event.pull_request.base.sha {{ '}}' }}
111+
```
112+
113+
Ideally, `DEVTOOLS_API_KEY` environment variable should be retrieved from Github Secrets, read more [here](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) .
114+
115+
This workflow will run per each pull request that's targeting the `master` branch OR in case there's a direct commit to the `master` branch. Feel free to align this configuration to whatever your project needs. What's essential here is that we provide necessary environment varaiables for our `GraphPublisher` class (to run).
116+
117+
However, there's one variable that needs to be updated before we can start using this workflow - `DEVTOOLS_API_KEY`. We can generate an API key dedicated for our project on this **page** .
118+
119+
Lastly, let's navigate to the `main.ts` file again and update the `publishOptions` object we previously left empty.
120+
121+
```typescript
122+
const publishOptions = {
123+
apiKey: process.env.DEVTOOLS_API_KEY,
124+
repository: process.env.REPOSITORY_NAME,
125+
owner: process.env.GITHUB_REPOSITORY_OWNER,
126+
sha: process.env.COMMIT_SHA,
127+
target: process.env.TARGET_SHA,
128+
trigger: process.env.GITHUB_BASE_REF ? 'pull' : 'push',
129+
branch: process.env.BRANCH_NAME,
130+
};
131+
```
132+
133+
For the best developer experience, make sure to integrate the **Github application** for your project by clicking on the "Integrate Github app" button (see screenshot below). Note - this isn't required.
134+
135+
<figure><img src="/assets/devtools/integrate-github-app.png" /></figure>
136+
137+
With this integration, you'll be able to see the status of the preview/report generation process right in your pull request:
138+
139+
<figure><img src="/assets/devtools/actions-preview.png" /></figure>
140+
141+
#### Integrations: Gitlab Pipelines
142+
143+
First let's start from creating a new Gitlab CI configuration file in the root directory of our project and call it, for example, `.gitlab-ci.yml`. Inside this file, let's use the following definition:
144+
145+
```typescript
146+
const publishOptions = {
147+
apiKey: process.env.DEVTOOLS_API_KEY,
148+
repository: process.env.REPOSITORY_NAME,
149+
owner: process.env.GITHUB_REPOSITORY_OWNER,
150+
sha: process.env.COMMIT_SHA,
151+
target: process.env.TARGET_SHA,
152+
trigger: process.env.GITHUB_BASE_REF ? 'pull' : 'push',
153+
branch: process.env.BRANCH_NAME,
154+
};
155+
```
156+
157+
> info **Hint** Ideally, `DEVTOOLS_API_KEY` environment variable should be retrieved from secrets.
158+
159+
This workflow will run per each pull request that's targeting the `master` branch OR in case there's a direct commit to the `master` branch. Feel free to align this configuration to whatever your project needs. What's essential here is that we provide necessary environment variables for our `GraphPublisher` class (to run).
160+
161+
However, there's one variable (in this workflow definition) that needs to be updated before we can start using this workflow - `DEVTOOLS_API_KEY`. We can generate an API key dedicated for our project on this **page** .
162+
163+
Lastly, let's navigate to the `main.ts` file again and update the `publishOptions` object we previously left empty.
164+
165+
```yaml
166+
image: node:16
167+
168+
stages:
169+
- build
170+
171+
cache:
172+
key:
173+
files:
174+
- package-lock.json
175+
paths:
176+
- node_modules/
177+
178+
workflow:
179+
rules:
180+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
181+
when: always
182+
- if: $CI_COMMIT_BRANCH == "master" && $CI_PIPELINE_SOURCE == "push"
183+
when: always
184+
- when: never
185+
186+
install_dependencies:
187+
stage: build
188+
script:
189+
- npm ci
190+
191+
publish_graph:
192+
stage: build
193+
needs:
194+
- install_dependencies
195+
script: npm run start
196+
variables:
197+
PUBLISH_GRAPH: 'true'
198+
DEVTOOLS_API_KEY: 'CHANGE_THIS_TO_YOUR_API_KEY'
199+
```
200+
201+
#### Other CI/CD tools
202+
203+
Nest Devtools CI/CD integration can be used with any CI/CD tool of your choice (e.g., [Bitbucket Pipelines](https://bitbucket.org/product/features/pipelines) , [CircleCI](https://circleci.com/), etc) so don't feel limited to providers we described here.
204+
205+
Look at the following `publishOptions` object configuration to understand what information is required to publish the graph for a given commit/build/PR.
206+
207+
```typescript
208+
const publishOptions = {
209+
apiKey: process.env.DEVTOOLS_API_KEY,
210+
repository: process.env.CI_PROJECT_NAME,
211+
owner: process.env.CI_PROJECT_ROOT_NAMESPACE,
212+
sha: process.env.CI_COMMIT_SHA,
213+
target: process.env.CI_MERGE_REQUEST_DIFF_BASE_SHA,
214+
trigger: process.env.CI_MERGE_REQUEST_DIFF_BASE_SHA ? 'pull' : 'push',
215+
branch:
216+
process.env.CI_COMMIT_BRANCH ??
217+
process.env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME,
218+
};
219+
```
220+
221+
Most of this information is provided through CI/CD built-in environment variables (see [CircleCI built-in environment list](https://circleci.com/docs/variables/#built-in-environment-variables) and [Bitbucket variables](https://support.atlassian.com/bitbucket-cloud/docs/variables-and-secrets/) ).
222+
223+
When it comes to the pipeline configuration for publishing graphs, we recommend using the following triggers:
224+
225+
- `push` event - only if the current branch represents a deployment environment, for example `master`, `main`, `staging`, `production`, etc.
226+
- `pull request` event - always, or when the **target branch** represents a deployment environment (see above)

content/devtools/overview.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
### Overview
2+
3+
> info **Hint** This chapter covers the Nest Devtools integration with the Nest framework. If you are looking for the Devtools application, please visit the [Devtools](https://devtools.nestjs.com) website.
4+
5+
To start debugging your local application, open up the `main.ts` file and make sure to set the `snapshot` attribute to `true` in the application options object, as follows:
6+
7+
```typescript
8+
async function bootstrap() {
9+
const app = await NestFactory.create(AppModule, {
10+
snapshot: true,
11+
});
12+
await app.listen(3000);
13+
}
14+
```
15+
16+
This will instruct the framework to collect necessary metadata that will let Nest Devtools visualize your application's graph.
17+
18+
Next up, let's install the required dependency:
19+
20+
```bash
21+
$ npm i @nestjs/devtools-integration
22+
```
23+
24+
> warning **Warning** If you're using `@nestjs/graphql` package in your application, make sure to install the upcoming `next` version (`npm i @nestjs/graphql@next`).
25+
26+
With this dependency in place, let's open up the `app.module.ts` file and import the `DevtoolsModule` that we just installed:
27+
28+
```typescript
29+
@Module({
30+
imports: [
31+
DevtoolsModule.register({
32+
http: process.env.NODE_ENV !== 'production',
33+
}),
34+
],
35+
controllers: [AppController],
36+
providers: [AppService],
37+
})
38+
export class AppModule {}
39+
```
40+
41+
> warning **Warning** The reason we are checking the `NODE_ENV` environment variable here is that you should never use this module in production!
42+
43+
Once the `DevtoolsModule` is imported and your application is up and running (`npm run start:dev`), you should be able to navigate to [Devtools](https://devtools.nestjs.com) URL and see the instrospected graph.
44+
45+
<figure><img src="/assets/devtools/modules-graph.png" /></figure>
46+
47+
So as we can see, `DevtoolsModule` makes your application expose an additional HTTP server (on port 8000) that the Devtools application will use to introspect your app.
48+
49+
Just to double-check that everything works as expected, change the graph view to "Classes". You should see the following screen:
50+
51+
<figure><img src="/assets/devtools/classes-graph.png" /></figure>
52+
53+
To focus on a specific node, click on the rectangle and the graph will show a popup window with the **"Focus"** button. You can also use the search bar (located in the sidebar) to find a specific node.
54+
55+
> info **Hint** If you click on the **Inspect** button, application will take you to the `/debug` page with that specific node selected.
56+
57+
<figure><img src="/assets/devtools/node-popup.png" /></figure>
58+
59+
Using the form controls located in the sidebar (on the left), you can control edges proximity to, for example, visualize a specific application sub-tree:
60+
61+
<figure><img src="/assets/devtools/subtree-view.png" /></figure>
62+
63+
#### Routes explorer
64+
65+
When you navigate to the **Routes explorer** page, you should see all of the registered entrypoints:
66+
67+
<figure><img src="/assets/devtools/routes.png" /></figure>
68+
69+
#### Sandbox
70+
71+
To execute JavaScript code on the fly & interact with your application in real-time, navigate to the **Sandbox** page:
72+
73+
<figure><img src="/assets/devtools/sandbox.png" /></figure>
74+
75+
#### Bootstrap performance analyzer
76+
77+
To see a list of all class nodes (controllers, providers, enhancers, etc.) and their corresponding instantiation times, navigate to the **Bootstrap performance** page:
78+
79+
<figure><img src="/assets/devtools/bootstrap-performance.png" /></figure>
80+
81+
#### Audit
82+
83+
To see the auto-generated audit - errors/warnings/hints that the application came up with while analyzing your serialized graph, navigate to the **
84+
Audit** page:
85+
86+
<figure><img src="/assets/devtools/audit.png" /></figure>
87+
88+
#### Preview static files
89+
90+
To save a serialized graph to a file, use the following code:
91+
92+
```typescript
93+
await app.listen(3000); // OR await app.init()
94+
writeFileSync('./graph.json', app.get(SerializedGraph).toString());
95+
```
96+
97+
> info **Hint** `SerializedGraph` is exported from the `@nestjs/core` package.
98+
99+
Then you can drag and drop this/upload this file:
100+
101+
<figure><img src="/assets/devtools/drag-and-drop.png" /></figure>

content/interceptors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ This approach means that the `intercept()` method effectively **wraps** the requ
2828

2929
Consider, for example, an incoming `POST /cats` request. This request is destined for the `create()` handler defined inside the `CatsController`. If an interceptor which does not call the `handle()` method is called anywhere along the way, the `create()` method won't be executed. Once `handle()` is called (and its `Observable` has been returned), the `create()` handler will be triggered. And once the response stream is received via the `Observable`, additional operations can be performed on the stream, and a final result returned to the caller.
3030

31-
<app-banner-shop></app-banner-shop>
31+
<app-banner-devtools></app-banner-devtools>
3232

3333
#### Aspect interception
3434

content/modules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ export class CatsModule {}
9999

100100
Now any module that imports the `CatsModule` has access to the `CatsService` and will share the same instance with all other modules that import it as well.
101101

102-
<app-banner-enterprise></app-banner-enterprise>
102+
<app-banner-devtools></app-banner-devtools>
103103

104104
#### Module re-exporting
105105

0 commit comments

Comments
 (0)