Skip to content

Commit

Permalink
🏗️ Using Fresh instead of Express
Browse files Browse the repository at this point in the history
  • Loading branch information
toridoriv committed Oct 16, 2023
1 parent 4837ffc commit 62f2322
Show file tree
Hide file tree
Showing 27 changed files with 401 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"[javascript][json][jsonc][typescript]": {
"[javascript][typescriptreact][json][jsonc][typescript]": {
"editor.defaultFormatter": "denoland.vscode-deno"
},
"[html]": {
Expand Down
2 changes: 2 additions & 0 deletions bin/commands/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ function getDependencyFiles(isDevelopment: boolean) {
match: [
/deps\./,
new RegExp("express-serve-static-core.d.ts"),
new RegExp("dev.ts"),
new RegExp("^main.ts"),
],
skip,
};
Expand Down
1 change: 1 addition & 0 deletions components/deps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { type JSX } from "preact";
19 changes: 19 additions & 0 deletions components/head.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { JSX } from "@components/deps.ts";

export function Favicon(props: JSX.HTMLAttributes<HTMLLinkElement>) {
return <link rel="icon" {...props} />;
}

export function PreloadedStylesheet(
props: JSX.HTMLAttributes<HTMLLinkElement>,
) {
return (
<link
as="style"
rel="preload"
// @ts-ignore: ¯\_(ツ)_/¯
onload="this.onload=null;this.rel='stylesheet'"
{...props}
/>
);
}
37 changes: 37 additions & 0 deletions components/nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { JSX } from "./deps.ts";

export function NavItem(
{ children, ...props }: JSX.HTMLAttributes<HTMLAnchorElement>,
) {
return (
<li class="nav-item">
<a className="nav-link" {...props}>{children}</a>
</li>
);
}

export function Nav(props: JSX.HTMLAttributes<HTMLAnchorElement>[]) {
return (
<nav
class="navbar navbar-expand-lg"
style="background-color: var(--bs-content-bg)"
>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbar-collapse-7"
aria-controls="navbar-collapse-7"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbar-collapse-7">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
{props.map(NavItem)}
</ul>
</div>
</nav>
);
}
13 changes: 12 additions & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"compilerOptions": {
"exactOptionalPropertyTypes": true,
"jsx": "react-jsx",
"jsxImportSource": "preact",
"noImplicitThis": true,
"strictNullChecks": true
},
Expand All @@ -16,7 +18,16 @@
"useTabs": false
},
"imports": {
"@modules/": "./modules/"
"$fresh/": "https://deno.land/x/fresh@1.5.2/",
"@components/": "./components/",
"@islands/": "./islands/",
"@modules/": "./modules/",
"@preact/signals": "https://esm.sh/*@preact/signals@1.2.1",
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.0",
"@routes/": "./routes/",
"preact": "https://esm.sh/preact@10.18.1",
"preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.2.2",
"preact/": "https://esm.sh/preact@10.18.1/"
},
"lint": {
"exclude": [
Expand Down
5 changes: 5 additions & 0 deletions dev.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import "https://deno.land/std@0.204.0/dotenv/load.ts";
import dev from "$fresh/dev.ts";
import config from "./fresh.config.ts";

await dev(import.meta.url, "./main.ts", config);
7 changes: 7 additions & 0 deletions fresh.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from "$fresh/server.ts";

export default defineConfig({
server: {
port: 3000,
},
});
17 changes: 17 additions & 0 deletions fresh.gen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// DO NOT EDIT. This file is generated by Fresh.
// This file SHOULD be checked into source version control.
// This file is automatically updated during development when running `dev.ts`.

import * as $0 from "./routes/_app.tsx";
import * as $1 from "./routes/index.tsx";

const manifest = {
routes: {
"./routes/_app.tsx": $0,
"./routes/index.tsx": $1,
},
islands: {},
baseUrl: import.meta.url,
};

export default manifest;
9 changes: 9 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/// <reference no-default-lib="true" />
/// <reference lib="dom" />
/// <reference lib="dom.iterable" />
/// <reference lib="dom.asynciterable" />
/// <reference lib="deno.ns" />

import "https://deno.land/std@0.204.0/dotenv/load.ts";

import { start } from "https://deno.land/x/fresh@1.5.1/server.ts";
1 change: 1 addition & 0 deletions modules/config/deps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { z } from "https://deno.land/x/zod@v3.22.4/mod.ts";
11 changes: 11 additions & 0 deletions modules/config/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {
EnvironmentSchema,
PackageJsonSchema,
} from "@modules/config/schemas.ts";
import PackageJson from "../../package.json" assert { type: "json" };

const env = EnvironmentSchema.parse(Deno.env.toObject());

const packageJson = PackageJsonSchema.parse(PackageJson);

export default { ...env, ...packageJson };
54 changes: 54 additions & 0 deletions modules/config/schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { z } from "@modules/config/deps.ts";

const UrlSchema = z.string().url();
const EmailSchema = z.string().email();
const NotEmptyStringSchema = z.string().min(1);

export const EnvironmentSchema = z.object({
ENVIRONMENT: z
.preprocess(toUpperCase, z.enum(["DEVELOPMENT", "PRODUCTION"]))
.default("PRODUCTION"),
PORT: z.coerce.number().int().min(1000).default(3000),
MONGODB_URI: UrlSchema.default("mongodb://localhost"),
ADMIN_EMAILS: z.preprocess(split, z.array(EmailSchema)),
ADMIN_PASSWORDS: z.preprocess(split, z.array(NotEmptyStringSchema)),
LOCATION: UrlSchema,
LOG_LEVEL: z.string().default("INFO"),
PRETTY_LOG: z.coerce.boolean().default(false),
});

export const PackageJsonSchema = z
.object({
name: z.string().min(1),
version: z.string().min(5),
homepage: UrlSchema,
})
.transform(toUpperCaseKeys);

function toUpperCase<T>(value: T) {
if (typeof value === "string") {
return value.toUpperCase();
}

return value;
}

function split<T>(value: T) {
if (typeof value === "string") {
return value.split(",");
}

return value;
}

function toUpperCaseKeys(value: {
name: string;
version: string;
homepage: string;
}) {
return {
NAME: value.name,
VERSION: value.version,
HOMEPAGE: value.homepage,
};
}
98 changes: 98 additions & 0 deletions routes/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { AppProps } from "$fresh/server.ts";
import { Nav } from "@components/nav.tsx";
import { Favicon, PreloadedStylesheet } from "@components/head.tsx";
import config from "@modules/config/mod.ts";

export interface AppProperties {
subtitle?: string;
}

const links = [
{ children: "🏠 Home", href: "/" },
{ children: "📚 Catalog", href: "/catalog/pages/1" },
{ children: "🏷️ Tags", href: "/tags" },
{ children: "🌐 Languages", href: "/languages" },
];

const favicons = [
{
rel: "apple-touch-icon",
sizes: "180x180",
href: "/assets/apple-touch-icon.png",
},
{
rel: "icon",
type: "image/png",
sizes: "32x32",
href: "/assets/favicon-32x32.png",
},
{
rel: "icon",
type: "image/png",
sizes: "16x16",
href: "/assets/favicon-16x16.png",
},
{
rel: "icon",
type: "image/x-icon",
sizes: "any",
href: "/assets/favicon.ico",
},
];

const stylesheets = [
{
href: "https://cdn.jsdelivr.net/npm/halfmoon@2.0.1/css/halfmoon.min.css",
},
{
href:
"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css",
},
{
href: "https://cdn.jsdelivr.net/npm/victormono@latest/dist/index.min.css",
},
{
href: "/styles/main.css",
},
];

export default function App(
{ Component, state, data }: AppProps<AppProperties, AppProperties>,
) {
console.log(Component.displayName);
console.log(state);
const title = data.subtitle ? `${data.subtitle} - Duofiction` : "Duofiction";

return (
<html lang="en" data-bs-theme="dark" data-bs-core="modern">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="NOINDEX, NOFOLLOW" />
<title>{title}</title>
{favicons.map(Favicon)}
<link
rel="manifest"
href={config.ENVIRONMENT === "DEVELOPMENT"
? "/assets/dev-site.webmanifest"
: "/assets/site.webmanifest"}
/>
{stylesheets.map(PreloadedStylesheet)}
</head>
<body class="subpixel-antialiased">
{Nav(links)}
<main class="container">
<Component />
</main>
<script
async
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"
>
</script>
<script type="module" src="/scripts/main.mjs"></script>
</body>
</html>
);
}
27 changes: 27 additions & 0 deletions routes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useState } from "preact/hooks";
import { Handlers, RouteContext } from "$fresh/server.ts";

interface Data {
subtitle: string;
}
export const handler: Handlers<unknown, Data> = {
GET(req, ctx) {
console.log(req);
return ctx.render({ subtitle: "Home" }, {});
},
};

export default function Home(_: Request, ctx: RouteContext) {
// ctx.state.subtitle = "Home";
return (
<div class="px-4 py-8 mx-auto bg-[#86efac]">
<div class="max-w-screen-md mx-auto flex flex-col items-center justify-center">
<h1 class="text-4xl font-bold">Welcome to Fresh</h1>
<p class="my-4">
Try updating this message in the
<code class="mx-2">./routes/index.tsx</code> file, and refresh.
</p>
</div>
</div>
);
}
6 changes: 3 additions & 3 deletions scripts.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { DenonConfig } from "https://deno.land/x/denon@2.5.0/mod.ts";
const config: DenonConfig = {
scripts: {
start: {
cmd: `deno run app/main.ts`,
cmd: `deno run dev.ts`,
desc: "Run my webserver",
watch: true,
},
Expand All @@ -13,8 +13,8 @@ const config: DenonConfig = {
watcher: {
interval: 1_000,
skip: ["**/.git/**", "**/bin/**"],
paths: ["app", "common"],
exts: ["ts", "css", "mjs", "json", "webmanifest"],
paths: ["islands", "modules", "routes", "components"],
exts: ["ts", "css", "mjs", "json", "webmanifest", "tsx"],
},
};

Expand Down
Binary file added static/assets/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/assets/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/assets/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions static/assets/dev-site.webmanifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"background_color": "#ffffff",
"display": "standalone",
"icons": [
{
"sizes": "192x192",
"src": "/assets/android-chrome-192x192.png",
"type": "image/png"
},
{
"sizes": "512x512",
"src": "/assets/android-chrome-512x512.png",
"type": "image/png"
}
],
"name": "Duofiction",
"short_name": "Duofiction",
"start_url": "http://localhost:3000",
"theme_color": "#ffffff"
}
Binary file added static/assets/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/assets/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/assets/favicon.ico
Binary file not shown.
2 changes: 2 additions & 0 deletions static/assets/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
User-agent: *
Disallow: /
Loading

0 comments on commit 62f2322

Please sign in to comment.