summaryrefslogtreecommitdiff
path: root/examples/ssr/src
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2022-03-16 12:16:21 -0400
committerGravatar GitHub <noreply@github.com> 2022-03-16 12:16:21 -0400
commit4c25a1c2eacf897427a7d6dac3bf476ef56799de (patch)
treedb1d341557694e17a07027ebea160c89bad4813d /examples/ssr/src
parent8f13b3d4068f0f017186fbc2dbd33a1427768ea4 (diff)
downloadastro-4c25a1c2eacf897427a7d6dac3bf476ef56799de.tar.gz
astro-4c25a1c2eacf897427a7d6dac3bf476ef56799de.tar.zst
astro-4c25a1c2eacf897427a7d6dac3bf476ef56799de.zip
Implements redirects, headers for SSR (#2798)
* Implements redirects, headers for SSR * Move away from an explicit Request * Properly handle endpoint routes in the build * chore(lint): ESLint fix * Update based on review comments Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Diffstat (limited to 'examples/ssr/src')
-rw-r--r--examples/ssr/src/api.ts51
-rw-r--r--examples/ssr/src/components/AddToCart.svelte9
-rw-r--r--examples/ssr/src/components/Cart.svelte6
-rw-r--r--examples/ssr/src/components/Header.astro20
-rw-r--r--examples/ssr/src/models/user.ts8
-rw-r--r--examples/ssr/src/pages/cart.astro47
-rw-r--r--examples/ssr/src/pages/login.astro30
-rw-r--r--examples/ssr/src/pages/login.form.js10
-rw-r--r--examples/ssr/src/pages/products/[id].astro2
9 files changed, 174 insertions, 9 deletions
diff --git a/examples/ssr/src/api.ts b/examples/ssr/src/api.ts
index 59619ade6..b71990f3f 100644
--- a/examples/ssr/src/api.ts
+++ b/examples/ssr/src/api.ts
@@ -5,12 +5,25 @@ interface Product {
image: string;
}
-//let origin: string;
-const { mode } = import.meta.env;
-const origin = mode === 'develepment' ? `http://localhost:3000` : `http://localhost:8085`;
+interface User {
+ id: number;
+}
+
+interface Cart {
+ items: Array<{
+ id: number;
+ name: string;
+ count: number;
+ }>;
+}
+
+const { MODE } = import.meta.env;
+const origin = MODE === 'development' ? `http://127.0.0.1:3000` : `http://127.0.0.1:8085`;
async function get<T>(endpoint: string, cb: (response: Response) => Promise<T>): Promise<T> {
- const response = await fetch(`${origin}${endpoint}`);
+ const response = await fetch(`${origin}${endpoint}`, {
+ credentials: 'same-origin'
+ });
if (!response.ok) {
// TODO make this better...
return null;
@@ -31,3 +44,33 @@ export async function getProduct(id: number): Promise<Product> {
return product;
});
}
+
+export async function getUser(): Promise<User> {
+ return get<User>(`/api/user`, async response => {
+ const user: User = await response.json();
+ return user;
+ });
+}
+
+export async function getCart(): Promise<Cart> {
+ return get<Cart>(`/api/cart`, async response => {
+ const cart: Cart = await response.json();
+ return cart;
+ });
+}
+
+export async function addToUserCart(id: number | string, name: string): Promise<void> {
+ await fetch(`${origin}/api/add-to-cart`, {
+ credentials: 'same-origin',
+ method: 'POST',
+ mode: 'no-cors',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Cache': 'no-cache'
+ },
+ body: JSON.stringify({
+ id,
+ name
+ })
+ });
+}
diff --git a/examples/ssr/src/components/AddToCart.svelte b/examples/ssr/src/components/AddToCart.svelte
index b03b8180a..0f7a97a93 100644
--- a/examples/ssr/src/components/AddToCart.svelte
+++ b/examples/ssr/src/components/AddToCart.svelte
@@ -1,11 +1,18 @@
<script>
+ import { addToUserCart } from '../api';
export let id = 0;
+ export let name = '';
- function addToCart() {
+ function notifyCartItem(id) {
window.dispatchEvent(new CustomEvent('add-to-cart', {
detail: id
}));
}
+
+ async function addToCart() {
+ await addToUserCart(id, name);
+ notifyCartItem(id);
+ }
</script>
<style>
button {
diff --git a/examples/ssr/src/components/Cart.svelte b/examples/ssr/src/components/Cart.svelte
index 63dd1b5a5..74db0bc79 100644
--- a/examples/ssr/src/components/Cart.svelte
+++ b/examples/ssr/src/components/Cart.svelte
@@ -12,6 +12,8 @@
.cart {
display: flex;
align-items: center;
+ text-decoration: none;
+ color: inherit;
}
.cart :first-child {
margin-right: 5px;
@@ -26,7 +28,7 @@
}
</style>
<svelte:window on:add-to-cart={onAddToCart}/>
-<div class="cart">
+<a href="/cart" class="cart">
<span class="material-icons cart-icon">shopping_cart</span>
<span class="count">{count}</span>
-</div>
+</a>
diff --git a/examples/ssr/src/components/Header.astro b/examples/ssr/src/components/Header.astro
index 2839c70d3..c4d925a5f 100644
--- a/examples/ssr/src/components/Header.astro
+++ b/examples/ssr/src/components/Header.astro
@@ -1,6 +1,10 @@
---
import TextDecorationSkip from './TextDecorationSkip.astro';
import Cart from './Cart.svelte';
+import { getCart } from '../api';
+
+const cart = await getCart();
+const cartCount = cart.items.reduce((sum, item) => sum + item.count, 0);
---
<style>
@import url('https://fonts.googleapis.com/css2?family=Lobster&display=swap');
@@ -21,11 +25,25 @@ import Cart from './Cart.svelte';
color: inherit;
text-decoration: none;
}
+
+ .right-pane {
+ display: flex;
+ }
+
+ .material-icons {
+ font-size: 36px;
+ margin-right: 1rem;
+ }
</style>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<header>
<h1><a href="/"><TextDecorationSkip text="Online Store" /></a></h1>
<div class="right-pane">
- <Cart client:idle />
+ <a href="/login">
+ <span class="material-icons">
+ login
+ </span>
+ </a>
+ <Cart client:idle count={cartCount} />
</div>
</header>
diff --git a/examples/ssr/src/models/user.ts b/examples/ssr/src/models/user.ts
new file mode 100644
index 000000000..ecd839d46
--- /dev/null
+++ b/examples/ssr/src/models/user.ts
@@ -0,0 +1,8 @@
+import lightcookie from 'lightcookie';
+
+
+export function isLoggedIn(request: Request): boolean {
+ const cookie = request.headers.get('cookie');
+ const parsed = lightcookie.parse(cookie);
+ return 'user-id' in parsed;
+}
diff --git a/examples/ssr/src/pages/cart.astro b/examples/ssr/src/pages/cart.astro
new file mode 100644
index 000000000..e4a00183e
--- /dev/null
+++ b/examples/ssr/src/pages/cart.astro
@@ -0,0 +1,47 @@
+---
+import Header from '../components/Header.astro';
+import Container from '../components/Container.astro';
+import { getCart } from '../api';
+import { isLoggedIn } from '../models/user';
+
+if(!isLoggedIn(Astro.request)) {
+ return Astro.redirect('/');
+}
+
+// They must be logged in.
+
+const user = { name: 'test'}; // getUser?
+const cart = await getCart();
+---
+<html>
+<head>
+ <title>Cart | Online Store</title>
+ <style>
+ h1 {
+ font-size: 36px;
+ }
+ </style>
+</head>
+<body>
+ <Header />
+
+ <Container tag="main">
+ <h1>Cart</h1>
+ <p>Hi { user.name }! Here are your cart items:</p>
+ <table>
+ <thead>
+ <tr>
+ <th>Item</th>
+ <th>Count</th>
+ </tr>
+ </thead>
+ <tbody>
+ {cart.items.map(item => <tr>
+ <td>{item.name}</td>
+ <td>{item.count}</td>
+ </tr>)}
+ </tbody>
+ </table>
+ </Container>
+</body>
+</html>
diff --git a/examples/ssr/src/pages/login.astro b/examples/ssr/src/pages/login.astro
new file mode 100644
index 000000000..b12a82a5e
--- /dev/null
+++ b/examples/ssr/src/pages/login.astro
@@ -0,0 +1,30 @@
+---
+import Header from '../components/Header.astro';
+import Container from '../components/Container.astro';
+---
+<html>
+<head>
+ <title>Online Store</title>
+ <style>
+ h1 {
+ font-size: 36px;
+ }
+ </style>
+</head>
+<body>
+ <Header />
+
+ <Container tag="main">
+ <h1>Login</h1>
+ <form action="/login.form" method="POST">
+ <label for="name">Name</label>
+ <input type="text" name="name">
+
+ <label for="password">Password</label>
+ <input type="password" name="password">
+
+ <input type="submit" value="Submit">
+ </form>
+ </Container>
+</body>
+</html>
diff --git a/examples/ssr/src/pages/login.form.js b/examples/ssr/src/pages/login.form.js
new file mode 100644
index 000000000..9875ae160
--- /dev/null
+++ b/examples/ssr/src/pages/login.form.js
@@ -0,0 +1,10 @@
+
+export function post(params, request) {
+ return new Response(null, {
+ status: 301,
+ headers: {
+ 'Location': '/',
+ 'Set-Cookie': 'user-id=1; Path=/; Max-Age=2592000'
+ }
+ });
+}
diff --git a/examples/ssr/src/pages/products/[id].astro b/examples/ssr/src/pages/products/[id].astro
index 943f2ab84..9c400c2f1 100644
--- a/examples/ssr/src/pages/products/[id].astro
+++ b/examples/ssr/src/pages/products/[id].astro
@@ -45,7 +45,7 @@ const product = await getProduct(id);
<figure>
<img src={product.image} />
<figcaption>
- <AddToCart id={id} client:idle />
+ <AddToCart client:idle id={id} name={product.name} />
<p>Description here...</p>
</figcaption>
</figure>