create-softeneers-app 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.html +56 -0
- package/README.md +16 -8
- package/dist/args.js +33 -4
- package/dist/args.js.map +1 -1
- package/dist/fragments.js +127 -0
- package/dist/fragments.js.map +1 -0
- package/dist/index.js +18 -7
- package/dist/index.js.map +1 -1
- package/dist/prompts.js +27 -1
- package/dist/prompts.js.map +1 -1
- package/dist/templates.js +33 -8
- package/dist/templates.js.map +1 -1
- package/package.json +2 -2
- package/templates/express-api/.env.example +13 -0
- package/templates/express-api/README.md +77 -0
- package/templates/express-api/docker-compose.yml +15 -0
- package/templates/express-api/package.json +36 -0
- package/templates/express-api/softeneers.template.json +17 -0
- package/templates/express-api/src/auth/auth.ts +11 -0
- package/templates/express-api/src/cars/routes.ts +58 -0
- package/templates/express-api/src/cars/store.ts +92 -0
- package/templates/express-api/src/cars/types.ts +8 -0
- package/templates/express-api/src/cars/validate.ts +16 -0
- package/templates/express-api/src/db.ts +13 -0
- package/templates/express-api/src/env.ts +23 -0
- package/templates/express-api/src/index.ts +55 -0
- package/templates/express-api/src/scripts/migrate.ts +13 -0
- package/templates/express-api/src/scripts/seed.ts +25 -0
- package/templates/express-api/test/validate.test.ts +25 -0
- package/templates/express-api/tsconfig.json +14 -0
- package/templates/hono-api/.env.example +13 -0
- package/templates/hono-api/README.md +77 -0
- package/templates/hono-api/docker-compose.yml +15 -0
- package/templates/hono-api/package.json +34 -0
- package/templates/hono-api/softeneers.template.json +17 -0
- package/templates/hono-api/src/auth/auth.ts +11 -0
- package/templates/hono-api/src/cars/routes.ts +43 -0
- package/templates/hono-api/src/cars/store.ts +92 -0
- package/templates/hono-api/src/cars/types.ts +8 -0
- package/templates/hono-api/src/cars/validate.ts +16 -0
- package/templates/hono-api/src/db.ts +13 -0
- package/templates/hono-api/src/env.ts +23 -0
- package/templates/hono-api/src/index.ts +44 -0
- package/templates/hono-api/src/scripts/migrate.ts +13 -0
- package/templates/hono-api/src/scripts/seed.ts +25 -0
- package/templates/hono-api/test/validate.test.ts +25 -0
- package/templates/hono-api/tsconfig.json +14 -0
- package/templates/minimal/.env.example +2 -0
- package/templates/minimal/README.md +33 -0
- package/templates/minimal/package.json +22 -0
- package/templates/minimal/src/index.ts +20 -0
- package/templates/minimal/test/greet.test.ts +12 -0
- package/templates/minimal/tsconfig.json +15 -0
- package/templates/tanstack-start/.env.example +11 -0
- package/templates/tanstack-start/README.md +73 -0
- package/templates/tanstack-start/docker-compose.yml +15 -0
- package/templates/tanstack-start/package.json +56 -0
- package/templates/tanstack-start/public/favicon.ico +0 -0
- package/templates/tanstack-start/public/logo192.png +0 -0
- package/templates/tanstack-start/public/logo512.png +0 -0
- package/templates/tanstack-start/public/manifest.json +25 -0
- package/templates/tanstack-start/public/robots.txt +3 -0
- package/templates/tanstack-start/softeneers.template.json +17 -0
- package/templates/tanstack-start/src/cars/types.ts +8 -0
- package/templates/tanstack-start/src/cars/validate.ts +16 -0
- package/templates/tanstack-start/src/router.tsx +19 -0
- package/templates/tanstack-start/src/routes/__root.tsx +54 -0
- package/templates/tanstack-start/src/routes/api/auth/$.ts +14 -0
- package/templates/tanstack-start/src/routes/cars.tsx +87 -0
- package/templates/tanstack-start/src/routes/index.tsx +20 -0
- package/templates/tanstack-start/src/server/auth.ts +11 -0
- package/templates/tanstack-start/src/server/cars.ts +27 -0
- package/templates/tanstack-start/src/server/db.ts +12 -0
- package/templates/tanstack-start/src/server/env.ts +22 -0
- package/templates/tanstack-start/src/server/scripts/migrate.ts +13 -0
- package/templates/tanstack-start/src/server/scripts/seed.ts +25 -0
- package/templates/tanstack-start/src/server/store.ts +79 -0
- package/templates/tanstack-start/src/styles.css +17 -0
- package/templates/tanstack-start/tsconfig.json +28 -0
- package/templates/tanstack-start/tsr.config.json +3 -0
- package/templates/tanstack-start/vite.config.ts +14 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'
|
|
2
|
+
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
|
|
3
|
+
import { TanStackDevtools } from '@tanstack/react-devtools'
|
|
4
|
+
|
|
5
|
+
import appCss from '../styles.css?url'
|
|
6
|
+
|
|
7
|
+
export const Route = createRootRoute({
|
|
8
|
+
head: () => ({
|
|
9
|
+
meta: [
|
|
10
|
+
{
|
|
11
|
+
charSet: 'utf-8',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'viewport',
|
|
15
|
+
content: 'width=device-width, initial-scale=1',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
title: 'TanStack Start Starter',
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
links: [
|
|
22
|
+
{
|
|
23
|
+
rel: 'stylesheet',
|
|
24
|
+
href: appCss,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}),
|
|
28
|
+
shellComponent: RootDocument,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
function RootDocument({ children }: { children: React.ReactNode }) {
|
|
32
|
+
return (
|
|
33
|
+
<html lang="en">
|
|
34
|
+
<head>
|
|
35
|
+
<HeadContent />
|
|
36
|
+
</head>
|
|
37
|
+
<body>
|
|
38
|
+
{children}
|
|
39
|
+
<TanStackDevtools
|
|
40
|
+
config={{
|
|
41
|
+
position: 'bottom-right',
|
|
42
|
+
}}
|
|
43
|
+
plugins={[
|
|
44
|
+
{
|
|
45
|
+
name: 'Tanstack Router',
|
|
46
|
+
render: <TanStackRouterDevtoolsPanel />,
|
|
47
|
+
},
|
|
48
|
+
]}
|
|
49
|
+
/>
|
|
50
|
+
<Scripts />
|
|
51
|
+
</body>
|
|
52
|
+
</html>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
|
|
3
|
+
import { auth } from '../../../server/auth'
|
|
4
|
+
|
|
5
|
+
// Catch-all server route: better-auth speaks the Fetch API, so hand it the raw
|
|
6
|
+
// Request and return its Response. Handles every /api/auth/* endpoint.
|
|
7
|
+
export const Route = createFileRoute('/api/auth/$')({
|
|
8
|
+
server: {
|
|
9
|
+
handlers: {
|
|
10
|
+
GET: ({ request }) => auth.handler(request),
|
|
11
|
+
POST: ({ request }) => auth.handler(request),
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
})
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createFileRoute, useRouter } from '@tanstack/react-router'
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
|
|
4
|
+
import { createCar, listCars, removeCar } from '../server/cars'
|
|
5
|
+
|
|
6
|
+
export const Route = createFileRoute('/cars')({
|
|
7
|
+
component: CarsPage,
|
|
8
|
+
loader: async () => listCars(),
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
function CarsPage() {
|
|
12
|
+
const cars = Route.useLoaderData()
|
|
13
|
+
const router = useRouter()
|
|
14
|
+
const [brand, setBrand] = useState('')
|
|
15
|
+
const [model, setModel] = useState('')
|
|
16
|
+
const [year, setYear] = useState('')
|
|
17
|
+
const [error, setError] = useState('')
|
|
18
|
+
|
|
19
|
+
async function add(event: React.FormEvent) {
|
|
20
|
+
event.preventDefault()
|
|
21
|
+
setError('')
|
|
22
|
+
try {
|
|
23
|
+
await createCar({ data: { brand, model, year: Number(year) } })
|
|
24
|
+
setBrand('')
|
|
25
|
+
setModel('')
|
|
26
|
+
setYear('')
|
|
27
|
+
await router.invalidate()
|
|
28
|
+
} catch {
|
|
29
|
+
setError('Please provide a brand, model and a valid year.')
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function del(id: number) {
|
|
34
|
+
await removeCar({ data: id })
|
|
35
|
+
await router.invalidate()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className="mx-auto max-w-2xl p-8">
|
|
40
|
+
<h1 className="text-3xl font-bold">Cars</h1>
|
|
41
|
+
<p className="mt-1 text-gray-500">A full CRUD example backed by a server function.</p>
|
|
42
|
+
|
|
43
|
+
<form onSubmit={add} className="mt-6 flex flex-wrap gap-2">
|
|
44
|
+
<input
|
|
45
|
+
className="flex-1 rounded border border-gray-300 px-3 py-2"
|
|
46
|
+
placeholder="Brand"
|
|
47
|
+
value={brand}
|
|
48
|
+
onChange={(e) => setBrand(e.target.value)}
|
|
49
|
+
/>
|
|
50
|
+
<input
|
|
51
|
+
className="flex-1 rounded border border-gray-300 px-3 py-2"
|
|
52
|
+
placeholder="Model"
|
|
53
|
+
value={model}
|
|
54
|
+
onChange={(e) => setModel(e.target.value)}
|
|
55
|
+
/>
|
|
56
|
+
<input
|
|
57
|
+
className="w-24 rounded border border-gray-300 px-3 py-2"
|
|
58
|
+
placeholder="Year"
|
|
59
|
+
value={year}
|
|
60
|
+
onChange={(e) => setYear(e.target.value)}
|
|
61
|
+
/>
|
|
62
|
+
<button className="rounded bg-black px-4 py-2 font-medium text-white" type="submit">
|
|
63
|
+
Add
|
|
64
|
+
</button>
|
|
65
|
+
</form>
|
|
66
|
+
{error && <p className="mt-2 text-sm text-red-600">{error}</p>}
|
|
67
|
+
|
|
68
|
+
<ul className="mt-6 divide-y divide-gray-200">
|
|
69
|
+
{cars.length === 0 && <li className="py-3 text-gray-500">No cars yet — add one above.</li>}
|
|
70
|
+
{cars.map((car) => (
|
|
71
|
+
<li key={car.id} className="flex items-center justify-between py-3">
|
|
72
|
+
<span>
|
|
73
|
+
{car.brand} {car.model} <span className="text-gray-400">({car.year})</span>
|
|
74
|
+
</span>
|
|
75
|
+
<button
|
|
76
|
+
className="text-sm text-red-600 hover:underline"
|
|
77
|
+
type="button"
|
|
78
|
+
onClick={() => del(car.id)}
|
|
79
|
+
>
|
|
80
|
+
Delete
|
|
81
|
+
</button>
|
|
82
|
+
</li>
|
|
83
|
+
))}
|
|
84
|
+
</ul>
|
|
85
|
+
</div>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Link, createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
|
|
3
|
+
export const Route = createFileRoute('/')({ component: Home })
|
|
4
|
+
|
|
5
|
+
function Home() {
|
|
6
|
+
return (
|
|
7
|
+
<div className="mx-auto max-w-2xl p-8">
|
|
8
|
+
<h1 className="text-4xl font-bold">Welcome to TanStack Start</h1>
|
|
9
|
+
<p className="mt-4 text-lg text-gray-600">
|
|
10
|
+
Generated by create-softeneers-app. A fullstack React app with type-safe server functions.
|
|
11
|
+
</p>
|
|
12
|
+
<Link
|
|
13
|
+
to="/cars"
|
|
14
|
+
className="mt-6 inline-block rounded bg-black px-5 py-2.5 font-medium text-white"
|
|
15
|
+
>
|
|
16
|
+
Open the cars CRUD demo →
|
|
17
|
+
</Link>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createAuth } from '@softeneers/auth'
|
|
2
|
+
|
|
3
|
+
import { env } from './env'
|
|
4
|
+
|
|
5
|
+
// Email + password auth via better-auth (@softeneers/auth). With no `database`
|
|
6
|
+
// configured better-auth uses an in-memory store — fine for local dev; point it
|
|
7
|
+
// at your DB for persistence. Mounted at /api/auth/* in routes/api/auth/$.ts.
|
|
8
|
+
export const auth = createAuth({
|
|
9
|
+
secret: env.AUTH_SECRET,
|
|
10
|
+
baseURL: env.AUTH_BASE_URL,
|
|
11
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createServerFn } from '@tanstack/react-start'
|
|
2
|
+
|
|
3
|
+
import { parseNewCar } from '../cars/validate'
|
|
4
|
+
import { carStore } from './store'
|
|
5
|
+
|
|
6
|
+
// Server functions: type-safe RPC the client calls directly. Their bodies (and
|
|
7
|
+
// the store/db imports above) run only on the server and are stripped from the
|
|
8
|
+
// client bundle.
|
|
9
|
+
export const listCars = createServerFn({ method: 'GET' }).handler(async () => {
|
|
10
|
+
return carStore.list()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export const createCar = createServerFn({ method: 'POST' })
|
|
14
|
+
.validator((data: unknown) => parseNewCar(data))
|
|
15
|
+
.handler(async ({ data }) => {
|
|
16
|
+
return carStore.create(data)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export const removeCar = createServerFn({ method: 'POST' })
|
|
20
|
+
.validator((data: unknown) => {
|
|
21
|
+
const id = Number(data)
|
|
22
|
+
if (!Number.isInteger(id)) throw new Error('A numeric car id is required.')
|
|
23
|
+
return id
|
|
24
|
+
})
|
|
25
|
+
.handler(async ({ data }) => {
|
|
26
|
+
return carStore.remove(data)
|
|
27
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createDb } from '@softeneers/db'
|
|
2
|
+
|
|
3
|
+
import { env } from './env'
|
|
4
|
+
|
|
5
|
+
// Configured (not-yet-connected) Sequelize instance. Server-only.
|
|
6
|
+
export const sequelize = createDb({
|
|
7
|
+
host: env.DB_HOST,
|
|
8
|
+
port: env.DB_PORT,
|
|
9
|
+
database: env.DB_NAME,
|
|
10
|
+
username: env.DB_USER,
|
|
11
|
+
password: env.DB_PASSWORD,
|
|
12
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import 'dotenv/config'
|
|
2
|
+
|
|
3
|
+
import { createEnv, z } from '@softeneers/env'
|
|
4
|
+
|
|
5
|
+
// Server-only validated environment. Variables for a feature exist only when
|
|
6
|
+
// that toggle is enabled at generation time.
|
|
7
|
+
export const env = createEnv({
|
|
8
|
+
schema: {
|
|
9
|
+
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
|
|
10
|
+
// #if db
|
|
11
|
+
DB_HOST: z.string().default('127.0.0.1'),
|
|
12
|
+
DB_PORT: z.coerce.number().default(3306),
|
|
13
|
+
DB_NAME: z.string().default('app_dev'),
|
|
14
|
+
DB_USER: z.string().default('root'),
|
|
15
|
+
DB_PASSWORD: z.string().default(''),
|
|
16
|
+
// #endif
|
|
17
|
+
// #if auth
|
|
18
|
+
AUTH_SECRET: z.string().min(16).default('dev-secret-change-me-to-a-long-random-string'),
|
|
19
|
+
AUTH_BASE_URL: z.string().default('http://localhost:3000'),
|
|
20
|
+
// #endif
|
|
21
|
+
},
|
|
22
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import 'dotenv/config'
|
|
2
|
+
|
|
3
|
+
import { assertConnection } from '@softeneers/db'
|
|
4
|
+
|
|
5
|
+
import { sequelize } from '../db'
|
|
6
|
+
import '../store' // importing the store registers the Car model
|
|
7
|
+
|
|
8
|
+
const reset = process.argv.includes('--reset')
|
|
9
|
+
|
|
10
|
+
await assertConnection(sequelize)
|
|
11
|
+
await sequelize.sync({ force: reset })
|
|
12
|
+
console.log(reset ? 'Database reset — tables recreated.' : 'Database synced — tables ensured.')
|
|
13
|
+
await sequelize.close()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import 'dotenv/config'
|
|
2
|
+
|
|
3
|
+
import { assertConnection } from '@softeneers/db'
|
|
4
|
+
|
|
5
|
+
import { sequelize } from '../db'
|
|
6
|
+
import { carStore } from '../store'
|
|
7
|
+
|
|
8
|
+
await assertConnection(sequelize)
|
|
9
|
+
await sequelize.sync()
|
|
10
|
+
|
|
11
|
+
const existing = await carStore.list()
|
|
12
|
+
if (existing.length > 0) {
|
|
13
|
+
console.log(`Skipped seeding — ${existing.length} cars already present.`)
|
|
14
|
+
} else {
|
|
15
|
+
for (const car of [
|
|
16
|
+
{ brand: 'Toyota', model: 'Corolla', year: 2021 },
|
|
17
|
+
{ brand: 'Tesla', model: 'Model 3', year: 2023 },
|
|
18
|
+
{ brand: 'Ford', model: 'Mustang', year: 1969 },
|
|
19
|
+
]) {
|
|
20
|
+
await carStore.create(car)
|
|
21
|
+
}
|
|
22
|
+
console.log('Seeded 3 cars.')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
await sequelize.close()
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Car, NewCar } from '../cars/types'
|
|
2
|
+
|
|
3
|
+
// Server-only data layer behind the cars server functions. With `db` on it is
|
|
4
|
+
// backed by MySQL (Sequelize via @softeneers/db); with it off it is an in-memory
|
|
5
|
+
// Map. Both satisfy the same CarStore. This module is never bundled into the
|
|
6
|
+
// client — it is only reached from server functions.
|
|
7
|
+
export interface CarStore {
|
|
8
|
+
list(): Promise<Array<Car>>
|
|
9
|
+
get(id: number): Promise<Car | null>
|
|
10
|
+
create(input: NewCar): Promise<Car>
|
|
11
|
+
remove(id: number): Promise<boolean>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// #if db
|
|
15
|
+
import { DataTypes, Model } from '@softeneers/db'
|
|
16
|
+
|
|
17
|
+
import { sequelize } from './db'
|
|
18
|
+
|
|
19
|
+
class CarModel extends Model {
|
|
20
|
+
declare id: number
|
|
21
|
+
declare brand: string
|
|
22
|
+
declare model: string
|
|
23
|
+
declare year: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
CarModel.init(
|
|
27
|
+
{
|
|
28
|
+
id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
|
|
29
|
+
brand: { type: DataTypes.STRING, allowNull: false },
|
|
30
|
+
model: { type: DataTypes.STRING, allowNull: false },
|
|
31
|
+
year: { type: DataTypes.INTEGER, allowNull: false },
|
|
32
|
+
},
|
|
33
|
+
{ sequelize, modelName: 'Car', tableName: 'cars' },
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
export { CarModel }
|
|
37
|
+
|
|
38
|
+
const toCar = (m: CarModel): Car => ({ id: m.id, brand: m.brand, model: m.model, year: m.year })
|
|
39
|
+
|
|
40
|
+
export const carStore: CarStore = {
|
|
41
|
+
async list() {
|
|
42
|
+
return (await CarModel.findAll({ order: [['id', 'ASC']] })).map(toCar)
|
|
43
|
+
},
|
|
44
|
+
async get(id) {
|
|
45
|
+
const m = await CarModel.findByPk(id)
|
|
46
|
+
return m ? toCar(m) : null
|
|
47
|
+
},
|
|
48
|
+
async create(input) {
|
|
49
|
+
return toCar(await CarModel.create(input))
|
|
50
|
+
},
|
|
51
|
+
async remove(id) {
|
|
52
|
+
const m = await CarModel.findByPk(id)
|
|
53
|
+
if (!m) return false
|
|
54
|
+
await m.destroy()
|
|
55
|
+
return true
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
// #endif
|
|
59
|
+
// #if !db
|
|
60
|
+
let nextId = 1
|
|
61
|
+
const cars = new Map<number, Car>()
|
|
62
|
+
|
|
63
|
+
export const carStore: CarStore = {
|
|
64
|
+
async list() {
|
|
65
|
+
return [...cars.values()].sort((a, b) => a.id - b.id)
|
|
66
|
+
},
|
|
67
|
+
async get(id) {
|
|
68
|
+
return cars.get(id) ?? null
|
|
69
|
+
},
|
|
70
|
+
async create(input) {
|
|
71
|
+
const car: Car = { id: nextId++, ...input }
|
|
72
|
+
cars.set(car.id, car)
|
|
73
|
+
return car
|
|
74
|
+
},
|
|
75
|
+
async remove(id) {
|
|
76
|
+
return cars.delete(id)
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
// #endif
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["**/*.ts", "**/*.tsx"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"jsx": "react-jsx",
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"paths": {
|
|
8
|
+
"#/*": ["./src/*"],
|
|
9
|
+
"@/*": ["./src/*"]
|
|
10
|
+
},
|
|
11
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
12
|
+
"types": ["vite/client"],
|
|
13
|
+
|
|
14
|
+
/* Bundler mode */
|
|
15
|
+
"moduleResolution": "bundler",
|
|
16
|
+
"allowImportingTsExtensions": true,
|
|
17
|
+
"verbatimModuleSyntax": true,
|
|
18
|
+
"noEmit": true,
|
|
19
|
+
|
|
20
|
+
/* Linting */
|
|
21
|
+
"skipLibCheck": true,
|
|
22
|
+
"strict": true,
|
|
23
|
+
"noUnusedLocals": true,
|
|
24
|
+
"noUnusedParameters": true,
|
|
25
|
+
"noFallthroughCasesInSwitch": true,
|
|
26
|
+
"noUncheckedSideEffectImports": true
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import { devtools } from '@tanstack/devtools-vite'
|
|
3
|
+
|
|
4
|
+
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
|
|
5
|
+
|
|
6
|
+
import viteReact from '@vitejs/plugin-react'
|
|
7
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
8
|
+
|
|
9
|
+
const config = defineConfig({
|
|
10
|
+
resolve: { tsconfigPaths: true },
|
|
11
|
+
plugins: [devtools(), tailwindcss(), tanstackStart(), viteReact()],
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
export default config
|