create-rari-app 0.1.3
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/dist/index.js +150 -0
- package/package.json +59 -0
- package/templates/default/README.md +122 -0
- package/templates/default/index.html +12 -0
- package/templates/default/package.json +39 -0
- package/templates/default/railway.json +20 -0
- package/templates/default/render.yaml +14 -0
- package/templates/default/src/App.tsx +19 -0
- package/templates/default/src/components/ServerTime.tsx +28 -0
- package/templates/default/src/components/Welcome.tsx +39 -0
- package/templates/default/src/main.tsx +68 -0
- package/templates/default/src/pages/about.tsx +248 -0
- package/templates/default/src/pages/examples.tsx +238 -0
- package/templates/default/src/pages/index.tsx +216 -0
- package/templates/default/src/styles/index.css +28 -0
- package/templates/default/src/vite-env.d.ts +1 -0
- package/templates/default/tsconfig.app.json +28 -0
- package/templates/default/tsconfig.json +11 -0
- package/templates/default/tsconfig.node.json +26 -0
- package/templates/default/vite.config.ts +8 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import { cancel, confirm, intro, isCancel, outro, select, spinner, text } from "@clack/prompts";
|
|
7
|
+
import pc from "picocolors";
|
|
8
|
+
|
|
9
|
+
//#region src/index.ts
|
|
10
|
+
const templates = { default: {
|
|
11
|
+
name: "Default",
|
|
12
|
+
description: "A clean starter with React Server Components"
|
|
13
|
+
} };
|
|
14
|
+
const packageManagers = {
|
|
15
|
+
pnpm: "pnpm",
|
|
16
|
+
npm: "npm",
|
|
17
|
+
yarn: "yarn",
|
|
18
|
+
bun: "bun"
|
|
19
|
+
};
|
|
20
|
+
async function main() {
|
|
21
|
+
console.clear();
|
|
22
|
+
intro(pc.bgCyan(pc.black(" create-rari-app ")));
|
|
23
|
+
const projectName = await text({
|
|
24
|
+
message: "What is your project named?",
|
|
25
|
+
placeholder: "my-rari-app",
|
|
26
|
+
validate: (value) => {
|
|
27
|
+
if (!value) return "Please enter a project name.";
|
|
28
|
+
if (value.includes(" ")) return "Project name cannot contain spaces.";
|
|
29
|
+
if (!/^[\w-]+$/.test(value)) return "Project name can only contain letters, numbers, hyphens, and underscores.";
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
if (isCancel(projectName)) {
|
|
33
|
+
cancel("Operation cancelled.");
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
const template = await select({
|
|
37
|
+
message: "Which template would you like to use?",
|
|
38
|
+
options: Object.entries(templates).map(([key, { name, description }]) => ({
|
|
39
|
+
value: key,
|
|
40
|
+
label: name,
|
|
41
|
+
hint: description
|
|
42
|
+
}))
|
|
43
|
+
});
|
|
44
|
+
if (isCancel(template)) {
|
|
45
|
+
cancel("Operation cancelled.");
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
const packageManager = await select({
|
|
49
|
+
message: "Which package manager would you like to use?",
|
|
50
|
+
options: Object.entries(packageManagers).map(([key, value]) => ({
|
|
51
|
+
value: key,
|
|
52
|
+
label: value
|
|
53
|
+
}))
|
|
54
|
+
});
|
|
55
|
+
if (isCancel(packageManager)) {
|
|
56
|
+
cancel("Operation cancelled.");
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
const installDeps = await confirm({
|
|
60
|
+
message: "Install dependencies?",
|
|
61
|
+
initialValue: true
|
|
62
|
+
});
|
|
63
|
+
if (isCancel(installDeps)) {
|
|
64
|
+
cancel("Operation cancelled.");
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
const options = {
|
|
68
|
+
name: projectName,
|
|
69
|
+
template,
|
|
70
|
+
packageManager,
|
|
71
|
+
installDeps
|
|
72
|
+
};
|
|
73
|
+
await createProject(options);
|
|
74
|
+
outro(pc.green("🎉 Project created successfully!"));
|
|
75
|
+
console.log();
|
|
76
|
+
console.log(pc.cyan("Next steps:"));
|
|
77
|
+
console.log(pc.gray(` cd ${options.name}`));
|
|
78
|
+
if (!options.installDeps) console.log(pc.gray(` ${options.packageManager} install`));
|
|
79
|
+
console.log(pc.gray(` ${options.packageManager} run dev`));
|
|
80
|
+
console.log();
|
|
81
|
+
}
|
|
82
|
+
async function createProject(options) {
|
|
83
|
+
const projectPath = join(process.cwd(), options.name);
|
|
84
|
+
const templatePath = join(import.meta.dirname, "..", "templates", options.template);
|
|
85
|
+
const s = spinner();
|
|
86
|
+
try {
|
|
87
|
+
s.start("Creating project structure...");
|
|
88
|
+
await mkdir(projectPath, { recursive: true });
|
|
89
|
+
await copyTemplate(templatePath, projectPath, options);
|
|
90
|
+
s.stop("Project structure created.");
|
|
91
|
+
if (options.installDeps) {
|
|
92
|
+
s.start("Installing dependencies...");
|
|
93
|
+
await installDependencies(projectPath, options.packageManager);
|
|
94
|
+
s.stop("Dependencies installed.");
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
s.stop("Error occurred.");
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function copyTemplate(templatePath, projectPath, options) {
|
|
102
|
+
const templateFiles = [
|
|
103
|
+
"package.json",
|
|
104
|
+
"vite.config.ts",
|
|
105
|
+
"tsconfig.json",
|
|
106
|
+
"tsconfig.app.json",
|
|
107
|
+
"tsconfig.node.json",
|
|
108
|
+
"index.html",
|
|
109
|
+
"src/main.tsx",
|
|
110
|
+
"src/App.tsx",
|
|
111
|
+
"src/vite-env.d.ts",
|
|
112
|
+
"src/styles/index.css",
|
|
113
|
+
"src/components/Welcome.tsx",
|
|
114
|
+
"src/components/ServerTime.tsx",
|
|
115
|
+
".gitignore"
|
|
116
|
+
];
|
|
117
|
+
await mkdir(join(projectPath, "src", "components"), { recursive: true });
|
|
118
|
+
await mkdir(join(projectPath, "src", "styles"), { recursive: true });
|
|
119
|
+
for (const file of templateFiles) {
|
|
120
|
+
const sourcePath = join(templatePath, file);
|
|
121
|
+
const destPath = join(projectPath, file);
|
|
122
|
+
try {
|
|
123
|
+
let content = await readFile(sourcePath, "utf-8");
|
|
124
|
+
content = content.replace(/\{\{PROJECT_NAME\}\}/g, options.name).replace(/\{\{PACKAGE_MANAGER\}\}/g, options.packageManager);
|
|
125
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
126
|
+
await writeFile(destPath, content);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.warn(`Warning: Could not copy ${file}:`, error);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function installDependencies(projectPath, packageManager) {
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
const child = spawn(packageManager, ["install"], {
|
|
135
|
+
cwd: projectPath,
|
|
136
|
+
stdio: "pipe"
|
|
137
|
+
});
|
|
138
|
+
child.on("close", (code) => {
|
|
139
|
+
if (code === 0) resolve();
|
|
140
|
+
else reject(/* @__PURE__ */ new Error(`${packageManager} install failed with code ${code}`));
|
|
141
|
+
});
|
|
142
|
+
child.on("error", reject);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
main().catch((error) => {
|
|
146
|
+
console.error(pc.red("Error:"), error.message);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
//#endregion
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-rari-app",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.3",
|
|
5
|
+
"description": "Create Runtime Accelerated Rendering Infrastructure (Rari) applications with no build configuration",
|
|
6
|
+
"author": "Ryan Skinner",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/rari-build/rari#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/rari-build/rari.git",
|
|
12
|
+
"directory": "packages/create-rari-app"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/rari-build/rari/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"rari",
|
|
19
|
+
"react",
|
|
20
|
+
"scaffolding",
|
|
21
|
+
"cli",
|
|
22
|
+
"create-app",
|
|
23
|
+
"generator",
|
|
24
|
+
"boilerplate",
|
|
25
|
+
"template",
|
|
26
|
+
"server-components",
|
|
27
|
+
"rust",
|
|
28
|
+
"framework",
|
|
29
|
+
"zero-config",
|
|
30
|
+
"starter",
|
|
31
|
+
"project-template"
|
|
32
|
+
],
|
|
33
|
+
"bin": {
|
|
34
|
+
"create-rari-app": "dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"templates"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "pnpm clean && pnpm typecheck && tsdown",
|
|
42
|
+
"dev": "tsdown --watch",
|
|
43
|
+
"clean": "rm -rf dist",
|
|
44
|
+
"typecheck": "tsgo",
|
|
45
|
+
"lint": "oxlint && eslint",
|
|
46
|
+
"lint:fix": "oxlint --fix && eslint --fix"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@clack/prompts": "^0.8.2",
|
|
50
|
+
"picocolors": "^1.1.1"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^24.1.0",
|
|
54
|
+
"@typescript/native-preview": "7.0.0-dev.20250611.1",
|
|
55
|
+
"eslint": "^9.32.0",
|
|
56
|
+
"oxlint": "^1.8.0",
|
|
57
|
+
"tsdown": "^0.12.9"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
A high-performance React Server Components application powered by [Rari](https://rari.dev).
|
|
4
|
+
|
|
5
|
+
## 🚀 Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies
|
|
9
|
+
{{INSTALL_COMMAND}}
|
|
10
|
+
|
|
11
|
+
# Start development server
|
|
12
|
+
{{PACKAGE_MANAGER}} run dev
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Visit [http://localhost:5173](http://localhost:5173) to see your app.
|
|
16
|
+
|
|
17
|
+
## 🚀 Deploy to the Cloud
|
|
18
|
+
|
|
19
|
+
This Rari application is pre-configured for cloud deployment.
|
|
20
|
+
|
|
21
|
+
### 🚂 Railway
|
|
22
|
+
|
|
23
|
+
### Quick Deploy
|
|
24
|
+
|
|
25
|
+
1. **Push to GitHub**:
|
|
26
|
+
```bash
|
|
27
|
+
git add .
|
|
28
|
+
git commit -m "Initial commit"
|
|
29
|
+
git push origin main
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
2. **Deploy to Railway**:
|
|
33
|
+
- Go to [railway.app](https://railway.app)
|
|
34
|
+
- Create new project → "Deploy from GitHub repo"
|
|
35
|
+
- Select your repository
|
|
36
|
+
- Click "Deploy Now"
|
|
37
|
+
|
|
38
|
+
3. **Generate Domain**:
|
|
39
|
+
- In Railway dashboard → Settings → Networking
|
|
40
|
+
- Click "Generate Domain"
|
|
41
|
+
- Your app will be live! 🎉
|
|
42
|
+
|
|
43
|
+
### Alternative: Setup Railway from CLI
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Configure Railway deployment files
|
|
47
|
+
{{PACKAGE_MANAGER}} run deploy:railway
|
|
48
|
+
|
|
49
|
+
# Follow the instructions to deploy
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 🎨 Render
|
|
53
|
+
|
|
54
|
+
1. **Push to GitHub**:
|
|
55
|
+
```bash
|
|
56
|
+
git add .
|
|
57
|
+
git commit -m "Initial commit"
|
|
58
|
+
git push origin main
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
2. **Deploy to Render**:
|
|
62
|
+
- Go to [render.com](https://render.com)
|
|
63
|
+
- Create new "Web Service"
|
|
64
|
+
- Connect your GitHub repository
|
|
65
|
+
- Render auto-detects Node.js and uses `render.yaml`
|
|
66
|
+
- Click "Create Web Service"
|
|
67
|
+
|
|
68
|
+
### Alternative: Setup Render from CLI
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Configure Render deployment files
|
|
72
|
+
{{PACKAGE_MANAGER}} run deploy:render
|
|
73
|
+
|
|
74
|
+
# Follow the instructions to deploy
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 📜 Available Scripts
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Development
|
|
81
|
+
{{PACKAGE_MANAGER}} run dev # Start development server
|
|
82
|
+
{{PACKAGE_MANAGER}} run build # Build for production
|
|
83
|
+
|
|
84
|
+
# Production
|
|
85
|
+
{{PACKAGE_MANAGER}} start # Start production server
|
|
86
|
+
{{PACKAGE_MANAGER}} run start:local # Start local production server
|
|
87
|
+
|
|
88
|
+
# Deployment
|
|
89
|
+
{{PACKAGE_MANAGER}} run deploy:railway # Setup Railway deployment
|
|
90
|
+
{{PACKAGE_MANAGER}} run deploy:render # Setup Render deployment
|
|
91
|
+
|
|
92
|
+
# Code Quality
|
|
93
|
+
{{PACKAGE_MANAGER}} run lint # Run linters
|
|
94
|
+
{{PACKAGE_MANAGER}} run typecheck # Run TypeScript checks
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 🌍 Environment Variables
|
|
98
|
+
|
|
99
|
+
Cloud platforms automatically provide:
|
|
100
|
+
- `PORT` - Server port (platform assigns this)
|
|
101
|
+
- `NODE_ENV=production` - Production mode
|
|
102
|
+
|
|
103
|
+
Optional variables you can set:
|
|
104
|
+
- `RUST_LOG=debug` - Rust logging level
|
|
105
|
+
|
|
106
|
+
## 🏗️ Architecture
|
|
107
|
+
|
|
108
|
+
- **⚡ Rust Runtime**: Native performance with zero-cost abstractions
|
|
109
|
+
- **🚀 React Server Components**: True server-side rendering
|
|
110
|
+
- **📁 File-based Routing**: Automatic route generation
|
|
111
|
+
- **🎯 Zero Configuration**: Works out of the box
|
|
112
|
+
|
|
113
|
+
## 📚 Learn More
|
|
114
|
+
|
|
115
|
+
- [Rari Documentation](https://rari.dev)
|
|
116
|
+
- [Railway Documentation](https://docs.railway.app)
|
|
117
|
+
- [Render Documentation](https://render.com/docs)
|
|
118
|
+
- [React Server Components](https://react.dev/reference/react/use-server)
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
Built with ❤️ using [Rari](https://rari.dev)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{PROJECT_NAME}}</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"private": true,
|
|
6
|
+
"description": "A Runtime Accelerated Rendering Infrastructure (Rari) application",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20.0.0"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "{{PACKAGE_MANAGER}} clean && {{PACKAGE_MANAGER}} typecheck && vite build",
|
|
12
|
+
"dev": "NODE_OPTIONS='--max-http-header-size=1048576' vite",
|
|
13
|
+
"start": "rari start",
|
|
14
|
+
"start:local": "rari start",
|
|
15
|
+
"deploy:railway": "rari deploy railway",
|
|
16
|
+
"deploy:render": "rari deploy render",
|
|
17
|
+
"clean": "rm -rf dist",
|
|
18
|
+
"lint": "oxlint && eslint",
|
|
19
|
+
"lint:fix": "oxlint --fix && eslint --fix",
|
|
20
|
+
"typecheck": "tsgo"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"rari": "latest",
|
|
24
|
+
"react": "^19.1.0",
|
|
25
|
+
"react-dom": "^19.1.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@tailwindcss/vite": "^4.1.11",
|
|
29
|
+
"@types/node": "^24.1.0",
|
|
30
|
+
"@types/react": "^19.1.8",
|
|
31
|
+
"@types/react-dom": "^19.1.6",
|
|
32
|
+
"@typescript/native-preview": "7.0.0-dev.20250611.1",
|
|
33
|
+
"@vitejs/plugin-react-oxc": "^0.2.3",
|
|
34
|
+
"eslint": "^9.32.0",
|
|
35
|
+
"oxlint": "^1.8.0",
|
|
36
|
+
"rolldown-vite": "^7.0.11",
|
|
37
|
+
"tailwindcss": "^4.1.11"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://railway.app/railway.schema.json",
|
|
3
|
+
"build": {
|
|
4
|
+
"builder": "NIXPACKS"
|
|
5
|
+
},
|
|
6
|
+
"deploy": {
|
|
7
|
+
"startCommand": "npm start",
|
|
8
|
+
"healthcheckPath": "/",
|
|
9
|
+
"healthcheckTimeout": 300,
|
|
10
|
+
"restartPolicyType": "ALWAYS"
|
|
11
|
+
},
|
|
12
|
+
"environments": {
|
|
13
|
+
"production": {
|
|
14
|
+
"variables": {
|
|
15
|
+
"NODE_ENV": "production",
|
|
16
|
+
"RUST_LOG": "info"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
services:
|
|
2
|
+
- type: web
|
|
3
|
+
name: '{{PROJECT_NAME}}'
|
|
4
|
+
runtime: node
|
|
5
|
+
env: node
|
|
6
|
+
plan: free
|
|
7
|
+
buildCommand: '{{INSTALL_COMMAND}}'
|
|
8
|
+
startCommand: '{{PACKAGE_MANAGER}} start'
|
|
9
|
+
healthCheckPath: /
|
|
10
|
+
envVars:
|
|
11
|
+
- key: NODE_ENV
|
|
12
|
+
value: production
|
|
13
|
+
- key: RUST_LOG
|
|
14
|
+
value: info
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RouterProvider } from 'rari/client'
|
|
2
|
+
import { routes } from './.rari/routes'
|
|
3
|
+
|
|
4
|
+
function App() {
|
|
5
|
+
return (
|
|
6
|
+
<RouterProvider
|
|
7
|
+
routes={routes}
|
|
8
|
+
config={{
|
|
9
|
+
basePath: '',
|
|
10
|
+
useHash: false,
|
|
11
|
+
caseSensitive: false,
|
|
12
|
+
}}
|
|
13
|
+
>
|
|
14
|
+
<div id="app" />
|
|
15
|
+
</RouterProvider>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default App
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
|
|
3
|
+
// This is a React Server Component
|
|
4
|
+
export default async function ServerTime() {
|
|
5
|
+
// This runs on the server!
|
|
6
|
+
const timestamp = new Date().toISOString()
|
|
7
|
+
|
|
8
|
+
// Simulate some async work
|
|
9
|
+
await new Promise(resolve => setTimeout(resolve, 100))
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className="bg-gradient-to-r from-green-50 to-blue-50 rounded-xl p-8 shadow-sm border border-green-200">
|
|
13
|
+
<h2 className="text-2xl font-semibold mb-4 text-gray-900">
|
|
14
|
+
⚡ Server Component
|
|
15
|
+
</h2>
|
|
16
|
+
<p className="text-gray-600 mb-4">
|
|
17
|
+
This component renders on the server with Rari's high-performance Rust runtime.
|
|
18
|
+
</p>
|
|
19
|
+
<div className="bg-white rounded-lg p-4 border">
|
|
20
|
+
<p className="text-sm text-gray-500 mb-1">Server timestamp:</p>
|
|
21
|
+
<p className="font-mono text-lg text-gray-900">{timestamp}</p>
|
|
22
|
+
</div>
|
|
23
|
+
<p className="text-xs text-gray-500 mt-4">
|
|
24
|
+
💡 This timestamp was generated on the server and won't change on refresh.
|
|
25
|
+
</p>
|
|
26
|
+
</div>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export default function Welcome() {
|
|
2
|
+
return (
|
|
3
|
+
<div className="bg-white rounded-xl p-8 shadow-sm">
|
|
4
|
+
<h2 className="text-2xl font-semibold mb-4 text-gray-900">
|
|
5
|
+
🎉 Welcome to Rari!
|
|
6
|
+
</h2>
|
|
7
|
+
<p className="text-gray-600 mb-4">
|
|
8
|
+
You've successfully created a new Rari application. This is a client component
|
|
9
|
+
that renders on both server and client.
|
|
10
|
+
</p>
|
|
11
|
+
<div className="space-y-2 text-sm text-gray-500">
|
|
12
|
+
<p>
|
|
13
|
+
🚀
|
|
14
|
+
<strong>High-performance</strong>
|
|
15
|
+
{' '}
|
|
16
|
+
React Server Components
|
|
17
|
+
</p>
|
|
18
|
+
<p>
|
|
19
|
+
⚡
|
|
20
|
+
<strong>Optimized</strong>
|
|
21
|
+
{' '}
|
|
22
|
+
Rust runtime
|
|
23
|
+
</p>
|
|
24
|
+
<p>
|
|
25
|
+
🔥
|
|
26
|
+
<strong>Hot module</strong>
|
|
27
|
+
{' '}
|
|
28
|
+
reloading
|
|
29
|
+
</p>
|
|
30
|
+
<p>
|
|
31
|
+
📦
|
|
32
|
+
<strong>Zero config</strong>
|
|
33
|
+
{' '}
|
|
34
|
+
setup
|
|
35
|
+
</p>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import ReactDOM from 'react-dom/client'
|
|
3
|
+
import App from './App'
|
|
4
|
+
import './styles/index.css'
|
|
5
|
+
|
|
6
|
+
import 'virtual:rsc-integration'
|
|
7
|
+
import 'virtual:rsc-client-components'
|
|
8
|
+
|
|
9
|
+
export function RouterErrorBoundary({
|
|
10
|
+
children,
|
|
11
|
+
}: {
|
|
12
|
+
children: React.ReactNode
|
|
13
|
+
}) {
|
|
14
|
+
const [hasError, setHasError] = React.useState(false)
|
|
15
|
+
const [error, setError] = React.useState<Error | null>(null)
|
|
16
|
+
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
const handleError = (event: ErrorEvent) => {
|
|
19
|
+
if (
|
|
20
|
+
event.error?.message?.includes('router')
|
|
21
|
+
|| event.error?.message?.includes('navigation')
|
|
22
|
+
) {
|
|
23
|
+
setHasError(true)
|
|
24
|
+
setError(event.error)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
window.addEventListener('error', handleError)
|
|
29
|
+
return () => window.removeEventListener('error', handleError)
|
|
30
|
+
}, [])
|
|
31
|
+
|
|
32
|
+
if (hasError) {
|
|
33
|
+
return (
|
|
34
|
+
<div className="min-h-screen bg-red-50 flex items-center justify-center p-8">
|
|
35
|
+
<div className="bg-white rounded-xl p-8 shadow-sm border border-red-200 max-w-2xl">
|
|
36
|
+
<h1 className="text-2xl font-bold text-red-900 mb-4">Router Error</h1>
|
|
37
|
+
<p className="text-red-700 mb-4">
|
|
38
|
+
There was an error with the routing system:
|
|
39
|
+
</p>
|
|
40
|
+
<pre className="bg-red-100 p-4 rounded-lg text-sm text-red-800 overflow-auto">
|
|
41
|
+
{error?.message || 'Unknown router error'}
|
|
42
|
+
</pre>
|
|
43
|
+
<button
|
|
44
|
+
type="button"
|
|
45
|
+
onClick={() => {
|
|
46
|
+
setHasError(false)
|
|
47
|
+
setError(null)
|
|
48
|
+
window.location.reload()
|
|
49
|
+
}}
|
|
50
|
+
className="mt-4 px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
|
|
51
|
+
>
|
|
52
|
+
Reload Page
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return <>{children}</>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
63
|
+
<React.StrictMode>
|
|
64
|
+
<RouterErrorBoundary>
|
|
65
|
+
<App />
|
|
66
|
+
</RouterErrorBoundary>
|
|
67
|
+
</React.StrictMode>,
|
|
68
|
+
)
|