Skip to content

Commit

Permalink
feat: routes/ directory
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Apr 7, 2022
1 parent b40f7ee commit 2f96340
Show file tree
Hide file tree
Showing 20 changed files with 70 additions and 45 deletions.
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ mkdir nitro-app
cd nitro-app
```

1️⃣ Create `api/hello.ts`:
1️⃣ Create `routes/index.ts`:

```ts [api/hello.ts]
```ts [routes/index.ts]
export default () => 'nitro is amazing!'
```

Expand All @@ -63,7 +63,7 @@ export default () => 'nitro is amazing!'
npx nitropack dev
```

🪄 Your API is ready at http://localhost:3000/api/hello
🪄 Your API is ready at http://localhost:3000/

**🤓 [TIP]** Check `.nitro/dev/index.mjs` if want to know what is happening

Expand Down Expand Up @@ -92,14 +92,16 @@ you should add the following to your `tsconfig.json` file:
}
```

## API Routes
## Routes and API Routes

API files inside `api/` directory will be automatically mapped to API routes and served using [h3](https://github.com/unjs/h3) router.
Handler files inside `routes/` and `api/` directory will be automatically mapped to [unjs/h3](https://github.com/unjs/h3) routes.

**Note:** `api/` is a shortcut for `routes/api` as a common prefix. However please note that some deployment providers use `app/` directory for their API format. In this case, you can simply use `routes/api` or `srcDir` option to move everything under `src/` or `server/` directory.

**Example:** Simple API route

```js
// api/test.ts
// routes/test.ts
import { eventHandler } from 'h3'
export default eventHandler(() => 'Hello World!')
Expand All @@ -108,13 +110,12 @@ export default eventHandler(() => 'Hello World!')
**Example:** API route with params
```js
// api/hello/[name].ts
// routes/hello/[name].ts
import { eventHandler } from 'h3'
export default eventHandler(event => `Hello ${event.params.name}!`)
export default eventHandler(event => `Hello ${event.context.params.name}!`)
```
## Storage
nitro provides a built-in storage layer using [unjs/unstorage](https://github.com/unjs/unstorage) that can abstract filesystem access.
Expand Down Expand Up @@ -165,7 +166,7 @@ import { cachedEventHandler } from '#nitro'
**Example:** Cache an API handler
```js
// api/test.ts
// routes/cached.ts
import { defineCachedFunction } from '#nitro'
const myFn = cachedEventHandler(async () => {
Expand All @@ -187,7 +188,7 @@ const myFn = defineCachedFunction(async () => {
```
**Example:** Enable cache on group of routes
**Example:** Enable cache on group of routes (**🧪 Experimental!**)
```js
// nitro.config.ts
Expand Down Expand Up @@ -404,7 +405,7 @@ Server's main base URL.
Server handlers and routes.
If `api/` and `middleware/` directories exist, they will be automatically added to the handlers array.
If `routes/`, `api/` or `middleware/` directories exist, they will be automatically added to the handlers array.
#### `devHandlers`
Expand All @@ -416,6 +417,8 @@ We can use `devHandlers` but note that they are **only available in development
#### `routes`
**🧪 Experimental!**
Route options. It is a map from route pattern (following [unjs/radix3](https://github.com/unjs/radix3)) to options.
Example:
Expand Down
2 changes: 1 addition & 1 deletion examples/api-routes/api/hello/:name.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { defineEventHandler } from 'h3'

export default defineEventHandler(event => `Hello ${event.params.name}!`)
export default defineEventHandler(event => `Hello ${event.context.params.name}!`)
2 changes: 0 additions & 2 deletions examples/api-routes/public/index.html

This file was deleted.

11 changes: 11 additions & 0 deletions examples/api-routes/routes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineEventHandler } from 'h3'

export default defineEventHandler(() => {
return `
<h2>API Routes:</h2>
<ul>
<li><a href="/api/hello">/api/hello</a></li>
<li><a href="/api/hello/world">/api/hello/world</a></li>
</ul>
`
})
File renamed without changes.
3 changes: 0 additions & 3 deletions examples/hello-world/api/hello.ts

This file was deleted.

1 change: 0 additions & 1 deletion examples/hello-world/public/index.html

This file was deleted.

3 changes: 3 additions & 0 deletions examples/hello-world/routes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { defineEventHandler } from 'h3'

export default defineEventHandler(() => '<h1>nitro is amazing!</h1>')
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineEventHandler } from 'h3'

export default defineEventHandler((event) => {
console.log('Middleware:', event.req.url)
event.context.auth = { name: 'User ' + Math.round(Math.random() * 100) }
})
5 changes: 5 additions & 0 deletions examples/middleware/routes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineEventHandler } from 'h3'

export default defineEventHandler(event => ({
auth: event.context.auth
}))
File renamed without changes.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"fs-extra": "^10.0.1",
"globby": "^13.1.1",
"gzip-size": "^7.0.0",
"h3": "^0.6.0",
"h3": "^0.7.1",
"hasha": "^5.2.2",
"hookable": "^5.1.1",
"http-proxy": "^1.18.1",
Expand Down
1 change: 0 additions & 1 deletion playground/nitro.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { defineNitroConfig } from '../src'

export default defineNitroConfig({
renderer: '~/app'
})
3 changes: 3 additions & 0 deletions playground/routes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { eventHandler } from 'h3'

export default eventHandler(() => '<h1>Hello Nitro!</h1>')
2 changes: 1 addition & 1 deletion src/rollup/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export const getRollupConfig = (nitro: Nitro) => {
...nitro.options.handlers
]
if (nitro.options.serveStatic) {
handlers.unshift({ route: '/', handler: '#nitro/static' })
handlers.unshift({ route: '', handler: '#nitro/static' })
}
if (nitro.options.renderer) {
handlers.push({ route: '/**', handler: nitro.options.renderer })
Expand Down
2 changes: 1 addition & 1 deletion src/rollup/plugins/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ ${imports.map(handler => `import ${getImportId(handler)} from '${handler}';`).jo
${lazyImports.map(handler => `const ${getImportId(handler)} = () => import('${handler}');`).join('\n')}
export const handlers = [
${handler.map(m => ` { route: '${m.route || '/'}', handler: ${getImportId(m.handler)}, lazy: ${m.lazy || true} }`).join(',\n')}
${handler.map(m => ` { route: '${m.route || ''}', handler: ${getImportId(m.handler)}, lazy: ${m.lazy || true} }`).join(',\n')}
];
`.trim()
// console.log(code)
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function createNitroApp (): NitroApp {
})
}

if (h.route === '/') {
if (h.route === '') {
h3App.use(config.app.baseURL, handler)
} else {
router.use(h.route, handler)
Expand Down
35 changes: 21 additions & 14 deletions src/scan.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { resolve, join } from 'pathe'
import { globby } from 'globby'
import { withBase } from 'ufo'
import { withBase, withLeadingSlash, withoutTrailingSlash } from 'ufo'
import type { Nitro, NitroEventHandler } from './types'

export const GLOB_SCAN_PATTERN = '**/*.{ts,mjs,js,cjs}'
type FileInfo = { dir: string, name: string, path: string }
type FileInfo = { dir: string, path: string, fullPath: string }

export async function scanHandlers (nitro: Nitro) {
const handlers = await Promise.all([
scanMiddleware(nitro),
scanAPI(nitro)
scanRoutes(nitro, 'api', '/api'),
scanRoutes(nitro, 'routes', '/')
]).then(r => r.flat())

nitro.scannedHandlers = handlers.flatMap(h => h.handlers)
Expand All @@ -19,16 +20,24 @@ export async function scanHandlers (nitro: Nitro) {

export function scanMiddleware (nitro: Nitro) {
return scanServerDir(nitro, 'middleware', file => ({
route: '/',
handler: file.path
route: '',
handler: file.fullPath
}))
}

export function scanAPI (nitro: Nitro) {
return scanServerDir(nitro, 'api', file => ({
handler: file.path,
route: withBase(file.name.replace(/\[([a-z]+)\]/g, ':$1'), '/api')
}))
export function scanRoutes (nitro: Nitro, dir: string, prefix: string = '/') {
return scanServerDir(nitro, dir, (file) => {
let route = file.path
.replace(/\.[a-z]+$/, '')
.replace(/index$/, '')
.replace(/\[([a-z]+)\]/g, ':$1')
route = withLeadingSlash(withoutTrailingSlash(withBase(route, prefix)))

return {
handler: file.fullPath,
route
}
})
}

async function scanServerDir (nitro: Nitro, name: string, mapper: (file: FileInfo) => NitroEventHandler) {
Expand All @@ -44,10 +53,8 @@ function scanDirs (dirs: string[]): Promise<FileInfo[]> {
return fileNames.map((fileName) => {
return {
dir,
name: fileName
.replace(/\.[a-z]+$/, '')
.replace(/\/index$/, ''),
path: resolve(dir, fileName)
path: fileName,
fullPath: resolve(dir, fileName)
}
}).sort((a, b) => b.path.localeCompare(a.path))
})).then(r => r.flat())
Expand Down
2 changes: 1 addition & 1 deletion test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export async function setupTest (preset) {
})
await prepare(nitro)
await copyPublicAssets(nitro)
await build(nitro)
await prerender(nitro)
await build(nitro)

afterAll(async () => {
if (ctx.server) {
Expand Down
10 changes: 5 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4103,15 +4103,15 @@ __metadata:
languageName: node
linkType: hard

"h3@npm:^0.6.0":
version: 0.6.0
resolution: "h3@npm:0.6.0"
"h3@npm:^0.7.1":
version: 0.7.1
resolution: "h3@npm:0.7.1"
dependencies:
cookie-es: ^0.5.0
destr: ^1.1.0
radix3: ^0.1.1
ufo: ^0.7.11
checksum: be187ff3a60b2a9a63babb9ea5d824d121c854396229d8843b9ac39dba316c27dbbd9fe30e111ac59dd5f6e826a98934d1e2e92d3b89cdb78b5c8d999ac89772
checksum: 72845e5c77fb4974a2ed50d036c5a8277b5362c59f83a7f8dc8ab36e5fe4952e6134d2aaca6eab7a7baa146a3cd3e8a26ac062ce9761eb9135a968ca765244a7
languageName: node
linkType: hard

Expand Down Expand Up @@ -5692,7 +5692,7 @@ __metadata:
fs-extra: ^10.0.1
globby: ^13.1.1
gzip-size: ^7.0.0
h3: ^0.6.0
h3: ^0.7.1
hasha: ^5.2.2
hookable: ^5.1.1
http-proxy: ^1.18.1
Expand Down

0 comments on commit 2f96340

Please sign in to comment.