mirror of
https://github.com/withastro/astro.git
synced 2025-03-10 23:01:26 -05:00
Drop Node 14 support (#5782)
* chore: Update engines field * fix(deps): Remove node-fetch * feat(polyfills): Remove node-fetch for undici * feat(webapi): Remove node-fetch from the webapis polyfills for undici * feat(core): Remove node-fetch for undici in Astro core * feat(telemetry): Remove node-fetch for undici * feat(node): Remove node-fetch for undici in node integration * feat(vercel): Remove node-fetch for undici in Vercel integration * chore: update lockfile * chore: update lockfile * chore: changeset * fix(set): Fix set directives not streaming correctly on Node 16 * Try another approach * Debugging * Debug fetch * Use global fetch if there is one * changeset for lit * Remove web-streams-polyfill * Remove web-streams-polyfill license note * Update .changeset/stupid-wolves-explain.md Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com> Co-authored-by: Matthew Phillips <matthew@skypack.dev> Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
This commit is contained in:
parent
d72625fb3d
commit
a2cb72deb8
3 changed files with 1 additions and 121 deletions
|
@ -3,21 +3,12 @@ import type { SSRManifest } from 'astro';
|
|||
import { App } from 'astro/app';
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||
|
||||
import * as requestTransformLegacy from './request-transform/legacy.js';
|
||||
import * as requestTransformNode18 from './request-transform/node18.js';
|
||||
import { getRequest, setResponse } from './request-transform';
|
||||
|
||||
polyfill(globalThis, {
|
||||
exclude: 'window document',
|
||||
});
|
||||
|
||||
// Node 18+ has a new API for request/response, while older versions use node-fetch
|
||||
// When we drop support for Node 14, we can remove the legacy code by switching to undici
|
||||
|
||||
const nodeVersion = parseInt(process.version.split('.')[0].slice(1)); // 'v14.17.0' -> 14
|
||||
|
||||
const { getRequest, setResponse } =
|
||||
nodeVersion >= 18 ? requestTransformNode18 : requestTransformLegacy;
|
||||
|
||||
export const createExports = (manifest: SSRManifest) => {
|
||||
const app = new App(manifest);
|
||||
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
import type { App } from 'astro/app';
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||
import { Readable } from 'node:stream';
|
||||
|
||||
const clientAddressSymbol = Symbol.for('astro.clientAddress');
|
||||
|
||||
/*
|
||||
Credits to the SvelteKit team
|
||||
https://github.com/sveltejs/kit/blob/69913e9fda054fa6a62a80e2bb4ee7dca1005796/packages/kit/src/node.js
|
||||
*/
|
||||
|
||||
function get_raw_body(req: IncomingMessage) {
|
||||
return new Promise<Uint8Array | null>((fulfil, reject) => {
|
||||
const h = req.headers;
|
||||
|
||||
if (!h['content-type']) {
|
||||
return fulfil(null);
|
||||
}
|
||||
|
||||
req.on('error', reject);
|
||||
|
||||
const length = Number(h['content-length']);
|
||||
|
||||
// https://github.com/jshttp/type-is/blob/c1f4388c71c8a01f79934e68f630ca4a15fffcd6/index.js#L81-L95
|
||||
if (isNaN(length) && h['transfer-encoding'] == null) {
|
||||
return fulfil(null);
|
||||
}
|
||||
|
||||
let data = new Uint8Array(length || 0);
|
||||
|
||||
if (length > 0) {
|
||||
let offset = 0;
|
||||
req.on('data', (chunk) => {
|
||||
const new_len = offset + Buffer.byteLength(chunk);
|
||||
|
||||
if (new_len > length) {
|
||||
return reject({
|
||||
status: 413,
|
||||
reason: 'Exceeded "Content-Length" limit',
|
||||
});
|
||||
}
|
||||
|
||||
data.set(chunk, offset);
|
||||
offset = new_len;
|
||||
});
|
||||
} else {
|
||||
req.on('data', (chunk) => {
|
||||
const new_data = new Uint8Array(data.length + chunk.length);
|
||||
new_data.set(data, 0);
|
||||
new_data.set(chunk, data.length);
|
||||
data = new_data;
|
||||
});
|
||||
}
|
||||
|
||||
req.on('end', () => {
|
||||
fulfil(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function getRequest(base: string, req: IncomingMessage): Promise<Request> {
|
||||
let headers = req.headers as Record<string, string>;
|
||||
if (req.httpVersionMajor === 2) {
|
||||
// we need to strip out the HTTP/2 pseudo-headers because node-fetch's
|
||||
// Request implementation doesn't like them
|
||||
headers = Object.assign({}, headers);
|
||||
delete headers[':method'];
|
||||
delete headers[':path'];
|
||||
delete headers[':authority'];
|
||||
delete headers[':scheme'];
|
||||
}
|
||||
const request = new Request(base + req.url, {
|
||||
method: req.method,
|
||||
headers,
|
||||
body: await get_raw_body(req), // TODO stream rather than buffer
|
||||
});
|
||||
Reflect.set(request, clientAddressSymbol, headers['x-forwarded-for']);
|
||||
return request;
|
||||
}
|
||||
|
||||
export async function setResponse(
|
||||
app: App,
|
||||
res: ServerResponse,
|
||||
response: Response
|
||||
): Promise<void> {
|
||||
const headers = Object.fromEntries(response.headers);
|
||||
|
||||
if (response.headers.has('set-cookie')) {
|
||||
// @ts-expect-error (headers.raw() is non-standard)
|
||||
headers['set-cookie'] = response.headers.raw()['set-cookie'];
|
||||
}
|
||||
|
||||
if (app.setCookieHeaders) {
|
||||
const setCookieHeaders: Array<string> = Array.from(app.setCookieHeaders(response));
|
||||
if (setCookieHeaders.length) {
|
||||
res.setHeader('Set-Cookie', setCookieHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
res.writeHead(response.status, headers);
|
||||
|
||||
if (response.body instanceof Readable) {
|
||||
response.body.pipe(res);
|
||||
} else {
|
||||
if (response.body) {
|
||||
res.write(await response.arrayBuffer());
|
||||
}
|
||||
|
||||
res.end();
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue