Skip to content

Commit b65a224

Browse files
committed
📘 doc: add life-cycle
1 parent 90181bc commit b65a224

File tree

18 files changed

+855
-78
lines changed

18 files changed

+855
-78
lines changed

components/midori/ray.vue

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
<!-- https://codepen.io/TWilson/pen/jOdWqbZ -->
22
<template>
3-
<div
4-
class="absolute flex flex-col w-full items-center justify-center bg-transparent transition-bg"
5-
:class="className"
6-
>
7-
<div
8-
class="jumbo absolute -inset-[10px] opacity-50"
9-
:class="{ '-safari': isSafari }"
10-
/>
3+
<div class="absolute flex flex-col w-full items-center justify-center bg-transparent transition-bg" :class="className">
4+
<div class="jumbo absolute -inset-[10px] opacity-50" :class="{ '-safari': isSafari }" />
115
</div>
126
</template>
137

@@ -16,36 +10,31 @@
1610
from {
1711
background-position: 50% 50%, 50% 50%;
1812
}
13+
1914
to {
2015
background-position: 350% 50%, 350% 50%;
2116
}
2217
}
2318
2419
.jumbo {
25-
--stripes: repeating-linear-gradient(
26-
100deg,
27-
#fff 0%,
28-
#fff 7%,
29-
transparent 10%,
30-
transparent 12%,
31-
#fff 16%
32-
);
33-
--stripesDark: repeating-linear-gradient(
34-
100deg,
35-
#000 0%,
36-
#000 7%,
37-
transparent 10%,
38-
transparent 12%,
39-
#000 16%
40-
);
41-
--rainbow: repeating-linear-gradient(
42-
100deg,
43-
#60a5fa 10%,
44-
#e879f9 15%,
45-
#60a5fa 20%,
46-
#5eead4 25%,
47-
#60a5fa 30%
48-
);
20+
--stripes: repeating-linear-gradient(100deg,
21+
#fff 0%,
22+
#fff 7%,
23+
transparent 10%,
24+
transparent 12%,
25+
#fff 16%);
26+
--stripesDark: repeating-linear-gradient(100deg,
27+
#000 0%,
28+
#000 7%,
29+
transparent 10%,
30+
transparent 12%,
31+
#000 16%);
32+
--rainbow: repeating-linear-gradient(100deg,
33+
#60a5fa 10%,
34+
#e879f9 15%,
35+
#60a5fa 20%,
36+
#5eead4 25%,
37+
#60a5fa 30%);
4938
background-image: var(--stripes), var(--rainbow);
5039
background-size: 300%, 200%;
5140
background-position: 50% 50%, 50% 50%;
@@ -84,7 +73,6 @@
8473
.dark .jumbo::after {
8574
background-image: var(--stripesDark), var(--rainbow);
8675
}
87-
8876
</style>
8977

9078
<script setup lang="ts">
@@ -97,6 +85,6 @@ const props = defineProps<{
9785
const className = ref(props.class || 'h-screen')
9886
const isSafari = ref(
9987
navigator.userAgent.indexOf('Safari') !== -1 &&
100-
navigator.userAgent.indexOf('Chrome') === -1
88+
navigator.userAgent.indexOf('Chrome') === -1
10189
)
10290
</script>

docs/.vitepress/config.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export default defineConfig({
114114
},
115115
{
116116
text: '✨ Essential',
117+
collapsed: true,
117118
items: [
118119
{
119120
text: 'Route',
@@ -151,11 +152,16 @@ export default defineConfig({
151152
},
152153
{
153154
text: '🔎 Validation',
155+
collapsed: true,
154156
items: [
155157
{
156158
text: 'Overview',
157159
link: '/new/validation/overview'
158160
},
161+
{
162+
text: 'Schema Type',
163+
link: '/new/validation/schema-type'
164+
},
159165
{
160166
text: 'Primitive Type',
161167
link: '/new/validation/primitive-type'
@@ -176,6 +182,7 @@ export default defineConfig({
176182
},
177183
{
178184
text: '🔁 Life Cycle',
185+
collapsed: true,
179186
items: [
180187
{
181188
text: 'Overview',
@@ -185,6 +192,10 @@ export default defineConfig({
185192
text: 'On Request',
186193
link: '/new/life-cycle/request'
187194
},
195+
{
196+
text: 'Parse',
197+
link: '/new/life-cycle/parse'
198+
},
188199
{
189200
text: 'Transform',
190201
link: '/new/life-cycle/transform'
@@ -203,12 +214,17 @@ export default defineConfig({
203214
},
204215
{
205216
text: 'On Response',
206-
link: '/new/life-cycle/on-error'
217+
link: '/new/life-cycle/on-response'
218+
},
219+
{
220+
text: 'Trace',
221+
link: '/new/life-cycle/trace'
207222
}
208223
]
209224
},
210225
{
211226
text: '🧭 Patterns',
227+
collapsed: true,
212228
items: [
213229
{
214230
text: 'Cookie',
@@ -220,16 +236,12 @@ export default defineConfig({
220236
},
221237
{
222238
text: 'Web Socket',
223-
link: '/patterns/cookie'
239+
link: '/patterns/websocket'
224240
},
225241
{
226242
text: 'Documentation',
227243
link: '/patterns/creating-documentation'
228244
},
229-
{
230-
text: 'Trace',
231-
link: '/patterns/trace'
232-
},
233245
{
234246
text: 'Mount',
235247
link: '/patterns/mount'

docs/new/essential/context.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Context is information about each request passed to [route handler](/essential/h
44
Context is unique for each request, and is not shared except it's a `store` property which is a global mutable state object, (aka state).
55

66
Elysia context is consists of:
7+
- **path** - Path name of the request
78
- **body** - [HTTP message](https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages), form or file upload.
89
- **query** - [Query String](https://en.wikipedia.org/wiki/Query_string), include additional parameters for search query as JavaScript Object. (Query is extract from a value after pathname starting from '?' question mark sign)
910
- **params** - Elysia's path parameters parsed as JavaScript object

docs/new/essential/life-cycle.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ Elysia does the following for every request:
5050
- Modify `Context` before validation
5151
- Best for:
5252
- Mutate existing context to conform with validation.
53-
- Adding new context (derive is based on this)
53+
- Adding new context (derive this)
5454
4. **Validation** (not interceptable)
5555
- Strictly validate incoming request provided by `Elysia.t`
5656
5. **Before Handle**
5757
- Execute right before the route handler
5858
- **If value is returned, route handler will be skipped**
5959
- Best for:
60-
- Providing custom requirements to access route, eg. user session, autorization.
60+
- Providing custom requirements to access route, eg. user session, authorization.
6161
6. **Handle** (Route Handler)
6262
- A callback function of each route
6363
7. **After Handle**

docs/new/essential/plugin.md

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ Elysia avoids this by differentiating the instance by using **name** and **optio
105105
```typescript
106106
import { Elysia } from 'elysia'
107107

108-
const plugin = (config) =>
109-
new Elysia({
110-
name: 'my-plugin',
111-
seed: config,
112-
}).get(`${config.prefix}/hi`, () => 'Hi')
108+
const plugin = (config) => new Elysia({
109+
name: 'my-plugin', // [!code ++]
110+
seed: config, // [!code ++]
111+
})
112+
.get(`${config.prefix}/hi`, () => 'Hi')
113113

114114
const app = new Elysia()
115115
.use(
@@ -130,26 +130,63 @@ import { Elysia } from 'elysia'
130130
const plugin = new Elysia({ name: 'plugin' })
131131

132132
const app = new Elysia()
133-
.use(
134-
plugin({
135-
prefix: '/v2'
136-
})
137-
)
133+
.use(plugin())
134+
.use(plugin())
135+
.use(plugin())
136+
.use(plugin())
138137
.listen(3000)
139138
```
140139

141140
This allows Elysia to improve performance by reusing the registered plugins instead of processing the plugin over and over again.
142141

143-
This is useful when using [Service Locator](/patterns/service-locator) pattern to provide type inference for the Elysia app.
144-
145-
If no `name` or `seed` is provided, Elysia will not deduplicate the plugin.
146-
147142
::: tip
148143
Seed could be anything, varying from a string to a complex object or class.
149144

150145
If the provided value is class, Elysia will then try to use `.toString` method to generate a checksum.
151146
:::
152147

148+
## Service Locator
149+
When you apply multiple state and decorators plugin to an instance, the instance will gain type safety.
150+
151+
However, you may notice that when you are trying to use the decorated value in other instance without decorator, you may realize that the type is missing.
152+
153+
```typescript
154+
import { Elysia } from 'elysia'
155+
156+
const main = new Elysia()
157+
.decorate('a', 'a')
158+
.use(child)
159+
160+
const child = new Elysia()
161+
// ❌ 'a' is missing
162+
.get('/', ({ a }) => a)
163+
```
164+
165+
This is the limitation of TypeScript, Elysia only have reference to the current instance only.
166+
167+
To counter this, Elysia introduce the **Service Locator** pattern.
168+
169+
Service Locator allow us get the plugin for us automatically, when `use` is call, Elysia will do two thing:
170+
Lookup for plugin checksum and retrieve the value, otherwise register a new one
171+
Infer type from the plugin
172+
173+
To put it simply, we only need to provide the plugin reference for Elysia to locate the service.
174+
175+
```typescript
176+
// setup.ts
177+
const setup = new Elysia({ name: 'setup' })
178+
.decorate('a', 'a')
179+
180+
// index.ts
181+
const main = new Elysia()
182+
.use(child)
183+
184+
// child.ts
185+
const child = new Elysia()
186+
.use(setup)
187+
.get('/', ({ a }) => a)
188+
```
189+
153190
## Official Plugins
154191

155192
You can find an officially maintained plugin at Elysia's [plugins](/plugins).

docs/new/essential/scope.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,22 @@ This means that the code above is translated into:
4646
```typescript
4747
import { Elysia } from 'elysia'
4848

49-
new Elysia().post('/sign-up', ({ body }) => signUp(body), {
50-
body: t.Object({
51-
username: t.String(),
52-
password: t.String()
49+
new Elysia()
50+
.post('/sign-up', ({ body }) => signUp(body), {
51+
body: t.Object({
52+
username: t.String(),
53+
password: t.String()
54+
})
5355
})
54-
})
55-
.post('/sign-in', (({ body }) => signIn(body), {
56-
beforeHandle: isUserExists,
57-
body: t.Object({
58-
username: t.String(),
59-
password: t.String()
56+
.post('/sign-in', (({ body }) => signIn(body), {
57+
beforeHandle: isUserExists,
58+
body: t.Object({
59+
username: t.String(),
60+
password: t.String()
61+
})
6062
})
61-
}).get('/', () => 'hi').listen(3000)
63+
.get('/', () => 'hi')
64+
.listen(3000)
6265
```
6366
6467
## Groupped Guard

docs/new/life-cycle/after-handle.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# After Handle
2+
Execute after the main handler, for mapping a returned value of **before handle** and **route handler** into a proper response.
3+
4+
It's recommended to use After Handle in the following situations:
5+
- Transform requests into a new value, eg. Compression, Event Stream
6+
- Add custom headers based on the response value, eg. **Content-Type**
7+
8+
## Example
9+
Below is an example of using the after handle to add HTML content type to response headers.
10+
11+
```typescript
12+
import { Elysia } from 'elysia'
13+
import { isHtml } from '@elysiajs/html'
14+
15+
new Elysia()
16+
.get('/', () => '<h1>Hello World</h1>', {
17+
afterHandle({ response, set }) {
18+
if (isHtml(response))
19+
set.headers['Content-Type'] = 'text/html; charset=utf8'
20+
}
21+
})
22+
.get('/hi', () => '<h1>Hello World</h1>')
23+
.listen(3000)
24+
```
25+
26+
The response should be listed as follows:
27+
28+
| Path | Content-Type |
29+
| ---- | ------------------------ |
30+
| / | text/html; charset=utf8 |
31+
| /hi | text/plain; charset=utf8 |
32+
33+
## Returned Value
34+
If a value is returned After Handle will use a return value as a new response value unless the value is **undefined**
35+
36+
The above example could be rewritten as the following:
37+
```typescript
38+
import { Elysia } from 'elysia'
39+
import { isHtml } from '@elysiajs/html'
40+
41+
new Elysia()
42+
.get('/', () => '<h1>Hello World</h1>', {
43+
afterHandle({ response, set }) {
44+
if (isHtml(response))
45+
new Response(response, {
46+
headers: {
47+
'content-type': 'text/html; charset=utf8'
48+
}
49+
})
50+
}
51+
})
52+
.get('/hi', () => '<h1>Hello World</h1>')
53+
.listen(3000)
54+
```
55+
56+
## Context
57+
`onAfterHandle` Context is extends from `Context` with additional properties of the following:
58+
- response: Response to return to client
59+
60+
All of the context is based on normal context and can be used like normal context in route handler.

0 commit comments

Comments
 (0)