summaryrefslogtreecommitdiff
path: root/packages/integrations
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2022-03-24 07:26:25 -0400
committerGravatar GitHub <noreply@github.com> 2022-03-24 07:26:25 -0400
commit5e52814d97a5723dbe7ebb32fbe040a7a4c0ea77 (patch)
treeb4cd5790933ad9829159314191487462bd5e9d2e /packages/integrations
parent5c96145527f9480e7b7b16b599f4b2091e41aa6c (diff)
downloadastro-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.json32
-rw-r--r--packages/integrations/node/readme.md53
-rw-r--r--packages/integrations/node/src/index.ts20
-rw-r--r--packages/integrations/node/src/server.ts48
-rw-r--r--packages/integrations/node/tsconfig.json10
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"
+ }
+}