diff options
author | 2024-08-29 19:58:06 +0200 | |
---|---|---|
committer | 2024-08-29 19:58:06 +0200 | |
commit | b2d097b51e1d8845d955cee4d1e8838f96975638 (patch) | |
tree | 1593bbc71f60058579ed35219adf53b68ee3a24b /packages/integrations/node/src/serve-app.ts | |
parent | 93a1db68cd9cf3bb2a4d9f7a8af13cbd881eb701 (diff) | |
parent | 7897044c1d95ef905a4835dafe75d5b5b323b5bf (diff) | |
download | astro-b2d097b51e1d8845d955cee4d1e8838f96975638.tar.gz astro-b2d097b51e1d8845d955cee4d1e8838f96975638.tar.zst astro-b2d097b51e1d8845d955cee4d1e8838f96975638.zip |
Merge `vercel` and `node` into main #366
Diffstat (limited to 'packages/integrations/node/src/serve-app.ts')
-rw-r--r-- | packages/integrations/node/src/serve-app.ts | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/packages/integrations/node/src/serve-app.ts b/packages/integrations/node/src/serve-app.ts new file mode 100644 index 000000000..2934a01ab --- /dev/null +++ b/packages/integrations/node/src/serve-app.ts @@ -0,0 +1,52 @@ +import { AsyncLocalStorage } from 'node:async_hooks'; +import { NodeApp } from 'astro/app/node'; +import type { RequestHandler } from './types.js'; + +/** + * Creates a Node.js http listener for on-demand rendered pages, compatible with http.createServer and Connect middleware. + * If the next callback is provided, it will be called if the request does not have a matching route. + * Intended to be used in both standalone and middleware mode. + */ +export function createAppHandler(app: NodeApp): RequestHandler { + /** + * Keep track of the current request path using AsyncLocalStorage. + * Used to log unhandled rejections with a helpful message. + */ + const als = new AsyncLocalStorage<string>(); + const logger = app.getAdapterLogger(); + process.on('unhandledRejection', (reason) => { + const requestUrl = als.getStore(); + logger.error(`Unhandled rejection while rendering ${requestUrl}`); + console.error(reason); + }); + + return async (req, res, next, locals) => { + let request: Request; + try { + request = NodeApp.createRequest(req); + } catch (err) { + logger.error(`Could not render ${req.url}`); + console.error(err); + res.statusCode = 500; + res.end('Internal Server Error'); + return; + } + + const routeData = app.match(request); + if (routeData) { + const response = await als.run(request.url, () => + app.render(request, { + addCookieHeader: true, + locals, + routeData, + }) + ); + await NodeApp.writeResponse(response, res); + } else if (next) { + return next(); + } else { + const response = await app.render(req); + await NodeApp.writeResponse(response, res); + } + }; +} |