Switched to vite

This commit is contained in:
2026-01-29 21:37:37 +01:00
parent 1a13946f63
commit ab98ee82a1
20 changed files with 1499 additions and 2318 deletions
-4
View File
@@ -1,4 +0,0 @@
.react-router
build
node_modules
README.md
+23 -6
View File
@@ -1,7 +1,24 @@
.DS_Store # Logs
.env logs
/node_modules/ *.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# React Router node_modules
/.react-router/ dist
/build/ dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
-22
View File
@@ -1,22 +0,0 @@
FROM node:20-alpine AS development-dependencies-env
COPY . /app
WORKDIR /app
RUN npm ci
FROM node:20-alpine AS production-dependencies-env
COPY ./package.json package-lock.json /app/
WORKDIR /app
RUN npm ci --omit=dev
FROM node:20-alpine AS build-env
COPY . /app/
COPY --from=development-dependencies-env /app/node_modules /app/node_modules
WORKDIR /app
RUN npm run build
FROM node:20-alpine
COPY ./package.json package-lock.json /app/
COPY --from=production-dependencies-env /app/node_modules /app/node_modules
COPY --from=build-env /app/build /app/build
WORKDIR /app
CMD ["npm", "run", "start"]
+60 -74
View File
@@ -1,87 +1,73 @@
# Welcome to React Router! # React + TypeScript + Vite
A modern, production-ready template for building full-stack React applications using React Router. This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/remix-run/react-router-templates/tree/main/default) Currently, two official plugins are available:
## Features - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
- 🚀 Server-side rendering ## React Compiler
- ⚡️ Hot Module Replacement (HMR)
- 📦 Asset bundling and optimization
- 🔄 Data loading and mutations
- 🔒 TypeScript by default
- 🎉 TailwindCSS for styling
- 📖 [React Router docs](https://reactrouter.com/)
## Getting Started The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
### Installation ## Expanding the ESLint configuration
Install the dependencies: If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
```bash ```js
npm install export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
``` ```
### Development You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
Start the development server with HMR: ```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
```bash export default defineConfig([
npm run dev globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
``` ```
Your application will be available at `http://localhost:5173`.
## Building for Production
Create a production build:
```bash
npm run build
```
## Deployment
### Docker Deployment
To build and run using Docker:
```bash
docker build -t my-app .
# Run the container
docker run -p 3000:3000 my-app
```
The containerized application can be deployed to any platform that supports Docker, including:
- AWS ECS
- Google Cloud Run
- Azure Container Apps
- Digital Ocean App Platform
- Fly.io
- Railway
### DIY Deployment
If you're familiar with deploying Node applications, the built-in app server is production-ready.
Make sure to deploy the output of `npm run build`
```
├── package.json
├── package-lock.json (or pnpm-lock.yaml, or bun.lockb)
├── build/
│ ├── client/ # Static assets
│ └── server/ # Server-side code
```
## Styling
This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever CSS framework you prefer.
---
Built with ❤️ using React Router.
-75
View File
@@ -1,75 +0,0 @@
import {
isRouteErrorResponse,
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "react-router";
import type { Route } from "./+types/root";
import "./app.css";
export const links: Route.LinksFunction = () => [
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
{
rel: "preconnect",
href: "https://fonts.gstatic.com",
crossOrigin: "anonymous",
},
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap",
},
];
export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
export default function App() {
return <Outlet />;
}
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
let message = "Oops!";
let details = "An unexpected error occurred.";
let stack: string | undefined;
if (isRouteErrorResponse(error)) {
message = error.status === 404 ? "404" : "Error";
details =
error.status === 404
? "The requested page could not be found."
: error.statusText || details;
} else if (import.meta.env.DEV && error && error instanceof Error) {
details = error.message;
stack = error.stack;
}
return (
<main className="pt-16 p-4 container mx-auto">
<h1>{message}</h1>
<p>{details}</p>
{stack && (
<pre className="w-full p-4 overflow-x-auto">
<code>{stack}</code>
</pre>
)}
</main>
);
}
-3
View File
@@ -1,3 +0,0 @@
import { type RouteConfig, index } from "@react-router/dev/routes";
export default [index("routes/home.tsx")] satisfies RouteConfig;
+23
View File
@@ -0,0 +1,23 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
},
])
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>3dplot-gen</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+1286 -2069
View File
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -1,34 +1,34 @@
{ {
"name": "3dplot-gen", "name": "3dplot-gen",
"private": true, "private": true,
"version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "react-router build", "dev": "vite",
"dev": "react-router dev", "build": "tsc -b && vite build",
"start": "react-router-serve ./build/server/index.js", "lint": "eslint .",
"typecheck": "react-router typegen && tsc" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@react-router/node": "7.12.0",
"@react-router/serve": "7.12.0",
"@types/papaparse": "^5.5.2", "@types/papaparse": "^5.5.2",
"@types/plotly.js-dist-min": "^2.3.4", "@types/plotly.js-dist-min": "^2.3.4",
"isbot": "^5.1.31",
"papaparse": "^5.5.3", "papaparse": "^5.5.3",
"plotly.js-dist-min": "^3.3.1", "plotly.js-dist-min": "^3.3.1",
"react": "^19.2.4", "react": "^19.2.0",
"react-dom": "^19.2.4", "react-dom": "^19.2.0"
"react-router": "7.12.0"
}, },
"devDependencies": { "devDependencies": {
"@react-router/dev": "7.12.0", "@eslint/js": "^9.39.1",
"@tailwindcss/vite": "^4.1.13", "@types/node": "^24.10.1",
"@types/node": "^22.19.7", "@types/react": "^19.2.5",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"tailwindcss": "^4.1.13", "@vitejs/plugin-react": "^5.1.1",
"typescript": "^5.9.2", "eslint": "^9.39.1",
"vite": "^7.1.7", "eslint-plugin-react-hooks": "^7.0.1",
"vite-tsconfig-paths": "^5.1.4" "eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4",
"vite": "^7.2.4"
} }
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

-7
View File
@@ -1,7 +0,0 @@
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;
+1 -9
View File
@@ -1,14 +1,6 @@
import type React from "react"; import type React from "react";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import * as papa from "papaparse"; import * as papa from "papaparse";
import type { Route } from "./+types/home";
export function meta({ }: Route.MetaArgs) {
return [
{ title: "3dplot-gen" },
{ name: "description", content: "CSV → 3D Plot generator" },
];
}
type Row = Record<string, number>; type Row = Record<string, number>;
@@ -73,7 +65,7 @@ const COLORSCALES = [
"Turbo", "Turbo",
] as const; ] as const;
export default function Home() { export default function App() {
const plotRef = useRef<HTMLDivElement>(null); const plotRef = useRef<HTMLDivElement>(null);
const [rows, setRows] = useState<Row[]>([]); const [rows, setRows] = useState<Row[]>([]);
View File
+10
View File
@@ -0,0 +1,10 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
+28
View File
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"types": ["vite/client"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}
+5 -25
View File
@@ -1,27 +1,7 @@
{ {
"include": [ "files": [],
"**/*", "references": [
"**/.server/**/*", { "path": "./tsconfig.app.json" },
"**/.client/**/*", { "path": "./tsconfig.node.json" }
".react-router/types/**/*" ]
],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"types": ["node", "vite/client"],
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"rootDirs": [".", "./.react-router/types"],
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
"esModuleInterop": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true
}
} }
+26
View File
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"types": ["node"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}
+5 -6
View File
@@ -1,8 +1,7 @@
import { reactRouter } from "@react-router/dev/vite"; import { defineConfig } from 'vite'
import tailwindcss from "@tailwindcss/vite"; import react from '@vitejs/plugin-react'
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
// https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [tailwindcss(), reactRouter(), tsconfigPaths()], plugins: [react()],
}); })