Skip to content

Commit aae9322

Browse files
committed
chore(ui/playground): use Hono instead of express
1 parent ed1bfde commit aae9322

12 files changed

Lines changed: 325 additions & 626 deletions

File tree

app-vite/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@
116116
"fflate": "^0.8.2",
117117
"fs-extra": "^11.3.4",
118118
"html-minifier-terser": "^7.2.0",
119-
"inquirer": "^13.4.0",
119+
"inquirer": "^13.4.1",
120120
"isbinaryfile": "^5.0.2",
121121
"kolorist": "^1.8.0",
122122
"magic-string": "^0.30.21",
@@ -129,9 +129,9 @@
129129
"semver": "^7.7.4",
130130
"serialize-javascript": "^7.0.5",
131131
"serve-static": "^2.2.1",
132-
"tinyglobby": "^0.2.10",
132+
"tinyglobby": "^0.2.16",
133133
"ts-essentials": "^10.1.1",
134-
"vite": "^8.0.5",
134+
"vite": "^8.0.7",
135135
"webpack-merge": "^6.0.1"
136136
},
137137
"devDependencies": {

create-quasar/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"kolorist": "^1.8.0",
3535
"minimist": "^1.2.8",
3636
"prompts": "^2.4.2",
37-
"tinyglobby": "^0.2.10"
37+
"tinyglobby": "^0.2.16"
3838
},
3939
"devDependencies": {
4040
"@types/prompts": "^2.4.9",

extras/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,6 @@
214214
"ionicons": "8.0.13",
215215
"line-awesome": "1.3.0",
216216
"themify-icons": "github:lykmapipo/themify-icons",
217-
"tinyglobby": "^0.2.15"
217+
"tinyglobby": "^0.2.16"
218218
}
219219
}

pnpm-lock.yaml

Lines changed: 162 additions & 541 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
"rolldown": "^1.0.0-rc.13",
8989
"sass-embedded": "^1.98.0",
9090
"table": "^6.8.2",
91-
"tinyglobby": "^0.2.10",
91+
"tinyglobby": "^0.2.16",
9292
"typescript": "^6.0.0",
9393
"vue": "catalog:"
9494
},

ui/playground/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
"vue-router": "catalog:"
1919
},
2020
"devDependencies": {
21+
"@hono/node-server": "^1.19.13",
2122
"@quasar/app-vite": "workspace:*",
22-
"express": "^5.0.0",
23-
"postcss": "^8.5.8"
23+
"hono": "^4.12.12",
24+
"postcss": "^8.5.9"
2425
},
2526
"engines": {
2627
"node": "^24 || ^22 || ^20",

ui/playground/src-ssr/middlewares/render.js

Lines changed: 37 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,42 @@ import { defineSsrMiddleware } from '#q-app/wrappers'
55
// render the page with Vue
66

77
export default defineSsrMiddleware(({ app, resolve, render, serve }) => {
8-
// we capture any other Express route and hand it
9-
// over to Vue and Vue Router to render our page
10-
app.get(resolve.urlPath('{*path}'), (req, res) => {
11-
res.setHeader('Content-Type', 'text/html')
12-
13-
render(/* the ssrContext: */ { req, res })
14-
.then(html => {
15-
// now let's send the rendered html to the client
16-
res.send(html)
17-
})
18-
.catch(err => {
19-
// oops, we had an error while rendering the page
20-
21-
// we were told to redirect to another URL
22-
if (err.url) {
23-
if (err.code) {
24-
res.redirect(err.code, err.url)
25-
} else {
26-
res.redirect(err.url)
27-
}
28-
} else if (err.code === 404) {
29-
// hmm, Vue Router could not find the requested route
30-
31-
// Should reach here only if no "catch-all" route
32-
// is defined in /src/routes
33-
res.status(404).send('404 | Page Not Found')
34-
} else if (import.meta.env.QUASAR_DEV) {
35-
// well, we treat any other code as error;
36-
// if we're in dev mode, then we can use Quasar CLI
37-
// to display a nice error page that contains the stack
38-
// and other useful information
39-
40-
// serve.error is available on dev only
41-
const { headers, html } = serve.error({ err, req })
42-
res.writeHead(500, headers)
43-
res.end(html)
44-
} else {
45-
// we're in production, so we should have another method
46-
// to display something to the client when we encounter an error
47-
// (for security reasons, it's not ok to display the same wealth
48-
// of information as we do in development)
49-
50-
// Render Error Page on production or
51-
// create a route (/src/routes) for an error page and redirect to it
52-
res.status(500).send('500 | Internal Server Error')
53-
54-
if (import.meta.env.QUASAR_DEBUG) {
55-
console.error(err.stack)
56-
}
57-
}
58-
})
8+
app.get(resolve.urlPath('/*'), async c => {
9+
const req = c.env?.incoming
10+
const res = c.env?.outgoing
11+
12+
try {
13+
const html = await render({ req, res })
14+
return c.html(html)
15+
} catch (err) {
16+
// oops, we had an error while rendering the page
17+
18+
// we were told to redirect to another URL
19+
if (err.url) {
20+
const redirectCode = err.code || 302
21+
return c.redirect(err.url, redirectCode)
22+
}
23+
24+
// hmm, Vue Router could not find the requested route
25+
if (err.code === 404) {
26+
c.status(404)
27+
return c.text('404 | Page Not Found')
28+
}
29+
30+
// we treat any other code as error
31+
if (import.meta.env.QUASAR_DEV) {
32+
// In dev mode, Quasar CLI displays a nice error page.
33+
// serve.error uses the native Node res to write the Vite overlay.
34+
const { html, headers } = serve.error({ err, req })
35+
return c.html(html, 500, headers)
36+
}
37+
38+
if (import.meta.env.QUASAR_DEBUG) {
39+
console.error(err.stack)
40+
}
41+
42+
// we're in production, render a generic error
43+
return c.text('500 | Internal Server Error', 500)
44+
}
5945
})
6046
})

ui/playground/src-ssr/server.js

Lines changed: 109 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99
* Make sure to yarn add / npm install (in your project root)
1010
* anything you import here (except for express and compression).
1111
*/
12-
import express from 'express'
12+
import { Hono } from 'hono'
13+
import { serve } from '@hono/node-server'
14+
import { serveStatic } from '@hono/node-server/serve-static'
15+
import { lstatSync } from 'node:fs'
1316
import {
1417
defineSsrCreate,
18+
defineSsrInjectDevMiddleware,
1519
defineSsrListen,
1620
defineSsrClose,
1721
defineSsrServeStaticContent,
@@ -23,9 +27,49 @@ import {
2327
* If needed, prepare your webserver to receive
2428
* connect-like middlewares.
2529
*
26-
* Should NOT be async!
30+
* Can be async: defineSsrCreate(async ({ ... }) => { ... })
2731
*/
28-
export const create = defineSsrCreate((/* { ... } */) => express())
32+
export const create = defineSsrCreate(async (/* { ... } */) => {
33+
const app = new Hono()
34+
35+
// place here any middlewares that
36+
// absolutely need to run before anything else
37+
if (import.meta.env.QUASAR_PROD) {
38+
const { compress } = await import('hono/compress')
39+
app.use(compress())
40+
}
41+
42+
return app
43+
})
44+
45+
/**
46+
* Used by Quasar SSR dev server to inject middleware into the webserver.
47+
* It uses it to handle Vite dev server, handle public paths, etc.
48+
* The given middleware is compatible with `node:http`'s Server, Express, Connect, etc.
49+
*
50+
* Can be async: defineSsrInjectDevMiddleware(async ({ app }) => { ... })
51+
*/
52+
export const injectDevMiddleware = defineSsrInjectDevMiddleware(
53+
({ app }) =>
54+
middleware => {
55+
app.use('*', async (c, next) => {
56+
// @hono/node-server exposes the raw Node.js req and res objects
57+
const req = c.env.incoming
58+
const res = c.env.outgoing
59+
60+
// Run the connect-style middleware (Vite Dev Server)
61+
const passed = await new Promise(resolve => {
62+
middleware(req, res, () => resolve(true))
63+
})
64+
65+
// If the Vite middleware calls next(), it didn't handle the request,
66+
// so we let Hono continue down the chain.
67+
if (passed) {
68+
await next()
69+
}
70+
})
71+
}
72+
)
2973

3074
/**
3175
* You need to make the server listen to the indicated port
@@ -37,15 +81,37 @@ export const create = defineSsrCreate((/* { ... } */) => express())
3781
*
3882
* For production, you can instead export your
3983
* handler for serverless use or whatever else fits your needs.
84+
*
85+
* Can be async: defineSsrListen(async ({ app, devHttpsApp, port }) => { ... })
4086
*/
41-
export const listen = defineSsrListen(({ app, devHttpsApp, port }) => {
42-
const server = devHttpsApp || app
43-
return server.listen(port, () => {
44-
if (import.meta.env.QUASAR_PROD) {
45-
console.log('Server listening at port ' + port)
87+
export const listen = defineSsrListen(
88+
async ({ app, devHttpsOptions, port }) => {
89+
const opts = {
90+
fetch: app.fetch,
91+
port
4692
}
47-
})
48-
})
93+
94+
/**
95+
* For production HTTPS you can use the /src-ssr/server-assets folder
96+
* to place your certificates and then read them here to create the server.
97+
*/
98+
99+
if (import.meta.env.QUASAR_DEV && devHttpsOptions) {
100+
const { createServer } = await import('node:https')
101+
opts.createServer = createServer
102+
opts.serverOptions = { ...devHttpsOptions }
103+
} else {
104+
const { createServer } = await import('node:http')
105+
opts.createServer = createServer
106+
}
107+
108+
return serve(opts, info => {
109+
if (import.meta.env.QUASAR_PROD) {
110+
console.log(`🚀 Server listening at port ${info.port}`)
111+
}
112+
})
113+
}
114+
)
49115

50116
/**
51117
* Should close the server and free up any resources.
@@ -55,7 +121,7 @@ export const listen = defineSsrListen(({ app, devHttpsApp, port }) => {
55121
* Should you need the result of the "listen()" call above,
56122
* you can use the "listenResult" param.
57123
*
58-
* Can be async.
124+
* Can be async: defineSsrClose(async ({ listenResult }) => { ... })
59125
*/
60126
export const close = defineSsrClose(({ listenResult }) => listenResult.close())
61127

@@ -66,15 +132,40 @@ const maxAge = import.meta.env.QUASAR_DEV ? 0 : 1000 * 60 * 60 * 24 * 30
66132
* to serve static content at "urlPath" from "pathToServe" folder/file.
67133
*
68134
* Notice resolve.urlPath(urlPath) and resolve.public(pathToServe) usages.
135+
*
136+
* Can be async: defineSsrServeStaticContent(async ({ app, resolve }) => {
137+
* Can return an async function: return async ({ urlPath = '/', pathToServe = '.', opts = {} }) => {
69138
*/
70139
export const serveStaticContent = defineSsrServeStaticContent(
71-
({ app, resolve }) =>
72-
({ urlPath = '/', pathToServe = '.', opts = {} }) => {
73-
const serveFn = express.static(resolve.public(pathToServe), {
74-
maxAge,
75-
...opts
76-
})
77-
app.use(resolve.urlPath(urlPath), serveFn)
140+
({ app, publicPath, resolve }) =>
141+
({ urlPath, pathToServe, opts = {} }) => {
142+
const pubPath = resolve.public(pathToServe)
143+
const isDir = lstatSync(publicPath).isDirectory()
144+
145+
const resolvedUrlPath = resolve.urlPath(urlPath)
146+
const routePath = isDir
147+
? resolvedUrlPath.endsWith('*')
148+
? resolvedUrlPath
149+
: `${resolvedUrlPath}*`
150+
: resolvedUrlPath
151+
152+
const { maxAge: maxAgeOpt, ...serveOpts } = opts
153+
const cacheAge = maxAgeOpt !== void 0 ? maxAgeOpt : maxAge
154+
155+
if (cacheAge > 0) {
156+
app.get(routePath, async (c, next) => {
157+
c.header('Cache-Control', `public, max-age=${cacheAge}`)
158+
await next()
159+
})
160+
}
161+
162+
app.use(
163+
routePath,
164+
serveStatic({
165+
[isDir ? 'root' : 'path']: pubPath,
166+
...serveOpts
167+
})
168+
)
78169
}
79170
)
80171

ui/testing/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616
"@quasar/extras": "workspace:*",
1717
"@quasar/vite-plugin": "workspace:^",
1818
"@vitejs/plugin-vue": "^6.0.5",
19-
"@vitest/ui": "^4.1.2",
19+
"@vitest/ui": "^4.1.3",
2020
"@vue/test-utils": "^2.4.6",
2121
"acorn": "^8.16.0",
2222
"fs-extra": "^11.3.4",
2323
"jsdom": "29.0.1",
2424
"prompts": "^2.4.2",
25-
"tinyglobby": "^0.2.10",
26-
"vite": "^8.0.5",
27-
"vitest": "^4.1.2",
25+
"tinyglobby": "^0.2.16",
26+
"vite": "^8.0.7",
27+
"vitest": "^4.1.3",
2828
"vue": "catalog:"
2929
}
3030
}

utils/render-ssr-error/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"fs-extra": "^11.3.4",
4242
"prismjs": "^1.29.0",
4343
"quasar": "workspace:*",
44-
"vite": "^8.0.5",
44+
"vite": "^8.0.7",
4545
"vue": "catalog:",
4646
"vue-router": "catalog:"
4747
},

0 commit comments

Comments
 (0)