0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-03-10 23:01:26 -05:00

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
This commit is contained in:
Matthew Phillips 2022-03-24 07:26:25 -04:00 committed by GitHub
commit 77e038ef52
5 changed files with 163 additions and 0 deletions

View file

@ -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:*"
}
}

View file

@ -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);
```

View file

@ -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());
}
}
};
}

View file

@ -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();
}

View file

@ -0,0 +1,10 @@
{
"extends": "../../../tsconfig.base.json",
"include": ["src"],
"compilerOptions": {
"allowJs": true,
"module": "ES2020",
"outDir": "./dist",
"target": "ES2020"
}
}