0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

Make it deployable to Netlify

This commit is contained in:
Matthew Phillips 2022-03-25 11:02:26 -04:00
parent 8e2cae4990
commit 1771f1cb12
16 changed files with 120 additions and 158 deletions

View file

@ -6,17 +6,4 @@ import nodejs from '@astrojs/node';
export default defineConfig({
adapter: nodejs(),
integrations: [svelte()],
vite: {
server: {
cors: {
credentials: true,
},
proxy: {
'/api': {
target: 'http://127.0.0.1:8085',
changeOrigin: true,
},
},
},
},
});

View file

@ -3,9 +3,7 @@
"version": "0.0.1",
"private": true,
"scripts": {
"dev-api": "node server/dev-api.mjs",
"dev-server": "astro dev --experimental-ssr",
"dev": "concurrently \"npm run dev-api\" \"astro dev --experimental-ssr\"",
"dev": "astro dev --experimental-ssr",
"start": "astro dev",
"build": "astro build --experimental-ssr",
"server": "node server/server.mjs"

View file

@ -1,100 +0,0 @@
import fs from 'fs';
import lightcookie from 'lightcookie';
const dbJSON = fs.readFileSync(new URL('./db.json', import.meta.url));
const db = JSON.parse(dbJSON);
const products = db.products;
const productMap = new Map(products.map((product) => [product.id, product]));
// Normally this would be in a database.
const userCartItems = new Map();
const routes = [
{
match: /\/api\/products\/([0-9])+/,
async handle(_req, res, [, idStr]) {
const id = Number(idStr);
if (productMap.has(id)) {
const product = productMap.get(id);
res.writeHead(200, {
'Content-Type': 'application/json',
});
res.end(JSON.stringify(product));
} else {
res.writeHead(404, {
'Content-Type': 'text/plain',
});
res.end('Not found');
}
},
},
{
match: /\/api\/products/,
async handle(_req, res) {
res.writeHead(200, {
'Content-Type': 'application/json',
});
res.end(JSON.stringify(products));
},
},
{
match: /\/api\/cart/,
async handle(req, res) {
res.writeHead(200, {
'Content-Type': 'application/json',
});
let cookie = req.headers.cookie;
let userId = cookie ? lightcookie.parse(cookie)['user-id'] : '1'; // default for testing
if (!userId || !userCartItems.has(userId)) {
res.end(JSON.stringify({ items: [] }));
return;
}
let items = userCartItems.get(userId);
let array = Array.from(items.values());
res.end(JSON.stringify({ items: array }));
},
},
{
match: /\/api\/add-to-cart/,
async handle(req, res) {
let body = '';
req.on('data', (chunk) => (body += chunk));
return new Promise((resolve) => {
req.on('end', () => {
let cookie = req.headers.cookie;
let userId = lightcookie.parse(cookie)['user-id'];
let msg = JSON.parse(body);
if (!userCartItems.has(userId)) {
userCartItems.set(userId, new Map());
}
let cart = userCartItems.get(userId);
if (cart.has(msg.id)) {
cart.get(msg.id).count++;
} else {
cart.set(msg.id, { id: msg.id, name: msg.name, count: 1 });
}
res.writeHead(200, {
'Content-Type': 'application/json',
});
res.end(JSON.stringify({ ok: true }));
});
});
},
},
];
export async function apiHandler(req, res) {
for (const route of routes) {
const match = route.match.exec(req.url);
if (match) {
return route.handle(req, res, match);
}
}
res.writeHead(404, {
'Content-Type': 'text/plain',
});
res.end('Not found');
}

View file

@ -1,17 +0,0 @@
import { createServer } from 'http';
import { apiHandler } from './api.mjs';
const PORT = process.env.PORT || 8085;
const server = createServer((req, res) => {
apiHandler(req, res).catch((err) => {
console.error(err);
res.writeHead(500, {
'Content-Type': 'text/plain',
});
res.end(err.toString());
});
});
server.listen(PORT);
console.log(`API running at http://localhost:${PORT}`);

View file

@ -1,29 +1,28 @@
import { createServer } from 'http';
import fs from 'fs';
import mime from 'mime';
import { apiHandler } from './api.mjs';
import { handler as ssrHandler } from '../dist/server/entry.mjs';
const clientRoot = new URL('../dist/client/', import.meta.url);
async function handle(req, res) {
ssrHandler(req, res, async () => {
// Did not match an SSR route
ssrHandler(req, res, async (err) => {
if(err) {
res.writeHead(500);
res.end(err.stack)
return;
}
if (/^\/api\//.test(req.url)) {
return apiHandler(req, res);
} else {
let local = new URL('.' + req.url, clientRoot);
try {
const data = await fs.promises.readFile(local);
res.writeHead(200, {
'Content-Type': mime.getType(req.url),
});
res.end(data);
} catch {
res.writeHead(404);
res.end();
}
let local = new URL('.' + req.url, clientRoot);
try {
const data = await fs.promises.readFile(local);
res.writeHead(200, {
'Content-Type': mime.getType(req.url),
});
res.end(data);
} catch {
res.writeHead(404);
res.end();
}
});
}

View file

@ -60,7 +60,7 @@ export async function getCart(): Promise<Cart> {
}
export async function addToUserCart(id: number | string, name: string): Promise<void> {
await fetch(`${origin}/api/add-to-cart`, {
await fetch(`${origin}/api/cart`, {
credentials: 'same-origin',
method: 'POST',
mode: 'no-cors',

View file

@ -0,0 +1,9 @@
import db from './db.json';
const products = db.products;
const productMap = new Map(products.map((product) => [product.id, product]));
export {
products,
productMap
};

View file

@ -0,0 +1,3 @@
// Normally this would be in a database.
export const userCartItems = new Map();

View file

@ -0,0 +1,47 @@
import lightcookie from 'lightcookie';
import { userCartItems } from '../../models/session';
export function get(_params: any, request: Request) {
let cookie = request.headers.get('cookie');
let userId = cookie ? lightcookie.parse(cookie)['user-id'] : '1'; // default for testing
if (!userId || !userCartItems.has(userId)) {
return {
body: JSON.stringify({ items: [] })
};
}
let items = userCartItems.get(userId);
let array = Array.from(items.values());
return {
body: JSON.stringify({ items: array })
}
}
interface AddToCartItem {
id: number;
name: string;
}
export async function post(_params: any, request: Request) {
const item: AddToCartItem = await request.json();
let cookie = request.headers.get('cookie');
let userId = lightcookie.parse(cookie)['user-id'];
if (!userCartItems.has(userId)) {
userCartItems.set(userId, new Map());
}
let cart = userCartItems.get(userId);
if (cart.has(item.id)) {
cart.get(item.id).count++;
} else {
cart.set(item.id, { id: item.id, name: item.name, count: 1 });
}
return {
body: JSON.stringify({
ok: true
})
};
}

View file

@ -0,0 +1,7 @@
import { products } from '../../models/db';
export function get() {
return {
body: JSON.stringify(products)
};
}

View file

@ -0,0 +1,17 @@
import { productMap } from '../../../models/db';
export function get({ id: idStr }) {
const id = Number(idStr);
if (productMap.has(id)) {
const product = productMap.get(id);
return {
body: JSON.stringify(product)
};
} else {
return new Response(null, {
status: 400,
statusText: 'Not found'
});
}
}

View file

@ -3,6 +3,7 @@
"lib": ["ES2015", "DOM"],
"module": "ES2022",
"moduleResolution": "node",
"resolveJsonModule": true,
"types": ["astro/env"]
}
}

View file

@ -71,8 +71,7 @@ export class App {
routeCache: this.#routeCache,
site: this.#manifest.site,
ssr: true,
method: info.routeData.type === 'endpoint' ? '' : 'GET',
headers: request.headers,
request,
});
if (result.type === 'response') {

View file

@ -1,14 +1,17 @@
import type { IncomingHttpHeaders } from 'http';
type HeaderType = Headers | Record<string, any> | IncomingHttpHeaders;
type RequestBody = ArrayBuffer | Blob | ReadableStream | URLSearchParams | FormData;
export function createRequest(url: URL | string, headers: HeaderType, method: string = 'GET'): Request {
export function createRequest(url: URL | string, headers: HeaderType,
method: string = 'GET', body: RequestBody | undefined = undefined): Request {
let headersObj = headers instanceof Headers ? headers :
new Headers(Object.entries(headers as Record<string, any>));
const request = new Request(url.toString(), {
method: method,
headers: headersObj
headers: headersObj,
body
});
Object.defineProperties(request, {
@ -26,7 +29,5 @@ export function createRequest(url: URL | string, headers: HeaderType, method: st
}
});
// TODO warn
return request;
}

View file

@ -128,8 +128,19 @@ async function handleRequest(
}
}
let body: ArrayBuffer | undefined = undefined;
if(!(req.method === 'GET' || req.method === 'HEAD')) {
let bytes: string[] = [];
await new Promise(resolve => {
req.setEncoding('utf-8');
req.on('data', bts => bytes.push(bts));
req.on('close', resolve);
});
body = new TextEncoder().encode(bytes.join('')).buffer;
}
// Headers are only available when using SSR.
const request = createRequest(url, buildingToSSR ? req.headers : new Headers(), req.method);
const request = createRequest(url, buildingToSSR ? req.headers : new Headers(), req.method, body);
try {
if (!pathname.startsWith(devRoot)) {