Skip to content

Commit 2bff595

Browse files
committed
Refactoring the mega file
2 parents 9c0fb99 + ea946e4 commit 2bff595

File tree

13 files changed

+893
-646
lines changed

13 files changed

+893
-646
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,5 @@ app-js-tw
66
app-ts-tw
77
app-fr
88
app-fr-tw
9+
my-app
910
.DS_Store
10-
# Local Netlify folder
11-
.netlify

README.md

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,96 @@
11
# Create React App for TanStack Router
22

3-
This CLI applications builds Tanstack Start applications that are the functional equivalent of [Create React App](https://create-react-app.dev/).
3+
This CLI applications builds Tanstack Router applications that are the functional equivalent of [Create React App](https://create-react-app.dev/).
44

55
To help accelerate the migration away from `create-react-app` we created the `create-tsrouter-app` CLI which is a plug-n-play replacement for CRA.
66

7-
Instead of:
7+
## Quick Start
8+
9+
To maintain compatability with `create-react-app` you can build a new application by running:
10+
11+
| Command | Description |
12+
| -------------------------------------------------------------- | --------------------------- |
13+
| `npx create-tsrouter-app@latest my-app` | Create a new app |
14+
| `npx create-tsrouter-app@latest my-app --template file-router` | Create a new file based app |
15+
| `npx create-tsrouter-app@latest my-app --template typescript` | Create a new TypeScript app |
16+
| `npx create-tsrouter-app@latest my-app --template javascript` | Create a new JavaScript app |
17+
| `npx create-tsrouter-app@latest my-app --tailwind` | Add Tailwind CSS support |
18+
19+
If you don't specify a project name, the CLI will walk you through an interactive setup process:
820

921
```bash
10-
npx create-react-app my-app
22+
npx create-tsrouter-app@latest
1123
```
1224

13-
You can now run:
25+
This will start an interactive CLI that guides you through the setup process, allowing you to choose:
26+
27+
- Project Name
28+
- Router Type (File-based or Code-based routing)
29+
- TypeScript support
30+
- Tailwind CSS integration
31+
- Package manager
32+
- Git initialization
33+
34+
## Command Line Options
35+
36+
You can also use command line flags to specify your preferences directly:
1437

1538
```bash
16-
npx create-tsrouter-app@latest my-app
39+
npx create-tsrouter-app@latest my-app --template file-router --tailwind --package-manager pnpm
1740
```
1841

19-
Instead of using:
42+
Available options:
43+
44+
- `--template <type>`: Choose between `file-router`, `typescript`, or `javascript`
45+
- `--tailwind`: Enable Tailwind CSS
46+
- `--package-manager`: Specify your preferred package manager (`npm`, `yarn`, `pnpm`, or `bun`)
47+
- `--no-git`: Do not initialize a git repository
48+
49+
When using flags, the CLI will display which options were provided and only prompt for the remaining choices.
50+
51+
## Features
52+
53+
What you'll get is a Vite application that uses TanStack Router. All the files will still be in the same place as in CRA, but you'll get a fully functional Router setup under in `app/main.tsx`.
54+
55+
`create-tsrouter-app` is everything you loved about CRA but implemented with modern tools and best practices, on top of the popular TanStack set of libraries. Which includes [@tanstack/react-query](https://tanstack.com/query/latest) and [@tanstack/react-router](https://tanstack.com/router/latest).
56+
57+
## Routing Options
58+
59+
### File Based Routing (Recommended)
60+
61+
File Based Routing is the default option when using the interactive CLI. The location of the home page will be `app/routes/index.tsx`. This approach provides a more intuitive and maintainable way to structure your routes.
62+
63+
To explicitly choose File Based Routing, use:
2064

2165
```bash
22-
npx create-react-app my-app --template typescript
66+
npx create-tsrouter-app@latest my-app --template file-router
2367
```
2468

25-
To create a SPA application using TypeScript. You can now run:
69+
### Code Based Routing
70+
71+
If you prefer traditional code-based routing, you can select it in the interactive CLI or specify it by using either the `typescript` or `javascript` template:
2672

2773
```bash
2874
npx create-tsrouter-app@latest my-app --template typescript
2975
```
3076

31-
What you'll get is a Vite application that uses TanStack Router. All the files will still be in the same place as in CRA, but you'll get a fully functional Router setup under in `app/main.tsx`.
77+
## Additional Configuration
3278

33-
`create-tsrouter-app` is everything you loved about CRA but implemented with modern tools and best practices, on top of the popular TanStack set of libraries. Which includes [@tanstack/react-query](https://tanstack.com/query/latest) and [@tanstack/react-router](https://tanstack.com/router/latest).
79+
### TypeScript
80+
81+
- File Based Routing always uses TypeScript
82+
- For Code Based Routing, you can choose between TypeScript and JavaScript
83+
- Enable TypeScript explicitly with `--template typescript`
3484

35-
If you want Tailwind then just add `--tailwind` and that will automatically configure [Tailwind V4](https://tailwindcss.com/).
85+
### Tailwind CSS
3686

37-
You can also specify your preferred package manager with `--package-manager` such as `npm`, `bun`, `yarn`, or `pnpm`.
87+
Enable Tailwind CSS either through the interactive CLI or by adding the `--tailwind` flag. This will automatically configure [Tailwind V4](https://tailwindcss.com/).
3888

39-
Extensive documentation on using the TanStack Router, migrating to a File Base Routing approach, as well as integrating [@tanstack/react-query](https://tanstack.com/query/latest) and [@tanstack/store](https://tanstack.com/store/latest) be found in the generated `README.md` for your project.
89+
### Package Manager
4090

41-
## File Based Routing
91+
Choose your preferred package manager (`npm`, `bun`, `yarn`, or `pnpm`) either through the interactive CLI or using the `--package-manager` flag.
4292

43-
By default `create-tsrouter-app` will create a Code Based Routing application. If you want to use File Based Routing then you can specify `--template file-router`. The location of the home page will be `app/routes/index.tsx`.
93+
Extensive documentation on using the TanStack Router, migrating to a File Base Routing approach, as well as integrating [@tanstack/react-query](https://tanstack.com/query/latest) and [@tanstack/store](https://tanstack.com/store/latest) can be found in the generated `README.md` for your project.
4494

4595
# Contributing
4696

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
22
"name": "create-tsrouter-app",
3-
"version": "0.1.2",
3+
"version": "0.2.0",
44
"description": "Tanstack Application Builder",
55
"bin": "./dist/index.js",
66
"type": "module",
77
"scripts": {
88
"build": "tsc",
99
"start": "tsc && node dist/index.js",
10-
"test": "echo \"Error: no test specified\" && exit 0",
10+
"test": "npm run test:lint",
1111
"cipublish": "node scripts/publish.js",
1212
"test:lint": "eslint ./src"
1313
},

src/add-ons.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { readFile } from 'node:fs/promises'
2+
import { existsSync, readdirSync, statSync } from 'node:fs'
3+
import { resolve } from 'node:path'
4+
import { fileURLToPath } from 'node:url'
5+
6+
export type AddOn = {
7+
id: string
8+
name: string
9+
description: string
10+
link: string
11+
main?: Array<{
12+
imports: Array<string>
13+
initialize: Array<string>
14+
providers: Array<{
15+
open: string
16+
close: string
17+
}>
18+
}>
19+
layout?: {
20+
imports: Array<string>
21+
jsx: string
22+
}
23+
routes: Array<{
24+
url: string
25+
name: string
26+
}>
27+
userUi?: {
28+
import: string
29+
jsx: string
30+
}
31+
directory: string
32+
packageAdditions: {
33+
dependencies?: Record<string, string>
34+
devDependencies?: Record<string, string>
35+
scripts?: Record<string, string>
36+
}
37+
command?: {
38+
command: string
39+
args?: Array<string>
40+
}
41+
readme?: string
42+
phase: 'setup' | 'add-on'
43+
shadcnComponents?: Array<string>
44+
warning?: string
45+
}
46+
47+
function isDirectory(path: string): boolean {
48+
return statSync(path).isDirectory()
49+
}
50+
51+
export async function getAllAddOns(): Promise<Array<AddOn>> {
52+
const addOnsBase = fileURLToPath(
53+
new URL('../templates/add-ons', import.meta.url),
54+
)
55+
56+
const addOns: Array<AddOn> = []
57+
58+
for (const dir of await readdirSync(addOnsBase).filter((file) =>
59+
isDirectory(resolve(addOnsBase, file)),
60+
)) {
61+
const filePath = resolve(addOnsBase, dir, 'info.json')
62+
const fileContent = await readFile(filePath, 'utf-8')
63+
64+
let packageAdditions: Record<string, string> = {}
65+
if (existsSync(resolve(addOnsBase, dir, 'package.json'))) {
66+
packageAdditions = JSON.parse(
67+
await readFile(resolve(addOnsBase, dir, 'package.json'), 'utf-8'),
68+
)
69+
}
70+
71+
let readme: string | undefined
72+
if (existsSync(resolve(addOnsBase, dir, 'README.md'))) {
73+
readme = await readFile(resolve(addOnsBase, dir, 'README.md'), 'utf-8')
74+
}
75+
76+
addOns.push({
77+
id: dir,
78+
...JSON.parse(fileContent),
79+
directory: resolve(addOnsBase, dir),
80+
packageAdditions,
81+
readme,
82+
})
83+
}
84+
return addOns
85+
}

src/cli.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Command, InvalidArgumentError } from 'commander'
2+
import { log } from '@clack/prompts'
3+
4+
import { createApp } from './create-app.js'
5+
import { normalizeOptions, promptForOptions } from './options.js'
6+
import { SUPPORTED_PACKAGE_MANAGERS } from './package-manager.js'
7+
8+
import type { PackageManager } from './package-manager.js'
9+
import type { CliOptions } from './types.js'
10+
11+
export function cli() {
12+
const program = new Command()
13+
14+
program
15+
.name('create-tsrouter-app')
16+
.description('CLI to create a new TanStack application')
17+
.argument('[project-name]', 'name of the project')
18+
.option('--no-git', 'do not create a git repository')
19+
.option<'typescript' | 'javascript' | 'file-router'>(
20+
'--template <type>',
21+
'project template (typescript, javascript, file-router)',
22+
(value) => {
23+
if (
24+
value !== 'typescript' &&
25+
value !== 'javascript' &&
26+
value !== 'file-router'
27+
) {
28+
throw new InvalidArgumentError(
29+
`Invalid template: ${value}. Only the following are allowed: typescript, javascript, file-router`,
30+
)
31+
}
32+
return value
33+
},
34+
)
35+
.option<PackageManager>(
36+
`--package-manager <${SUPPORTED_PACKAGE_MANAGERS.join('|')}>`,
37+
`Explicitly tell the CLI to use this package manager`,
38+
(value) => {
39+
if (!SUPPORTED_PACKAGE_MANAGERS.includes(value as PackageManager)) {
40+
throw new InvalidArgumentError(
41+
`Invalid package manager: ${value}. Only the following are allowed: ${SUPPORTED_PACKAGE_MANAGERS.join(
42+
', ',
43+
)}`,
44+
)
45+
}
46+
return value as PackageManager
47+
},
48+
)
49+
.option('--tailwind', 'add Tailwind CSS', false)
50+
.option('--add-ons', 'pick from a list of available add-ons', false)
51+
.action(async (projectName: string, options: CliOptions) => {
52+
try {
53+
const cliOptions = {
54+
projectName,
55+
...options,
56+
} as CliOptions
57+
let finalOptions = normalizeOptions(cliOptions)
58+
if (!finalOptions) {
59+
finalOptions = await promptForOptions(cliOptions)
60+
}
61+
await createApp(finalOptions)
62+
} catch (error) {
63+
log.error(
64+
error instanceof Error ? error.message : 'An unknown error occurred',
65+
)
66+
process.exit(1)
67+
}
68+
})
69+
70+
program.parse()
71+
}

src/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const CODE_ROUTER = 'code-router'
2+
export const FILE_ROUTER = 'file-router'

0 commit comments

Comments
 (0)