diff options
author | 2022-03-24 07:26:25 -0400 | |
---|---|---|
committer | 2022-03-24 07:26:25 -0400 | |
commit | 5e52814d97a5723dbe7ebb32fbe040a7a4c0ea77 (patch) | |
tree | b4cd5790933ad9829159314191487462bd5e9d2e /packages/integrations | |
parent | 5c96145527f9480e7b7b16b599f4b2091e41aa6c (diff) | |
download | astro-5e52814d97a5723dbe7ebb32fbe040a7a4c0ea77.tar.gz astro-5e52814d97a5723dbe7ebb32fbe040a7a4c0ea77.tar.zst astro-5e52814d97a5723dbe7ebb32fbe040a7a4c0ea77.zip |
Adapters v0 (#2855)
* Adapter v0
* Finalizing adapters
* Update the lockfile
* Add the default adapter after config setup is called
* Create the default adapter in config:done
* Fix lint error
* Remove unused callConfigSetup
* remove unused export
* Use a test adapter to test SSR
* Adds a changeset
* Updated based on feedback
* Updated the lockfile
* Only throw if set to a different adapter
* Clean up outdated comments
* Move the adapter to an config option
* Make adapter optional
* Update the docs/changeset to reflect config API change
* Clarify regular Node usage
Diffstat (limited to 'packages/integrations')
-rw-r--r-- | packages/integrations/node/package.json | 32 | ||||
-rw-r--r-- | packages/integrations/node/readme.md | 53 | ||||
-rw-r--r-- | packages/integrations/node/src/index.ts | 20 | ||||
-rw-r--r-- | packages/integrations/node/src/server.ts | 48 | ||||
-rw-r--r-- | packages/integrations/node/tsconfig.json | 10 |
5 files changed, 163 insertions, 0 deletions
diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json new file mode 100644 index 000000000..1208dbd4a --- /dev/null +++ b/packages/integrations/node/package.json @@ -0,0 +1,32 @@ +{ + "name": "@astrojs/node", + "description": "Deploy your site to a Node.js server", + "version": "0.0.1", + "type": "module", + "types": "./dist/index.d.ts", + "author": "withastro", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/withastro/astro.git", + "directory": "packages/integrations/node" + }, + "bugs": "https://github.com/withastro/astro/issues", + "homepage": "https://astro.build", + "exports": { + ".": "./dist/index.js", + "./server.js": "./dist/server.js", + "./package.json": "./package.json" + }, + "scripts": { + "build": "astro-scripts build \"src/**/*.ts\" && tsc", + "dev": "astro-scripts dev \"src/**/*.ts\"" + }, + "dependencies": { + "@astrojs/webapi": "^0.11.0" + }, + "devDependencies": { + "astro": "workspace:*", + "astro-scripts": "workspace:*" + } +} diff --git a/packages/integrations/node/readme.md b/packages/integrations/node/readme.md new file mode 100644 index 000000000..011485278 --- /dev/null +++ b/packages/integrations/node/readme.md @@ -0,0 +1,53 @@ +# @astrojs/node + +An experimental static-side rendering adapter for use with Node.js servers. + +In your astro.config.mjs use: + +```js +import nodejs from '@astrojs/node'; + +export default { + adapter: nodejs() +} +``` + +After performing a build there will be a `dist/server/entry.mjs` module that works like a middleware function. You can use with any framework that supports the Node `request` and `response` objects. For example, with Express you can do: + +```js +import express from 'express'; +import { handler as ssrHandler } from './dist/server/entry.mjs'; + +const app = express(); +app.use(ssrHandler); + +app.listen(8080); +``` + +# Using `http` + +This adapter does not require you use Express and can work with even the `http` and `https` modules. The adapter does following the Expression convention of calling a function when either + +- A route is not found for the request. +- There was an error rendering. + +You can use these to implement your own 404 behavior like so: + +```js +import http from 'http'; +import { handler as ssrHandler } from './dist/server/entry.mjs'; + +http.createServer(function(req, res) { + ssrHandler(req, res, err => { + if(err) { + res.writeHead(500); + res.end(err.toString()); + } else { + // Serve your static assets here maybe? + // 404? + res.writeHead(404); + res.end(); + } + }); +}).listen(8080); +``` diff --git a/packages/integrations/node/src/index.ts b/packages/integrations/node/src/index.ts new file mode 100644 index 000000000..903d5b1cc --- /dev/null +++ b/packages/integrations/node/src/index.ts @@ -0,0 +1,20 @@ +import type { AstroAdapter, AstroIntegration } from 'astro'; + +export function getAdapter(): AstroAdapter { + return { + name: '@astrojs/node', + serverEntrypoint: '@astrojs/node/server.js', + exports: ['handler'], + }; +} + +export default function createIntegration(): AstroIntegration { + return { + name: '@astrojs/node', + hooks: { + 'astro:config:done': ({ setAdapter }) => { + setAdapter(getAdapter()); + } + } + }; +} diff --git a/packages/integrations/node/src/server.ts b/packages/integrations/node/src/server.ts new file mode 100644 index 000000000..791dc58b2 --- /dev/null +++ b/packages/integrations/node/src/server.ts @@ -0,0 +1,48 @@ +import type { SSRManifest } from 'astro'; +import type { IncomingMessage, ServerResponse } from 'http'; +import { NodeApp } from 'astro/app/node'; +import { polyfill } from '@astrojs/webapi'; + +polyfill(globalThis, { + exclude: 'window document' +}); + +export function createExports(manifest: SSRManifest) { + const app = new NodeApp(manifest, new URL(import.meta.url)); + return { + async handler(req: IncomingMessage, res: ServerResponse, next?: (err?: unknown) => void) { + const route = app.match(req); + + if(route) { + try { + const response = await app.render(req); + await writeWebResponse(res, response); + } catch(err: unknown) { + if(next) { + next(err); + } else { + throw err; + } + } + } else if(next) { + return next(); + } + } + } +} + +async function writeWebResponse(res: ServerResponse, webResponse: Response) { + const { status, headers, body } = webResponse; + res.writeHead(status, Object.fromEntries(headers.entries())); + if (body) { + const reader = body.getReader(); + while (true) { + const { done, value } = await reader.read(); + if (done) break; + if (value) { + res.write(value); + } + } + } + res.end(); +} diff --git a/packages/integrations/node/tsconfig.json b/packages/integrations/node/tsconfig.json new file mode 100644 index 000000000..44baf375c --- /dev/null +++ b/packages/integrations/node/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "allowJs": true, + "module": "ES2020", + "outDir": "./dist", + "target": "ES2020" + } +} |