summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/middleware/astro.config.mjs13
-rw-r--r--examples/middleware/package.json23
-rw-r--r--examples/middleware/src/components/Card.astro63
-rw-r--r--examples/middleware/src/env.d.ts13
-rw-r--r--examples/middleware/src/layouts/Layout.astro35
-rw-r--r--examples/middleware/src/middleware.ts71
-rw-r--r--examples/middleware/src/pages/admin.astro55
-rw-r--r--examples/middleware/src/pages/api/login.ts18
-rw-r--r--examples/middleware/src/pages/index.astro63
-rw-r--r--examples/middleware/src/pages/login.astro75
-rw-r--r--examples/middleware/tsconfig.json3
11 files changed, 432 insertions, 0 deletions
diff --git a/examples/middleware/astro.config.mjs b/examples/middleware/astro.config.mjs
new file mode 100644
index 000000000..1d4662423
--- /dev/null
+++ b/examples/middleware/astro.config.mjs
@@ -0,0 +1,13 @@
+import { defineConfig } from 'astro/config';
+import node from '@astrojs/node';
+
+// https://astro.build/config
+export default defineConfig({
+ output: 'server',
+ adapter: node({
+ mode: 'standalone',
+ }),
+ experimental: {
+ middleware: true,
+ },
+});
diff --git a/examples/middleware/package.json b/examples/middleware/package.json
new file mode 100644
index 000000000..0a62e221e
--- /dev/null
+++ b/examples/middleware/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "@example/middleware",
+ "type": "module",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "dev": "astro dev",
+ "start": "astro dev",
+ "build": "astro build",
+ "preview": "astro preview",
+ "astro": "astro",
+ "server": "node dist/server/entry.mjs"
+ },
+ "dependencies": {
+ "astro": "workspace:*",
+ "svelte": "^3.48.0",
+ "@astrojs/node": "workspace:*",
+ "concurrently": "^7.2.1",
+ "unocss": "^0.15.6",
+ "vite-imagetools": "^4.0.4",
+ "html-minifier": "^4.0.0"
+ }
+}
diff --git a/examples/middleware/src/components/Card.astro b/examples/middleware/src/components/Card.astro
new file mode 100644
index 000000000..c68fa2ab3
--- /dev/null
+++ b/examples/middleware/src/components/Card.astro
@@ -0,0 +1,63 @@
+---
+export interface Props {
+ title: string;
+ body: string;
+ href: string;
+}
+
+const { href, title, body } = Astro.props;
+---
+
+<li class="link-card">
+ <a href={href}>
+ <h2>
+ {title}
+ <span>&rarr;</span>
+ </h2>
+ <p>
+ {body}
+ </p>
+ </a>
+</li>
+<style>
+ .link-card {
+ list-style: none;
+ display: flex;
+ padding: 0.25rem;
+ background-color: white;
+ background-image: none;
+ background-size: 400%;
+ border-radius: 0.6rem;
+ background-position: 100%;
+ transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
+ }
+
+ .link-card > a {
+ width: 100%;
+ text-decoration: none;
+ line-height: 1.4;
+ padding: 1rem 1.3rem;
+ border-radius: 0.35rem;
+ color: #111;
+ background-color: white;
+ opacity: 0.8;
+ }
+ h2 {
+ margin: 0;
+ font-size: 1.25rem;
+ transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
+ }
+ p {
+ margin-top: 0.5rem;
+ margin-bottom: 0;
+ color: #444;
+ }
+ .link-card:is(:hover, :focus-within) {
+ background-position: 0;
+ background-image: var(--accent-gradient);
+ }
+ .link-card:is(:hover, :focus-within) h2 {
+ color: rgb(var(--accent));
+ }
+</style>
diff --git a/examples/middleware/src/env.d.ts b/examples/middleware/src/env.d.ts
new file mode 100644
index 000000000..f2de6d45d
--- /dev/null
+++ b/examples/middleware/src/env.d.ts
@@ -0,0 +1,13 @@
+/// <reference types="astro/client" />
+declare global {
+ namespace AstroMiddleware {
+ interface Locals {
+ user: {
+ name: string;
+ surname: string;
+ };
+ }
+ }
+}
+
+export {};
diff --git a/examples/middleware/src/layouts/Layout.astro b/examples/middleware/src/layouts/Layout.astro
new file mode 100644
index 000000000..22100824e
--- /dev/null
+++ b/examples/middleware/src/layouts/Layout.astro
@@ -0,0 +1,35 @@
+---
+export interface Props {
+ title: string;
+}
+
+const { title } = Astro.props;
+---
+
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width" />
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
+ <meta name="generator" content={Astro.generator} />
+ <title>{title}</title>
+ </head>
+ <body>
+ <slot />
+ </body>
+</html>
+<style is:global>
+ :root {
+ --accent: 124, 58, 237;
+ --accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
+ }
+ html {
+ font-family: system-ui, sans-serif;
+ background-color: #f6f6f6;
+ }
+ code {
+ font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
+ Bitstream Vera Sans Mono, Courier New, monospace;
+ }
+</style>
diff --git a/examples/middleware/src/middleware.ts b/examples/middleware/src/middleware.ts
new file mode 100644
index 000000000..1c0bd855f
--- /dev/null
+++ b/examples/middleware/src/middleware.ts
@@ -0,0 +1,71 @@
+import { defineMiddleware, sequence } from 'astro/middleware';
+import htmlMinifier from 'html-minifier';
+
+const limit = 50;
+
+const loginInfo = {
+ token: undefined,
+ currentTime: undefined,
+};
+
+export const minifier = defineMiddleware(async (context, next) => {
+ const response = await next();
+ // check if the response is returning some HTML
+ if (response.headers.get('content-type') === 'text/html') {
+ let headers = response.headers;
+ let html = await response.text();
+ let newHtml = htmlMinifier.minify(html, {
+ removeAttributeQuotes: true,
+ collapseWhitespace: true,
+ });
+ return new Response(newHtml, {
+ status: 200,
+ headers,
+ });
+ }
+ return response;
+});
+
+const validation = defineMiddleware(async (context, next) => {
+ if (context.request.url.endsWith('/admin')) {
+ if (loginInfo.currentTime) {
+ const difference = new Date().getTime() - loginInfo.currentTime;
+ if (difference > limit) {
+ console.log('hit threshold');
+ loginInfo.token = undefined;
+ loginInfo.currentTime = undefined;
+ return context.redirect('/login');
+ }
+ }
+ // we naively check if we have a token
+ if (loginInfo.token && loginInfo.token === 'loggedIn') {
+ // we fill the locals with user-facing information
+ context.locals.user = {
+ name: 'AstroUser',
+ surname: 'AstroSurname',
+ };
+ return await next();
+ } else {
+ loginInfo.token = undefined;
+ loginInfo.currentTime = undefined;
+ return context.redirect('/login');
+ }
+ } else if (context.request.url.endsWith('/api/login')) {
+ const response = await next();
+ // the login endpoint will return to us a JSON with username and password
+ const data = await response.json();
+ // we naively check if username and password are equals to some string
+ if (data.username === 'astro' && data.password === 'astro') {
+ // we store the token somewhere outside of locals because the `locals` object is attached to the request
+ // and when doing a redirect, we lose that information
+ loginInfo.token = 'loggedIn';
+ loginInfo.currentTime = new Date().getTime();
+ return context.redirect('/admin');
+ }
+ }
+ // we don't really care about awaiting the response in this case
+ next();
+ return;
+});
+
+export const onRequest = sequence(validation, minifier);
diff --git a/examples/middleware/src/pages/admin.astro b/examples/middleware/src/pages/admin.astro
new file mode 100644
index 000000000..028fd6b08
--- /dev/null
+++ b/examples/middleware/src/pages/admin.astro
@@ -0,0 +1,55 @@
+---
+import Layout from '../layouts/Layout.astro';
+const user = Astro.locals.user;
+---
+
+<Layout title="Welcome back!!">
+ <main>
+ <h1>Welcome back <span class="text-gradient">{user.name} {user.surname}</span></h1>
+ </main>
+</Layout>
+
+<style>
+ main {
+ margin: auto;
+ padding: 1.5rem;
+ max-width: 60ch;
+ }
+ h1 {
+ font-size: 3rem;
+ font-weight: 800;
+ margin: 0;
+ }
+ .text-gradient {
+ background-image: var(--accent-gradient);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-size: 400%;
+ background-position: 0%;
+ }
+ .instructions {
+ line-height: 1.6;
+ margin: 1rem 0;
+ border: 1px solid rgba(var(--accent), 25%);
+ background-color: white;
+ padding: 1rem;
+ border-radius: 0.4rem;
+ }
+ .instructions code {
+ font-size: 0.875em;
+ font-weight: bold;
+ background: rgba(var(--accent), 12%);
+ color: rgb(var(--accent));
+ border-radius: 4px;
+ padding: 0.3em 0.45em;
+ }
+ .instructions strong {
+ color: rgb(var(--accent));
+ }
+ .link-card-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
+ gap: 1rem;
+ padding: 0;
+ }
+</style>
diff --git a/examples/middleware/src/pages/api/login.ts b/examples/middleware/src/pages/api/login.ts
new file mode 100644
index 000000000..fa3f7b59b
--- /dev/null
+++ b/examples/middleware/src/pages/api/login.ts
@@ -0,0 +1,18 @@
+import { APIRoute } from 'astro';
+
+export const post: APIRoute = async ({ request }) => {
+ const data = await request.formData();
+ const username = data.get('username');
+ const password = data.get('password');
+ return new Response(
+ JSON.stringify({
+ username,
+ password,
+ }),
+ {
+ headers: {
+ 'content-type': 'application/json',
+ },
+ }
+ );
+};
diff --git a/examples/middleware/src/pages/index.astro b/examples/middleware/src/pages/index.astro
new file mode 100644
index 000000000..ff77d4a15
--- /dev/null
+++ b/examples/middleware/src/pages/index.astro
@@ -0,0 +1,63 @@
+---
+import Layout from '../layouts/Layout.astro';
+import Card from '../components/Card.astro';
+---
+
+<Layout title="Welcome to Astro.">
+ <main>
+ <h1>Welcome to <span class="text-gradient">Astro</span></h1>
+ <p class="instructions">
+ To get started, open the directory <code>src/pages</code> in your project.<br />
+ <strong>Code Challenge:</strong> Tweak the "Welcome to Astro" message above.
+ </p>
+ {}
+ <ul role="list" class="link-card-grid">
+ <Card href="/login" title="Login" body="Try the login" />
+ </ul>
+ </main>
+</Layout>
+
+<style>
+ main {
+ margin: auto;
+ padding: 1.5rem;
+ max-width: 60ch;
+ }
+ h1 {
+ font-size: 3rem;
+ font-weight: 800;
+ margin: 0;
+ }
+ .text-gradient {
+ background-image: var(--accent-gradient);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-size: 400%;
+ background-position: 0%;
+ }
+ .instructions {
+ line-height: 1.6;
+ margin: 1rem 0;
+ border: 1px solid rgba(var(--accent), 25%);
+ background-color: white;
+ padding: 1rem;
+ border-radius: 0.4rem;
+ }
+ .instructions code {
+ font-size: 0.875em;
+ font-weight: bold;
+ background: rgba(var(--accent), 12%);
+ color: rgb(var(--accent));
+ border-radius: 4px;
+ padding: 0.3em 0.45em;
+ }
+ .instructions strong {
+ color: rgb(var(--accent));
+ }
+ .link-card-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
+ gap: 1rem;
+ padding: 0;
+ }
+</style>
diff --git a/examples/middleware/src/pages/login.astro b/examples/middleware/src/pages/login.astro
new file mode 100644
index 000000000..99cf4cc94
--- /dev/null
+++ b/examples/middleware/src/pages/login.astro
@@ -0,0 +1,75 @@
+---
+import Layout from '../layouts/Layout.astro';
+
+const status = Astro.response.status;
+let redirectMessage;
+if (status === 301) {
+ redirectMessage = 'Your session is finished, please login again';
+}
+---
+
+<Layout title="Welcome to Astro.">
+ <main>
+ <h1>Welcome to <span class="text-gradient">Astro</span></h1>
+ <p class="instructions">
+ To get started, open the directory <code>src/pages</code> in your project.<br />
+ <strong>Code Challenge:</strong> Tweak the "Welcome to Astro" message above.
+ </p>
+ {redirectMessage}
+ <form action="/api/login" method="POST">
+ <label>
+ Username: <input type="text" minlength="1" id="username" name="username" />
+ </label>
+ <label>
+ Password: <input type="password" minlength="1" id="password" name="password" />
+ </label>
+
+ <button>Submit</button>
+ </form>
+ </main>
+</Layout>
+
+<style>
+ main {
+ margin: auto;
+ padding: 1.5rem;
+ max-width: 60ch;
+ }
+ h1 {
+ font-size: 3rem;
+ font-weight: 800;
+ margin: 0;
+ }
+ .text-gradient {
+ background-image: var(--accent-gradient);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-size: 400%;
+ background-position: 0%;
+ }
+ .instructions {
+ line-height: 1.6;
+ margin: 1rem 0;
+ border: 1px solid rgba(var(--accent), 25%);
+ background-color: white;
+ padding: 1rem;
+ border-radius: 0.4rem;
+ }
+ .instructions code {
+ font-size: 0.875em;
+ font-weight: bold;
+ background: rgba(var(--accent), 12%);
+ color: rgb(var(--accent));
+ border-radius: 4px;
+ padding: 0.3em 0.45em;
+ }
+ .instructions strong {
+ color: rgb(var(--accent));
+ }
+ .link-card-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
+ gap: 1rem;
+ padding: 0;
+ }
+</style>
diff --git a/examples/middleware/tsconfig.json b/examples/middleware/tsconfig.json
new file mode 100644
index 000000000..d78f81ec4
--- /dev/null
+++ b/examples/middleware/tsconfig.json
@@ -0,0 +1,3 @@
+{
+ "extends": "astro/tsconfigs/base"
+}