Skip to content

Commit

Permalink
New compile lifecycle events
Browse files Browse the repository at this point in the history
  • Loading branch information
danjoa committed Dec 16, 2024
1 parent d9a6c6c commit fd2cf36
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 46 deletions.
38 changes: 38 additions & 0 deletions node.js/cds-compile.md
Original file line number Diff line number Diff line change
Expand Up @@ -421,3 +421,41 @@ Examples:
> cds.resolve('none') // > undefined
```
> Try this in cds repl launched from your project root to see that in action.


## Lifecycle Events

The following [lifecycle events](cds-facade#lifecycle-events) are emitted via the `cds` facade object during the server bootstrapping process.
You can register event handlers using `cds.on()` like so:


```js
const cds = require('@sap/cds')
cds.on('compile.for.runtime', ...)
cds.on('compile.to.dbx', ...)
cds.on('compile.to.edmx', ...)
```

> [!warning]
> As we're using Node's standard [EventEmitter](https://nodejs.org/api/events.html#asynchronous-vs-synchronous),
> event handlers execute **synchronously** in the order they are registered.

> [!tip] Note that several of these events coud be emitted for the same model, so ensure your handlers are idempodent.


### compile.for.runtime {.event}

A one-time event, emitted before the model is compiled for usage in Node.js or Java runtime.
This is the right place to, for example, add custom elements required at runtime.


### compile.to.dbx {.event}

A one-time event, emitted before database-specific artifacts, i.e. SQL DDL scripts, are generated from the model.
This is the right place to, for example, add custom elements required in your persistence.


### compile.to.edmx {.event}

A one-time event, emitted immediately before the model is compiled to edmx.
This is the right place to add custom transformations to the model, for example, to add custom Fiori annotations.
27 changes: 16 additions & 11 deletions node.js/cds-facade.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,21 +392,26 @@ cds.exit() //> will rune above handlers before stopping the server




## Lifecycle Events

[Learn more about Lifecycle Events in `cds.server`](cds-server#lifecycle-events){.learn-more}

#### cds. once '*bootstrap*' {.event}

#### cds. on '*loaded*' {.event}
The `cds` facade object is an [EventEmitter](https://nodejs.org/api/events.html#asynchronous-vs-synchronous),
which frameworks emits events to, during the server bootstrapping process, or when we compile models.
You can register event handlers using `cds.on()` like so:

#### cds. on '*connect*' {.event}

#### cds. on '*serving*' {.event}
```js twoslash
// @noErrors
const cds = require('@sap/cds')
cds.on('bootstrap', ...)
cds.on('served', ...)
cds.on('listening', ...)
```

#### cds. once '*served*' {.event}
- [Learn more about Lifecycle Events emitted by `cds.compile`](cds-compile#lifecycle-events) {.learn-more}
- [Learn more about Lifecycle Events emitted by `cds.server`](cds-server#lifecycle-events) {.learn-more}

#### cds. once '*listening*' {.event}

#### cds. once '*shutdown*' {.event}
> [!warning]
> As we're using Node's standard [EventEmitter](https://nodejs.org/api/events.html#asynchronous-vs-synchronous),
> event handlers execute **synchronously** in the order they are registered, with `served` and `shutdown`
> events as the only exeptions.
53 changes: 18 additions & 35 deletions node.js/cds-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,24 @@ The `req` object in your express middleware is not the same as `req` in your CDS

## Lifecycle Events

The following [lifecycle events](cds-facade#lifecycle-events) are emitted via the `cds` facade object during the server bootstrapping process.
You can register event handlers using `cds.on()` like so:


```js
const cds = require('@sap/cds')
cds.on('bootstrap', ...)
cds.on('served', ...)
cds.on('listening', ...)
```


> [!warning]
> As we're using Node's standard [EventEmitter](https://nodejs.org/api/events.html#asynchronous-vs-synchronous),
> event handlers execute **synchronously** in the order they are registered, with `served` and `shutdown`
> events as the only exeptions.

### bootstrap {.event}

A one-time event, emitted immediately after the [express.js app](cds-facade#cds-app)
Expand All @@ -150,7 +168,6 @@ const cds = require('@sap/cds')
const express = require('express')
cds.on('bootstrap', app => {
// add your own middleware before any by cds are added

// for example, serve static resources incl. index.html
app.use(express.static(__dirname+'/srv/public'))
})
Expand Down Expand Up @@ -205,40 +222,6 @@ A one-time event, emitted when the server is closed and/or the process finishes.
This event supports _asynchronous_ event handlers.


### Event Handlers

#### Synchronous vs. asynchronous

Unless otherwise noted, event handlers execute **synchronously** in the order they are registered.
This is due to `cds.on()` and `cds.emit()` using Node's [EventEmitter](https://nodejs.org/api/events.html#asynchronous-vs-synchronous) contract.

In other words this asynchronous handler code does **not work** as expected:

```js twoslash
// @noErrors
const cds = require('@sap/cds')
const asyncCode = async () => Promise.resolve()
// ---cut---
cds.on ('bootstrap', async ()=> {
await asyncCode() // [!code error] // will NOT be awaited
})
```

You can use the [served](#served) event's asynchronous nature though to wait for such bootstrap code:

```js twoslash
const cds = require('@sap/cds')
// ---cut---
let done
cds.on('bootstrap', ()=> {
done = asyncCode()
})
cds.on('served', async ()=> {
await moreCode()
await done
})
```



## Configuration
Expand Down

0 comments on commit fd2cf36

Please sign in to comment.