revine 0.8.0 → 0.9.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.
Files changed (55) hide show
  1. package/README.md +81 -81
  2. package/dist/commands/createProject.js +20 -2
  3. package/dist/config/package.js +4 -0
  4. package/dist/index.js +64 -2
  5. package/dist/prompts/project.js +11 -8
  6. package/dist/runtime/bundler/defaults/vite.js +17 -0
  7. package/dist/runtime/bundler/generateConfig.js +27 -0
  8. package/dist/runtime/bundler/revinePlugin.js +68 -0
  9. package/dist/runtime/bundler/utils/loadUserConfig.js +20 -0
  10. package/dist/runtime/bundler/vite.config.js +7 -0
  11. package/dist/runtime/bundler/viteLoggerPlugin.js +27 -0
  12. package/dist/runtime/routing/fileBased.js +29 -0
  13. package/dist/setup/dependencies.js +8 -0
  14. package/dist/setup/tailwind.js +128 -133
  15. package/package.json +44 -29
  16. package/src/commands/createProject.ts +88 -65
  17. package/src/config/package.ts +28 -23
  18. package/src/config/readme.ts +7 -7
  19. package/src/config/vite.ts +19 -19
  20. package/src/index.ts +91 -15
  21. package/src/prompts/git.ts +61 -61
  22. package/src/prompts/index.ts +3 -3
  23. package/src/prompts/project.ts +34 -31
  24. package/src/prompts/tailwind.ts +13 -13
  25. package/{template/.revine → src/runtime}/bundler/defaults/vite.ts +18 -18
  26. package/src/runtime/bundler/generateConfig.ts +36 -0
  27. package/src/runtime/bundler/revinePlugin.ts +71 -0
  28. package/src/runtime/bundler/utils/loadUserConfig.ts +19 -0
  29. package/{template/.revine → src/runtime}/bundler/vite.config.ts +8 -8
  30. package/{template/.revine → src/runtime}/bundler/viteLoggerPlugin.ts +33 -33
  31. package/{template/.revine → src/runtime}/routing/fileBased.tsx +46 -44
  32. package/src/setup/dependencies.ts +26 -16
  33. package/src/setup/tailwind.ts +151 -163
  34. package/src/utils/file.ts +9 -9
  35. package/src/utils/logger.ts +9 -9
  36. package/template/README.md +62 -62
  37. package/template/index.html +19 -19
  38. package/template/package.json +21 -24
  39. package/template/revine.config.ts +13 -13
  40. package/template/src/NotFound.tsx +13 -13
  41. package/template/src/pages/index.tsx +62 -62
  42. package/template/src/root.tsx +14 -14
  43. package/template/src/styles/global.css +191 -191
  44. package/template/tsconfig.json +20 -24
  45. package/tsconfig.json +15 -14
  46. package/dist/commands/create.js +0 -65
  47. package/dist/installers/dependencies.js +0 -15
  48. package/dist/lib/setup/directory.js +0 -21
  49. package/dist/lib/setup/package.js +0 -17
  50. package/dist/lib/setup/tailwind.js +0 -22
  51. package/dist/lib/utils/exec.js +0 -15
  52. package/dist/lib/utils/paths.js +0 -6
  53. package/template/.revine/bundler/generateConfig.ts +0 -18
  54. package/template/.revine/bundler/utils/loadUserConfig.ts +0 -13
  55. /package/{template/.revine → src/runtime}/bundler/types/vite-env.d.ts +0 -0
@@ -1,44 +1,46 @@
1
- import { createBrowserRouter } from "react-router-dom";
2
- import { lazy, Suspense, ComponentType } from "react";
3
- import NotFound from "../../src/NotFound";
4
-
5
- const pages = import.meta.glob("../../src/pages/**/*.tsx");
6
-
7
- const routes = Object.entries(pages).map(([filePath, component]) => {
8
- let cleaned = filePath.replace(/\\/g, "/");
9
-
10
- cleaned = cleaned.replace(/.*\/pages\//, "");
11
-
12
- cleaned = cleaned.replace(/\.tsx$/i, "");
13
-
14
- cleaned = cleaned.replace(/\/index$/, "");
15
-
16
- cleaned = cleaned.replace(/\[(\w+)\]/g, ":$1");
17
-
18
- if (cleaned === "index") {
19
- cleaned = "";
20
- }
21
-
22
- const routePath = cleaned === "" ? "/" : `/${cleaned}`;
23
-
24
- const Component = lazy(
25
- component as unknown as () => Promise<{ default: ComponentType }>
26
- );
27
-
28
- return {
29
- path: routePath,
30
- element: (
31
- <Suspense fallback={<div>Loading...</div>}>
32
- <Component />
33
- </Suspense>
34
- ),
35
- };
36
- });
37
-
38
- // fallback route for 404s
39
- routes.push({
40
- path: "*",
41
- element: <NotFound />,
42
- });
43
-
44
- export const router = createBrowserRouter(routes);
1
+ import { createBrowserRouter } from "react-router-dom";
2
+ import { lazy, Suspense, ComponentType } from "react";
3
+ // @ts-ignore
4
+ import NotFound from "/src/NotFound";
5
+
6
+ // @ts-ignore
7
+ const pages = import.meta.glob("/src/pages/**/*.tsx");
8
+
9
+ const routes = Object.entries(pages).map(([filePath, component]) => {
10
+ let cleaned = filePath.replace(/\\/g, "/");
11
+
12
+ cleaned = cleaned.replace(/.*\/pages\//, "");
13
+
14
+ cleaned = cleaned.replace(/\.tsx$/i, "");
15
+
16
+ cleaned = cleaned.replace(/\/index$/, "");
17
+
18
+ cleaned = cleaned.replace(/\[(\w+)\]/g, ":$1");
19
+
20
+ if (cleaned === "index") {
21
+ cleaned = "";
22
+ }
23
+
24
+ const routePath = cleaned === "" ? "/" : `/${cleaned}`;
25
+
26
+ const Component = lazy(
27
+ component as unknown as () => Promise<{ default: ComponentType }>
28
+ );
29
+
30
+ return {
31
+ path: routePath,
32
+ element: (
33
+ <Suspense fallback={<div>Loading...</div>}>
34
+ <Component />
35
+ </Suspense>
36
+ ),
37
+ };
38
+ });
39
+
40
+ // fallback route for 404s
41
+ routes.push({
42
+ path: "*",
43
+ element: <NotFound />,
44
+ });
45
+
46
+ export const router = createBrowserRouter(routes);
@@ -1,16 +1,26 @@
1
- import { spawnSync } from "child_process";
2
- import { logError, logInfo } from "../utils/logger.js";
3
-
4
- export async function installDependencies(projectDir: string): Promise<void> {
5
- const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
6
- const installResult = spawnSync(npmCmd, ["install"], {
7
- stdio: "inherit",
8
- cwd: projectDir,
9
- shell: true,
10
- });
11
- if (installResult.error || installResult.status !== 0) {
12
- logError("Error installing dependencies:", installResult.error);
13
- logInfo("Try running manually: npm install");
14
- process.exit(1);
15
- }
16
- }
1
+ import { spawnSync } from "child_process";
2
+ import { logError, logInfo } from "../utils/logger.js";
3
+
4
+ export async function installDependencies(projectDir: string): Promise<void> {
5
+ const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
6
+
7
+ // Step 1: npm install
8
+ const installResult = spawnSync(npmCmd, ["install"], {
9
+ stdio: "inherit",
10
+ cwd: projectDir,
11
+ shell: true,
12
+ });
13
+ if (installResult.error || installResult.status !== 0) {
14
+ logError("Error installing dependencies:", installResult.error);
15
+ logInfo("Try running manually: npm install");
16
+ process.exit(1);
17
+ }
18
+
19
+ // Step 2: Link local revine if available (replaces npm version with local build)
20
+ // This is a no-op if revine hasn't been globally linked via `npm link` in the revine repo.
21
+ spawnSync(npmCmd, ["link", "revine"], {
22
+ stdio: "pipe", // suppress output — silently skip if not linked
23
+ cwd: projectDir,
24
+ shell: true,
25
+ });
26
+ }
@@ -1,163 +1,151 @@
1
- import path from "path";
2
- import fs from "fs-extra";
3
- import { updateViteConfig } from "../config/vite.js";
4
- import { logInfo } from "../utils/logger.js";
5
-
6
- export async function setupTailwind(projectDir: string) {
7
- logInfo("\nSetting up Tailwind CSS...");
8
-
9
- // Point to the hidden Vite config
10
- const viteConfigPath = path.join(
11
- projectDir,
12
- ".revine",
13
- "bundler",
14
- "defaults",
15
- "vite.ts"
16
- );
17
-
18
- // Use existing updateViteConfig logic on this new path
19
- await updateViteConfig(viteConfigPath);
20
-
21
- // Write the Tailwind CSS import into the existing global.css file
22
- const cssFile = path.join(projectDir, "src", "styles", "global.css");
23
- const cssFileContent = `@import 'tailwindcss';\n`;
24
- await fs.writeFile(cssFile, cssFileContent);
25
-
26
- // Update the starter file for Tailwind classes
27
- const starterFile = path.join(projectDir, "src", "pages", "index.tsx");
28
- const starterFileContent = `
29
- export default function HomePage() {
30
- return (
31
- <main className="flex min-h-screen flex-col items-center justify-center p-6 bg-gradient-to-b from-white via-white to-indigo-200">
32
- {/* Hero Section */}
33
- <div className="max-w-screen-lg w-full text-center space-y-6">
34
- <h1 className="text-4xl sm:text-6xl font-extrabold text-gray-900 tracking-tight leading-tight">
35
- Welcome to{" "}
36
- <span className="text-transparent bg-clip-text bg-gradient-to-r from-indigo-500 via-indigo-600 to-black">
37
- Revine
38
- </span>
39
- </h1>
40
- <p className="text-xl sm:text-2xl text-gray-600 font-light">
41
- The modern, powerful, and streamlined React framework.
42
- </p>
43
- </div>
44
-
45
- {/* CTA Buttons */}
46
- <div className="mt-8 flex space-x-4">
47
- <a
48
- href="#get-started"
49
- className="rounded-md bg-indigo-600 px-6 py-3 text-white font-semibold shadow-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-colors"
50
- >
51
- Get Started
52
- </a>
53
- <a
54
- href="#docs"
55
- className="rounded-md bg-white px-6 py-3 text-indigo-600 font-semibold border border-indigo-200 shadow hover:bg-gray-100 transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
56
- >
57
- Read Docs
58
- </a>
59
- </div>
60
-
61
- {/* Features Section */}
62
- <div className="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3 max-w-screen-lg w-full">
63
- <a
64
- href="#fast"
65
- className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
66
- >
67
- <h3 className="text-lg font-semibold text-gray-900 mb-2">
68
- Lightning Fast
69
- </h3>
70
- <p className="text-gray-600">
71
- Built on Vite for ultra-fast development and instant HMR.
72
- </p>
73
- </a>
74
-
75
- <a
76
- href="#routing"
77
- className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
78
- >
79
- <h3 className="text-lg font-semibold text-gray-900 mb-2">
80
- Simple File-based Routing
81
- </h3>
82
- <p className="text-gray-600">
83
- Create pages in <code>src/pages</code> and Revine will handle the
84
- rest.
85
- </p>
86
- </a>
87
-
88
- <a
89
- href="#tailwind"
90
- className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
91
- >
92
- <h3 className="text-lg font-semibold text-gray-900 mb-2">
93
- Tailwind Integration
94
- </h3>
95
- <p className="text-gray-600">
96
- Pre-configured for Tailwind CSS, so you can style quickly and
97
- easily.
98
- </p>
99
- </a>
100
-
101
- <a
102
- href="#dev-experience"
103
- className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
104
- >
105
- <h3 className="text-lg font-semibold text-gray-900 mb-2">Great DX</h3>
106
- <p className="text-gray-600">
107
- Minimal config, fast builds, custom logging, and more.
108
- </p>
109
- </a>
110
-
111
- <a
112
- href="#abstract"
113
- className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
114
- >
115
- <h3 className="text-lg font-semibold text-gray-900 mb-2">
116
- Abstracted Internals
117
- </h3>
118
- <p className="text-gray-600">
119
- A .revine folder houses the complex Vite config. Keep your root
120
- clean.
121
- </p>
122
- </a>
123
-
124
- <a
125
- href="#customize"
126
- className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
127
- >
128
- <h3 className="text-lg font-semibold text-gray-900 mb-2">
129
- Fully Customizable
130
- </h3>
131
- <p className="text-gray-600">
132
- Easily extend or override settings in <code>revine.config.ts</code>.
133
- </p>
134
- </a>
135
- </div>
136
- </main>
137
- );
138
- }
139
- `;
140
- await fs.writeFile(starterFile, starterFileContent);
141
-
142
- // Replace the NotFound.tsx content
143
- const notFoundFile = path.join(projectDir, "src", "NotFound.tsx");
144
- const notFoundContent = `
145
- export default function NotFound() {
146
- return (
147
- <div className="min-h-screen flex items-center justify-center bg-gray-100">
148
- <div className="text-center space-y-4">
149
- <h1 className="text-6xl font-bold text-gray-900">404</h1>
150
- <p className="text-xl text-gray-600">Page Not Found</p>
151
- <a
152
- href="/"
153
- className="mt-6 inline-block bg-indigo-600 text-white font-semibold px-6 py-3 rounded-md shadow hover:bg-indigo-700"
154
- >
155
- Go Back Home
156
- </a>
157
- </div>
158
- </div>
159
- );
160
- }
161
- `;
162
- await fs.writeFile(notFoundFile, notFoundContent);
163
- }
1
+ import path from "path";
2
+ import fs from "fs-extra";
3
+ import { updateViteConfig } from "../config/vite.js";
4
+ import { logInfo } from "../utils/logger.js";
5
+
6
+ export async function setupTailwind(projectDir: string) {
7
+ logInfo("\nSetting up Tailwind CSS...");
8
+
9
+ // Write the Tailwind CSS import into the existing global.css file
10
+ const cssFile = path.join(projectDir, "src", "styles", "global.css");
11
+ const cssFileContent = `@import 'tailwindcss';\n`;
12
+ await fs.writeFile(cssFile, cssFileContent);
13
+
14
+ // Update the starter file for Tailwind classes
15
+ const starterFile = path.join(projectDir, "src", "pages", "index.tsx");
16
+ const starterFileContent = `
17
+ export default function HomePage() {
18
+ return (
19
+ <main className="flex min-h-screen flex-col items-center justify-center p-6 bg-gradient-to-b from-white via-white to-indigo-200">
20
+ {/* Hero Section */}
21
+ <div className="max-w-screen-lg w-full text-center space-y-6">
22
+ <h1 className="text-4xl sm:text-6xl font-extrabold text-gray-900 tracking-tight leading-tight">
23
+ Welcome to{" "}
24
+ <span className="text-transparent bg-clip-text bg-gradient-to-r from-indigo-500 via-indigo-600 to-black">
25
+ Revine
26
+ </span>
27
+ </h1>
28
+ <p className="text-xl sm:text-2xl text-gray-600 font-light">
29
+ The modern, powerful, and streamlined React framework.
30
+ </p>
31
+ </div>
32
+
33
+ {/* CTA Buttons */}
34
+ <div className="mt-8 flex space-x-4">
35
+ <a
36
+ href="#get-started"
37
+ className="rounded-md bg-indigo-600 px-6 py-3 text-white font-semibold shadow-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-colors"
38
+ >
39
+ Get Started
40
+ </a>
41
+ <a
42
+ href="#docs"
43
+ className="rounded-md bg-white px-6 py-3 text-indigo-600 font-semibold border border-indigo-200 shadow hover:bg-gray-100 transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
44
+ >
45
+ Read Docs
46
+ </a>
47
+ </div>
48
+
49
+ {/* Features Section */}
50
+ <div className="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3 max-w-screen-lg w-full">
51
+ <a
52
+ href="#fast"
53
+ className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
54
+ >
55
+ <h3 className="text-lg font-semibold text-gray-900 mb-2">
56
+ Lightning Fast
57
+ </h3>
58
+ <p className="text-gray-600">
59
+ Built on Vite for ultra-fast development and instant HMR.
60
+ </p>
61
+ </a>
62
+
63
+ <a
64
+ href="#routing"
65
+ className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
66
+ >
67
+ <h3 className="text-lg font-semibold text-gray-900 mb-2">
68
+ Simple File-based Routing
69
+ </h3>
70
+ <p className="text-gray-600">
71
+ Create pages in <code>src/pages</code> and Revine will handle the
72
+ rest.
73
+ </p>
74
+ </a>
75
+
76
+ <a
77
+ href="#tailwind"
78
+ className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
79
+ >
80
+ <h3 className="text-lg font-semibold text-gray-900 mb-2">
81
+ Tailwind Integration
82
+ </h3>
83
+ <p className="text-gray-600">
84
+ Pre-configured for Tailwind CSS, so you can style quickly and
85
+ easily.
86
+ </p>
87
+ </a>
88
+
89
+ <a
90
+ href="#dev-experience"
91
+ className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
92
+ >
93
+ <h3 className="text-lg font-semibold text-gray-900 mb-2">Great DX</h3>
94
+ <p className="text-gray-600">
95
+ Minimal config, fast builds, custom logging, and more.
96
+ </p>
97
+ </a>
98
+
99
+ <a
100
+ href="#abstract"
101
+ className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
102
+ >
103
+ <h3 className="text-lg font-semibold text-gray-900 mb-2">
104
+ Abstracted Internals
105
+ </h3>
106
+ <p className="text-gray-600">
107
+ A .revine folder houses the complex Vite config. Keep your root
108
+ clean.
109
+ </p>
110
+ </a>
111
+
112
+ <a
113
+ href="#customize"
114
+ className="block rounded-xl border border-gray-200 bg-white p-6 shadow transition hover:shadow-xl hover:-translate-y-1"
115
+ >
116
+ <h3 className="text-lg font-semibold text-gray-900 mb-2">
117
+ Fully Customizable
118
+ </h3>
119
+ <p className="text-gray-600">
120
+ Easily extend or override settings in <code>revine.config.ts</code>.
121
+ </p>
122
+ </a>
123
+ </div>
124
+ </main>
125
+ );
126
+ }
127
+ `;
128
+ await fs.writeFile(starterFile, starterFileContent);
129
+
130
+ // Replace the NotFound.tsx content
131
+ const notFoundFile = path.join(projectDir, "src", "NotFound.tsx");
132
+ const notFoundContent = `
133
+ export default function NotFound() {
134
+ return (
135
+ <div className="min-h-screen flex items-center justify-center bg-gray-100">
136
+ <div className="text-center space-y-4">
137
+ <h1 className="text-6xl font-bold text-gray-900">404</h1>
138
+ <p className="text-xl text-gray-600">Page Not Found</p>
139
+ <a
140
+ href="/"
141
+ className="mt-6 inline-block bg-indigo-600 text-white font-semibold px-6 py-3 rounded-md shadow hover:bg-indigo-700"
142
+ >
143
+ Go Back Home
144
+ </a>
145
+ </div>
146
+ </div>
147
+ );
148
+ }
149
+ `;
150
+ await fs.writeFile(notFoundFile, notFoundContent);
151
+ }
package/src/utils/file.ts CHANGED
@@ -1,9 +1,9 @@
1
- import fs from "fs-extra";
2
-
3
- export async function copyTemplate(
4
- templateDir: string,
5
- destinationDir: string,
6
- force?: boolean
7
- ): Promise<void> {
8
- await fs.copy(templateDir, destinationDir, { overwrite: force });
9
- }
1
+ import fs from "fs-extra";
2
+
3
+ export async function copyTemplate(
4
+ templateDir: string,
5
+ destinationDir: string,
6
+ force?: boolean
7
+ ): Promise<void> {
8
+ await fs.copy(templateDir, destinationDir, { overwrite: force });
9
+ }
@@ -1,9 +1,9 @@
1
- import chalk from "chalk";
2
-
3
- export function logInfo(message: string) {
4
- console.log(chalk.cyan(message));
5
- }
6
-
7
- export function logError(message: string, error?: any) {
8
- console.error(chalk.red(message), error || "");
9
- }
1
+ import chalk from "chalk";
2
+
3
+ export function logInfo(message: string) {
4
+ console.log(chalk.cyan(message));
5
+ }
6
+
7
+ export function logError(message: string, error?: any) {
8
+ console.error(chalk.red(message), error || "");
9
+ }
@@ -1,63 +1,63 @@
1
- # %PROJECT_NAME%
2
-
3
- Welcome to your new Revine project!
4
-
5
- ## Getting Started
6
-
7
- ### 1. Install dependencies
8
- ```bash
9
- npm install
10
- ```
11
-
12
- ### 2. Start development server
13
- ```bash
14
- npm run dev
15
- ```
16
-
17
- ## Scripts
18
- - npm run dev - Start dev server
19
-
20
- - npm run build - Production build
21
-
22
- - npm run preview - Preview production build
23
-
24
- ## Project Structure
25
- ```bash
26
- src/
27
- ├── pages/ # Application routes
28
- │ └── index.tsx # Home page
29
- ├── App.tsx # Router configuration
30
- └── main.tsx # Application entry point
31
- ```
32
-
33
- ## Customization
34
- ### Add a New Page
35
- Create new .tsx file in src/pages
36
-
37
- ```tsx
38
- // src/pages/about.tsx
39
- export default function About() {
40
- return <h1>About Page</h1>
41
- }
42
- ```
43
- Access at /about
44
-
45
- ### Modify Vite Config
46
- Edit vite.config.ts:
47
-
48
- ```typescript
49
- export default defineConfig({
50
- plugins: [react()],
51
- server: {
52
- port: 8080 // Custom port
53
- }
54
- });
55
- ```
56
-
57
- ## Deployment
58
- Build for production:
59
-
60
- ```bash
61
- npm run build
62
- ```
1
+ # %PROJECT_NAME%
2
+
3
+ Welcome to your new Revine project!
4
+
5
+ ## Getting Started
6
+
7
+ ### 1. Install dependencies
8
+ ```bash
9
+ npm install
10
+ ```
11
+
12
+ ### 2. Start development server
13
+ ```bash
14
+ npm run dev
15
+ ```
16
+
17
+ ## Scripts
18
+ - npm run dev - Start dev server
19
+
20
+ - npm run build - Production build
21
+
22
+ - npm run preview - Preview production build
23
+
24
+ ## Project Structure
25
+ ```bash
26
+ src/
27
+ ├── pages/ # Application routes
28
+ │ └── index.tsx # Home page
29
+ ├── App.tsx # Router configuration
30
+ └── main.tsx # Application entry point
31
+ ```
32
+
33
+ ## Customization
34
+ ### Add a New Page
35
+ Create new .tsx file in src/pages
36
+
37
+ ```tsx
38
+ // src/pages/about.tsx
39
+ export default function About() {
40
+ return <h1>About Page</h1>
41
+ }
42
+ ```
43
+ Access at /about
44
+
45
+ ### Modify Vite Config
46
+ Edit vite.config.ts:
47
+
48
+ ```typescript
49
+ export default defineConfig({
50
+ plugins: [react()],
51
+ server: {
52
+ port: 8080 // Custom port
53
+ }
54
+ });
55
+ ```
56
+
57
+ ## Deployment
58
+ Build for production:
59
+
60
+ ```bash
61
+ npm run build
62
+ ```
63
63
  The build artifacts will be in dist/ directory.