Skip to content

Commit 060ed03

Browse files
authored
feat(core): new view engine (#401)
* feat(core): wip refined view engine * test(core): wip * test: more tests for view engine * test(core): add tests case for multiple roots of views * test: more tests * test: fix paths * test: finishing up with tests * chore: add `@types/ejs` to ejs example * feat(example): add custom view examples * fix: proper node target * fix(core): `_locals` being added to options in `app.render` * chore: fix eta example types * chore: fix readme
1 parent bec8ee5 commit 060ed03

26 files changed

Lines changed: 924 additions & 6252 deletions

.eslintrc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@
1313
},
1414
"rules": {
1515
"@typescript-eslint/ban-ts-comment": "warn",
16-
"@typescript-eslint/no-explicit-any": "warn"
16+
"@typescript-eslint/no-explicit-any": "warn",
17+
"no-unused-vars": "off",
18+
"@typescript-eslint/no-unused-vars": [
19+
"warn", // or "error"
20+
{
21+
"argsIgnorePattern": "^_",
22+
"varsIgnorePattern": "^_",
23+
"caughtErrorsIgnorePattern": "^_"
24+
}
25+
]
1726
}
1827
}

config/build.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { builtinModules } from 'node:module'
55
export const build = (dependencies: Record<string, string> = {}) =>
66
defineConfig({
77
build: {
8-
target: 'node12',
8+
target: 'node14.21.3',
99
minify: false,
1010
lib: {
1111
entry: 'src/index.ts',

examples/custom-view/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Custom view example
2+
3+
Example of a custom View engine to alter rendering logic of a template.
4+
5+
## Setup
6+
7+
```sh
8+
tinyhttp new custom-view
9+
```
10+
11+
## Run
12+
13+
```sh
14+
node index.js
15+
```

examples/custom-view/index.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { App } from '@tinyhttp/app'
2+
import { CustomView } from './view.js'
3+
import fs from 'node:fs/promises'
4+
5+
const app = new App()
6+
7+
app.set('views', `${process.cwd()}/views`)
8+
9+
app.set('view', CustomView)
10+
11+
app.engine('html', async (path, locals, _opts, cb) => {
12+
const template = await fs.readFile(path, 'utf-8')
13+
14+
const renderedTemplate = template.replace(/{{\s*([^}\s]+)\s*}}/g, (_, placeholder) => {
15+
return locals[placeholder] || ''
16+
})
17+
cb(null, renderedTemplate)
18+
})
19+
20+
app.get('/', (req, res) => {
21+
res.render('hello.html', { name: 'v1rtl' })
22+
})
23+
24+
app.listen(3000)

examples/custom-view/package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "custom-view",
3+
"private": true,
4+
"type": "module",
5+
"dependencies": {
6+
"@tinyhttp/app": "workspace:*"
7+
},
8+
"scripts": {
9+
"start": "node index.js"
10+
}
11+
}

examples/custom-view/view.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { extname } from 'node:path'
2+
3+
export class CustomView {
4+
constructor(name, options = {}) {
5+
this.options = options
6+
this.ext = extname(name)
7+
this.engine = options.engines[this.ext]
8+
this.path = `${options.root}/${name}`
9+
}
10+
async render(options, data, cb) {
11+
this.engine(this.path, data, options, cb)
12+
}
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>Hello {{ name }}!</p>

examples/ejs/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,8 @@
88
},
99
"scripts": {
1010
"start": "node index.js"
11+
},
12+
"devDependencies": {
13+
"@types/ejs": "^3.1.2"
1114
}
1215
}

examples/eta/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Eta example
22

3-
Basic example of using tinyhttp and [Eta](https://github.com/eta-dev/eta).
3+
Basic example of using tinyhttp and [Eta v2](https://github.com/eta-dev/eta).
44

55
## Install
66

examples/eta/index.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { App } from '@tinyhttp/app'
22
import { renderFile as eta } from 'eta'
3-
import { EtaConfig } from 'eta/dist/types/config'
3+
import { EtaConfig, PartialConfig } from 'eta/dist/types/config'
44

5-
const app = new App<EtaConfig>()
5+
const app = new App()
66

7-
app.engine('eta', eta)
7+
app.engine<EtaConfig>('eta', eta)
88

99
function func() {
1010
return new Promise((resolve) => {
@@ -16,14 +16,12 @@ function func() {
1616

1717
app.use(
1818
(_, res) =>
19-
void res.render(
19+
void res.render<PartialConfig>(
2020
'index.eta',
2121
{ name: 'Eta', func },
2222
{
23-
renderOptions: {
24-
async: true,
25-
cache: true
26-
}
23+
async: true,
24+
cache: true
2725
}
2826
)
2927
)

0 commit comments

Comments
 (0)