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:
commit
77e038ef52
5 changed files with 163 additions and 0 deletions
32
packages/integrations/node/package.json
Normal file
32
packages/integrations/node/package.json
Normal 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:*"
|
||||
}
|
||||
}
|
53
packages/integrations/node/readme.md
Normal file
53
packages/integrations/node/readme.md
Normal 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);
|
||||
```
|
20
packages/integrations/node/src/index.ts
Normal file
20
packages/integrations/node/src/index.ts
Normal 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());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
48
packages/integrations/node/src/server.ts
Normal file
48
packages/integrations/node/src/server.ts
Normal 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();
|
||||
}
|
10
packages/integrations/node/tsconfig.json
Normal file
10
packages/integrations/node/tsconfig.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"include": ["src"],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"module": "ES2020",
|
||||
"outDir": "./dist",
|
||||
"target": "ES2020"
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue