add routing of static files to server for deploy
This commit is contained in:
parent
728506de49
commit
c95e91fa15
@ -2,17 +2,17 @@ module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
ignorePatterns: ["dist", ".eslintrc.cjs"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["react-refresh"],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
"react-refresh/only-export-components": [
|
||||
"warn",
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
29
README.md
29
README.md
@ -1,15 +1,19 @@
|
||||
# React + TypeScript + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
This template provides a minimal setup to get React working in Vite with HMR and
|
||||
some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md)
|
||||
uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc)
|
||||
uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
If you are developing a production application, we recommend updating the
|
||||
configuration to enable type aware lint rules:
|
||||
|
||||
- Configure the top-level `parserOptions` property like this:
|
||||
|
||||
@ -17,14 +21,19 @@ If you are developing a production application, we recommend updating the config
|
||||
export default {
|
||||
// other rules...
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
project: ['./tsconfig.json', './tsconfig.node.json', './tsconfig.app.json'],
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
project: ["./tsconfig.json", "./tsconfig.node.json", "./tsconfig.app.json"],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
||||
- Replace `plugin:@typescript-eslint/recommended` to
|
||||
`plugin:@typescript-eslint/recommended-type-checked` or
|
||||
`plugin:@typescript-eslint/strict-type-checked`
|
||||
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
|
||||
- Install
|
||||
[eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and
|
||||
add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends`
|
||||
list
|
||||
|
||||
6040
api/data.json
6040
api/data.json
File diff suppressed because it is too large
Load Diff
31
api/main.ts
31
api/main.ts
@ -1,32 +1,33 @@
|
||||
import { Application, Router } from "@oak/oak";
|
||||
import { oakCors } from "@tajpouria/cors";
|
||||
import data from "./data.json" with { type: "json" };
|
||||
import routeStaticFilesFrom from "./util/routeStaticFilesFrom.ts";
|
||||
|
||||
const router = new Router();
|
||||
|
||||
router.get("/", (context) => {
|
||||
context.response.body = "Welcome to dinosaur API!";
|
||||
})
|
||||
router.get("/api/dinosaurs", (context) => {
|
||||
context.response.body = data;
|
||||
});
|
||||
|
||||
router.get("/dinosaurs", (context) => {
|
||||
context.response.body = data;
|
||||
})
|
||||
router.get("/api/dinosaurs/:dinosaur", (context) => {
|
||||
if (!context?.params?.dinosaur) {
|
||||
context.response.body = "No dinosaur name provided.";
|
||||
}
|
||||
|
||||
router.get("/dinosaurs/:dinosaur", (context) => {
|
||||
if (!context?.params?.dinosaur) {
|
||||
context.response.body = "No dinosaur name provided.";
|
||||
}
|
||||
const dinosaur = data.find((item) =>
|
||||
item.name.toLowerCase() === context.params.dinosaur.toLowerCase()
|
||||
);
|
||||
|
||||
const dinosaur = data.find((item) =>
|
||||
item.name.toLowerCase() === context.params.dinosaur.toLowerCase()
|
||||
);
|
||||
|
||||
context.response.body = dinosaur ? dinosaur : "No dinosaur found.";
|
||||
context.response.body = dinosaur ? dinosaur : "No dinosaur found.";
|
||||
});
|
||||
|
||||
const app = new Application();
|
||||
app.use(oakCors());
|
||||
app.use(router.routes());
|
||||
app.use(router.allowedMethods());
|
||||
app.use(routeStaticFilesFrom([
|
||||
`${Deno.cwd()}/dist`,
|
||||
`${Deno.cwd()}/public`,
|
||||
]));
|
||||
|
||||
await app.listen({ port: 8000 });
|
||||
|
||||
19
api/util/routeStaticFilesFrom.ts
Normal file
19
api/util/routeStaticFilesFrom.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Next } from "jsr:@oak/oak/middleware";
|
||||
import { Context } from "jsr:@oak/oak/context";
|
||||
|
||||
// Configure static site routes so that we can serve
|
||||
// the Vite build output and the public folder
|
||||
export default function routeStaticFilesFrom(staticPaths: string[]) {
|
||||
return async (context: Context<Record<string, object>>, next: Next) => {
|
||||
for (const path of staticPaths) {
|
||||
try {
|
||||
await context.send({ root: path, index: "index.html" });
|
||||
return;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
await next();
|
||||
};
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
"packages": {
|
||||
"specifiers": {
|
||||
"jsr:@oak/commons@^1.0": "jsr:@oak/commons@1.0.0",
|
||||
"jsr:@oak/oak": "jsr:@oak/oak@17.0.0",
|
||||
"jsr:@oak/oak@^17.0.0": "jsr:@oak/oak@17.0.0",
|
||||
"jsr:@std/assert@^1.0": "jsr:@std/assert@1.0.6",
|
||||
"jsr:@std/bytes@^1.0": "jsr:@std/bytes@1.0.2",
|
||||
@ -27,6 +28,7 @@
|
||||
"npm:react-dom@^18.3.1": "npm:react-dom@18.3.1_react@18.3.1",
|
||||
"npm:react-router-dom@^6.26.2": "npm:react-router-dom@6.26.2_react@18.3.1_react-dom@18.3.1__react@18.3.1",
|
||||
"npm:react@^18.3.1": "npm:react@18.3.1",
|
||||
"npm:typescript@5.6.2": "npm:typescript@5.6.2",
|
||||
"npm:typescript@^5.2.2": "npm:typescript@5.6.2",
|
||||
"npm:vite": "npm:vite@5.4.8",
|
||||
"npm:vite@5.4.8": "npm:vite@5.4.8",
|
||||
|
||||
@ -5,9 +5,10 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "deno task dev:api & deno task dev:vite",
|
||||
"dev:api": "deno run --allow-env --allow-net api/main.ts",
|
||||
"dev:api": "deno run --allow-env --allow-read --allow-net api/main.ts",
|
||||
"dev:vite": "deno run -A npm:vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"serve": "deno task build && deno task dev:api",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { Route, Routes } from "react-router-dom";
|
||||
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
||||
import Index from "./pages/index";
|
||||
import Dinosaur from "./pages/Dinosaur";
|
||||
import "./App.css";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Index />} />
|
||||
<Route path="/:selectedDinosaur" element={<Dinosaur />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import "./index.css";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>,
|
||||
<App />,
|
||||
);
|
||||
|
||||
@ -1,26 +1,24 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import { Dino } from "../../types";
|
||||
import { Dino } from "../types";
|
||||
|
||||
export default function Dinosaur() {
|
||||
const { selectedDinosaur } = useParams();
|
||||
const [dinosaur, setDino] = useState<Dino>({ name: "", description: "" });
|
||||
const { selectedDinosaur } = useParams();
|
||||
const [dinosaur, setDino] = useState<Dino>({ name: "", description: "" });
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const resp = await fetch(
|
||||
`http://localhost:8000/dinosaurs/${selectedDinosaur}`,
|
||||
);
|
||||
const dino = await resp.json() as Dino;
|
||||
setDino(dino);
|
||||
})();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const resp = await fetch(`/api/dinosaurs/${selectedDinosaur}`);
|
||||
const dino = await resp.json() as Dino;
|
||||
setDino(dino);
|
||||
})();
|
||||
}, [selectedDinosaur]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{dinosaur.name}</h1>
|
||||
<p>{dinosaur.description}</p>
|
||||
<Link to="/">🠠 Back to all dinosaurs</Link>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<h1>{dinosaur.name}</h1>
|
||||
<p>{dinosaur.description}</p>
|
||||
<Link to="/">🠠 Back to all dinosaurs</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,29 +1,33 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Dino } from "../../types.ts";
|
||||
import { Dino } from "../types.ts";
|
||||
|
||||
export default function Index() {
|
||||
const [dinosaurs, setDinosaurs] = useState<Dino[]>([]);
|
||||
const [dinosaurs, setDinosaurs] = useState<Dino[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const response = await fetch(`http://localhost:8000/dinosaurs/`);
|
||||
const allDinosaurs = await response.json() as Dino[];
|
||||
setDinosaurs(allDinosaurs);
|
||||
})();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const response = await fetch(`/api/dinosaurs/`);
|
||||
const allDinosaurs = await response.json() as Dino[];
|
||||
setDinosaurs(allDinosaurs);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>Welcome to the Dinosaur app</h1>
|
||||
<p>Click on a dinosaur below to learn more.</p>
|
||||
{dinosaurs.map((dinosaur: Dino) => {
|
||||
return (
|
||||
<Link to={`/${dinosaur.name.toLowerCase()}`} key={dinosaur.name} className="dinosaur">
|
||||
{dinosaur.name}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</main>
|
||||
);
|
||||
return (
|
||||
<main>
|
||||
<h1>Welcome to the Dinosaur app</h1>
|
||||
<p>Click on a dinosaur below to learn more.</p>
|
||||
{dinosaurs.map((dinosaur: Dino) => {
|
||||
return (
|
||||
<Link
|
||||
to={`/${dinosaur.name.toLowerCase()}`}
|
||||
key={dinosaur.name}
|
||||
className="dinosaur"
|
||||
>
|
||||
{dinosaur.name}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@ -23,5 +23,5 @@
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": ["src", "tsconfig.json"]
|
||||
}
|
||||
|
||||
@ -1,7 +1,15 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
})
|
||||
server: {
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: "http://localhost:8000",
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user