Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/quality-gateway-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
bun-version: latest
- run: bun install --frozen-lockfile
- run: bun lint
- run: bun build:static
- run: bunx react-router build

biome:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ node_modules
# playwright
test-results
playwright-report

# React Router
/.react-router/
/build/
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ This WebApp is the main project of PodCodar, a learning community about programm

- 📖 [Remix docs](https://remix.run/docs)

## Features

- 🚀 Server-side rendering
- ⚡️ Hot Module Replacement (HMR)
- 📦 Asset bundling and optimization
- 🔄 Data loading and mutations
- 🔒 TypeScript by default
- 🎉 TailwindCSS for styling
- 📖 [React Router docs](https://reactrouter.com/)

## Development

### System Dependencies
Expand Down
2 changes: 1 addition & 1 deletion app/cookies.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MAX_COOKIE_AGE } from "@packages/contants";
import { createCookie } from "@remix-run/cloudflare"; // or cloudflare/deno
import { createCookie } from "react-router";

export const selectedTheme = createCookie("selected-theme", {
path: "/",
Expand Down
18 changes: 0 additions & 18 deletions app/entry.client.tsx

This file was deleted.

37 changes: 13 additions & 24 deletions app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,35 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
*/

import type { AppLoadContext, EntryContext } from "@remix-run/cloudflare";
import { RemixServer } from "@remix-run/react";
import { isbot } from "isbot";
import { renderToReadableStream } from "react-dom/server";
import {
type AppLoadContext,
type EntryContext,
ServerRouter,
} from "react-router";

const ABORT_DELAY = 5000;

export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
status: number,
headers: Headers,
routerContext: EntryContext,
// This is ignored so we can keep it in the template for visibility. Feel
// free to delete this parameter in your app if you're not using it!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
loadContext: AppLoadContext,
_loadContext: AppLoadContext,
) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), ABORT_DELAY);

const body = await renderToReadableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
<ServerRouter context={routerContext} url={request.url} />,
{
signal: controller.signal,
onError(error: unknown) {
if (!controller.signal.aborted) {
// Log streaming rendering errors from inside the shell
console.error(error);
}
responseStatusCode = 500;
status = 500;
},
},
);
Expand All @@ -48,9 +40,6 @@ export default async function handleRequest(
await body.allReady;
}

responseHeaders.set("Content-Type", "text/html");
return new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
});
headers.set("Content-Type", "text/html");
return new Response(body, { headers, status });
}
10 changes: 4 additions & 6 deletions app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import type { Theme } from "@packages/utils/theme";
import type {
ActionFunctionArgs,
LinksFunction,
LoaderFunctionArgs,
} from "@remix-run/cloudflare";
import {
type ActionFunctionArgs,
Links,
type LinksFunction,
type LoaderFunctionArgs,
Meta,
Outlet,
Scripts,
Expand All @@ -14,7 +12,7 @@ import {
redirect,
useLoaderData,
useRouteError,
} from "@remix-run/react";
} from "react-router";

import "./tailwind.css";
import Metadata from "@packages/components/Metadata";
Expand Down
6 changes: 6 additions & 0 deletions app/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type RouteConfig, route } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";

const routes = await flatRoutes();

export default [...routes, route("/*", "./catchall.tsx")] satisfies RouteConfig;
7 changes: 5 additions & 2 deletions app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import RoadmapSection from "@packages/components/RoadmapSection";
import TechSection from "@packages/components/TechSection";
import TestimonialSection from "@packages/components/TestimonialSection";
import WhyItWorksSection from "@packages/components/WhyItWorksSection";
import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/cloudflare";
import { useLoaderData } from "@remix-run/react";

import { description, title } from "@packages/config/site";
import { Database } from "@packages/repositories/db";
import {
type LoaderFunctionArgs,
type MetaFunction,
useLoaderData,
} from "react-router";

export const meta: MetaFunction = () => {
return [{ title }, { name: "description", content: description }];
Expand Down
4 changes: 1 addition & 3 deletions app/routes/team.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import TeamPage from "@packages/components/TeamPage";
import { Database } from "@packages/repositories/db";
import type { LoaderFunctionArgs } from "@remix-run/cloudflare";
import { useLoaderData } from "@remix-run/react";
import { type LoaderFunctionArgs, useLoaderData } from "react-router";

export async function loader({ context }: LoaderFunctionArgs) {
console.log(context);
const db = new Database(
context.cloudflare.env.TURSO_CONNECTION_URL,
context.cloudflare.env.TURSO_AUTH_TOKEN,
Expand Down
Binary file modified bun.lockb
Binary file not shown.
7 changes: 3 additions & 4 deletions functions/[[path]].ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { createPagesFunctionHandler } from "@remix-run/cloudflare-pages";
import { createRequestHandler } from "@react-router/cloudflare";

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - the server build file is generated by `remix vite:build`
// eslint-disable-next-line import/no-unresolved
// @ts-ignore - the server build file is generated by `react-router build`
import * as build from "../build/server";

export const onRequest = createPagesFunctionHandler({
export const onRequest = createRequestHandler({
build,
});
4 changes: 2 additions & 2 deletions load-context.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { AppLoadContext } from "@remix-run/cloudflare";
import type { AppLoadContext } from "react-router";
import type { PlatformProxy } from "wrangler";

type Cloudflare = Omit<PlatformProxy<Env>, "dispose">;

declare module "@remix-run/cloudflare" {
declare module "react-router" {
interface AppLoadContext {
cloudflare: Cloudflare;
extra: string; // augmented
Expand Down
56 changes: 29 additions & 27 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,62 +6,64 @@
"sideEffects": false,
"type": "module",
"scripts": {
"dev": "bun run typegen && remix vite:dev",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs",
"dev": "bun run typegen && react-router dev",
"prebuild": "bun run typegen && bun run db:migrate",
"build": "remix vite:build",
"build": "react-router build",
"deploy": "bun run build && wrangler pages deploy",
"lint": "biome lint",
"fmt": "biome check --write ",
"encrypt": "gpg -c .env",
"decrypt": "gpg -d .env.gpg > .env && cp .env .dev.vars",
"decrypt": "gpg -d .env.gpg > .env && cp .env .dev.vars && wrangler types",
"test": "bun test packages app",
"e2e": "playwright test",
"db:migrate": "drizzle-kit migrate",
"db:studio": "drizzle-kit studio",
"typegen": "wrangler types && drizzle-kit generate",
"preview": "bun run build && wrangler pages dev",
"start": "wrangler pages dev ./build/client",
"typegen": "drizzle-kit generate && react-router typegen",
"typecheck": "tsc"
},
"dependencies": {
"@libsql/client": "^0.14.0",
"@remix-run/cloudflare": "^2.15.2",
"@remix-run/cloudflare-pages": "^2.15.2",
"@remix-run/react": "^2.15.2",
"@remix-run/serve": "^2.15.2",
"daisyui": "^4.12.22",
"@react-router/cloudflare": "^7.1.1",
"@react-router/fs-routes": "^7.1.1",
"@react-router/node": "^7.1.1",
"@react-router/serve": "^7.1.1",
"daisyui": "^4.12.23",
"dotenv": "^16.4.7",
"drizzle-orm": "^0.38.2",
"i18next": "^24.2.0",
"isbot": "^4.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^15.2.0"
"drizzle-orm": "^0.38.3",
"i18next": "^24.2.1",
"isbot": "^5.1.21",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-i18next": "^15.4.0",
"react-router": "^7.1.1"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@modyfi/vite-plugin-yaml": "^1.1.0",
"@playwright/test": "^1.49.1",
"@remix-run/dev": "^2.15.2",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"autoprefixer": "^10.4.19",
"@react-router/dev": "^7.1.1",
"@types/node": "^20.17.13",
"@types/react": "^19.0.7",
"@types/react-dom": "^19.0.3",
"autoprefixer": "^10.4.20",
"drizzle-kit": "^0.30.1",
"lefthook": "^1.10.0",
"lint-staged": "^15.2.11",
"lefthook": "^1.10.7",
"lint-staged": "^15.3.0",
"mermaid": "^11.4.1",
"postcss": "^8.4.38",
"tailwindcss": "^3.4.4",
"typescript": "^5.1.6",
"vite": "^5.1.0",
"vite-tsconfig-paths": "^4.2.1",
"postcss": "^8.5.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.3",
"vite": "^5.4.11",
"vite-tsconfig-paths": "^4.3.2",
"vitepress": "^1.5.0",
"vitepress-carbon": "^1.5.0",
"vitepress-plugin-mermaid": "^2.0.17",
"wrangler": "^3.99.0"
"wrangler": "^3.102.0"
},
"lint-staged": {
"*.{md,mdx}": "bunx prettier --write",
Expand Down
2 changes: 1 addition & 1 deletion packages/components/Link.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link as DefaulLink, type LinkProps } from "@remix-run/react";
import { Link as DefaulLink, type LinkProps } from "react-router";

type Props = Omit<LinkProps, "to"> & {
children: React.ReactNode;
Expand Down
2 changes: 0 additions & 2 deletions packages/components/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"use client";

import { useState } from "react";

import { Logo } from "@packages/components/icons";
Expand Down
4 changes: 1 addition & 3 deletions packages/components/ToggleThemeButton.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"use client";

import { type Theme, strToTheme, toggleTheme } from "@packages/utils/theme";
import { Form } from "@remix-run/react";
import { useState } from "react";
import { Form } from "react-router";

export default function ToggleThemeButton() {
const [colorMode, setColorMode] = useState<Theme>(
Expand Down
7 changes: 7 additions & 0 deletions react-router.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Config } from "@react-router/dev/config";

export default {
// Config options...
// Server-side render by default, to enable SPA mode set this to `false`
ssr: true,
} satisfies Config;
40 changes: 15 additions & 25 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,38 +1,28 @@
{
"include": [
"**/*.ts",
"**/*.tsx",
"**/.server/**/*.ts",
"**/.server/**/*.tsx",
"**/.client/**/*.ts",
"**/.client/**/*.tsx"
"**/*",
"**/.server/**/*",
"**/.client/**/*",
".react-router/types/**/*"
],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"types": [
"vite/client",
"@remix-run/cloudflare",
"@cloudflare/workers-types/2023-07-01"
],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"types": ["node", "vite/client"],
"target": "ES2022",
"strict": true,
"allowJs": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"module": "ES2022",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"rootDirs": [".", "./.react-router/types"],
"baseUrl": ".",
"paths": {
"@packages/*": ["./packages/*"],
"f/*": ["./functions/*"],
"~/*": ["./app/*"]
},

// Vite takes care of building everything, not tsc.
"noEmit": true
"esModuleInterop": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true
}
}
Loading
Loading