Skip to content

Commit

Permalink
Merge pull request #212 from sejori/example-architecture
Browse files Browse the repository at this point in the history
feat: cleaned preactSSR example
  • Loading branch information
sejori authored Jul 22, 2024
2 parents ceeecd8 + 335b2af commit e7951dc
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 121 deletions.
24 changes: 24 additions & 0 deletions example/preactSSR/handlers/github.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Handler, file } from "../../../mod.ts";

const base = `https://raw.githubusercontent.com/sejori/peko/main/example/preactSSR`;

export const githubHandler =
(path: string, type?: string): Handler =>
async (ctx) =>
(
await file(
ctx.state.env.ENVIRONMENT === "production"
? new URL(`${base}${path}`)
: new URL("../" + path, import.meta.url),
{
headers: new Headers({
...(type && { "Content-Type": type }),
// instruct browser to cache file in prod env
"Cache-Control":
ctx.state.env.ENVIRONMENT === "production"
? "max-age=86400, stale-while-revalidate=86400"
: "no-store",
}),
}
)
)(ctx);
24 changes: 24 additions & 0 deletions example/preactSSR/handlers/parrot.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Handler } from "../../../mod.ts";

export const parrotHandler: Handler = async (ctx) => {
const reader = ctx.request.body?.getReader();
let result = "";
const chunkSize = 1024;

if (reader) {
let done = false;
while (!done) {
const { value, done: chunkDone } = await reader.read();
if (value) {
result += new TextDecoder().decode(value);
if (result.length >= chunkSize) {
result = result.slice(0, chunkSize);
break;
}
}
done = chunkDone;
}
}

return new Response(`Parrot sqwarks: ${result}`);
};
32 changes: 32 additions & 0 deletions example/preactSSR/handlers/preact.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { renderToString } from "preact-render-to-string";
import { Handler, ssr } from "../../../mod.ts";
import htmlTemplate from "../src/document.ts";

export const preactHandler =
(
component: (props: Record<string, unknown>) => unknown,
title: string,
entrypoint: string
): Handler =>
(ctx) => {
return ssr(
() => {
const ssrHTML = renderToString(component(ctx.state), null, null);
return htmlTemplate({
title,
ssrHTML,
entrypoint,
serverState: ctx.state,
});
},
{
headers: new Headers({
// instruct browser to cache page in prod env
"Cache-Control":
ctx.state.env.ENVIRONMENT === "production"
? "max-age=86400, stale-while-revalidate=86400"
: "no-store",
}),
}
)(ctx);
};
12 changes: 12 additions & 0 deletions example/preactSSR/handlers/rdmEvent.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Handler, sse } from "../../../mod.ts";

const demoEventTarget = new EventTarget();
export const randomEventHandler: Handler = (ctx) => {
setInterval(() => {
demoEventTarget.dispatchEvent(
new CustomEvent("send", { detail: Math.random() })
);
}, 2500);

return sse(demoEventTarget)(ctx);
};
9 changes: 9 additions & 0 deletions example/preactSSR/middleware/reqTime.middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Middleware } from "../../../mod.ts";

export const reqTime: Middleware = (ctx) => {
ctx.state = {
env: ctx.state.env,
request_time: `${Date.now()}`,
DENO_REGION: ctx.state.env.DENO_REGION,
};
};
147 changes: 26 additions & 121 deletions example/preactSSR/router.ts
Original file line number Diff line number Diff line change
@@ -1,137 +1,42 @@
import {
Router,
RequestContext,
logger,
sse,
cacher,
ssr,
file,
} from "../../mod.ts"; //"https://deno.land/x/peko/mod.ts"
import { renderToString } from "preact-render-to-string";

import Home from "./src/pages/Home.ts";
import { Router, logger, cacher } from "../../mod.ts"; //"https://deno.land/x/peko/mod.ts"
import { preactHandler } from "./handlers/preact.handler.ts";
import { githubHandler } from "./handlers/github.handler.ts";
import { reqTime } from "./middleware/reqTime.middleware.ts";
import { randomEventHandler } from "./handlers/rdmEvent.handler.ts";
import { parrotHandler } from "./handlers/parrot.handler.ts";
import About from "./src/pages/About.ts";
import htmlTemplate from "./document.ts";
import Home from "./src/pages/Home.ts";

const router = new Router();
router.use(logger(console.log));

// SSR example, with cache bc static page
router.get("/", {
middleware: cacher(),
handler: (ctx) => {
return ssr(
() => {
const ssrHTML = renderToString(Home(), null, null);
return htmlTemplate({
title: "Peko",
ssrHTML,
entrypoint: "/src/pages/Home.ts",
});
},
{
headers: new Headers({
// instruct browser to cache page in prod env
"Cache-Control":
ctx.state.env.ENVIRONMENT === "production"
? "max-age=86400, stale-while-revalidate=86400"
: "no-store",
}),
}
)(ctx);
},
});
// SSR, with cache because static page
router.get("/", cacher(), preactHandler(Home, "Peko", "/src/pages/Home.ts"));

// SSR example, no cache because dynamic content
// (About page renders server state into HTML)
// SSR, no cache because dynamic content
router.get(
"/about",
(ctx) => {
ctx.state = {
request_time: `${Date.now()}`,
...ctx.state.env,
};
},
ssr((ctx) => {
const ssrHTML = renderToString(About(ctx.state), null, null);
return htmlTemplate({
title: "Peko | About",
ssrHTML,
entrypoint: "/src/pages/About.ts",
serverState: ctx.state,
});
})
reqTime,
preactHandler(About, "Peko | About", "/src/pages/About.ts")
);

// Static file example
// dynamic URL param for filename, always cache
router.get("/assets/:filename", cacher(), async (ctx) =>
(
await file(
new URL(
`https://raw.githubusercontent.com/sejori/peko/main/example/preactSSR/assets/${ctx.params.filename}`
),
{
headers: new Headers({
// instruct browser to cache file in prod env
"Cache-Control":
ctx.state.env.ENVIRONMENT === "production"
? "max-age=86400, stale-while-revalidate=86400"
: "no-store",
}),
}
)
)(ctx)
// Static, URL param for filename, always cache
router.get("/assets/:filename", cacher(), (ctx) =>
githubHandler(`/assets/${ctx.params.filename}`)(ctx)
);

// Return transformed source code example
// dynamic URL param for filename, always cache, transformed with esbuild at build time
router.get("/src/:dirname/:filename", cacher(), async (ctx) => {
const transformedFilename = ctx.params.filename.replace(".ts", ".js");
return (
await file(
ctx.state.env.ENVIRONMENT === "production"
? new URL(
`https://raw.githubusercontent.com/sejori/peko/main/example/preactSSR/dist/${ctx.params.dirname}/${transformedFilename}`
)
: new URL(
`./dist/${ctx.params.dirname}/${transformedFilename}`,
import.meta.url
),
{
headers: new Headers({
"Content-Type": "application/javascript",
// instruct browser to cache file in prod env
"Cache-Control":
ctx.state.env.ENVIRONMENT === "production"
? "max-age=86400, stale-while-revalidate=86400"
: "no-store",
}),
}
)
)(ctx);
});

// Server-sent events example
const demoEventTarget = new EventTarget();
router.get("/sse", (ctx: RequestContext) => {
setInterval(() => {
demoEventTarget.dispatchEvent(
new CustomEvent("send", { detail: Math.random() })
);
}, 2500);
// Transformed src at build-time with esbuild, always cache
router.get("/src/:dirname/:filename", cacher(), (ctx) =>
githubHandler(
`/dist/${ctx.params.dirname}/${ctx.params.filename.replace(".ts", ".js")}`,
"application/javascript"
)(ctx)
);

return sse(demoEventTarget)(ctx);
});
// Server-sent events demo
router.get("/sse", randomEventHandler);

// .addRoute example
router.addRoute({
path: "/api/parrot",
method: "POST",
handler: async (ctx: RequestContext) => {
const body = await ctx.request.text();
return new Response(`Parrot sqwarks: ${body}`);
},
});
// Basic
router.post("/parrot", parrotHandler);

export default router;
File renamed without changes.

0 comments on commit e7951dc

Please sign in to comment.