revine 0.1.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.md +81 -0
- package/dist/commands/create.js +65 -0
- package/dist/index.js +101 -0
- package/dist/lib/setup/directory.js +21 -0
- package/dist/lib/setup/package.js +17 -0
- package/dist/lib/setup/tailwind.js +22 -0
- package/dist/lib/utils/exec.js +15 -0
- package/dist/lib/utils/paths.js +6 -0
- package/package.json +29 -0
- package/src/index.ts +143 -0
- package/template/README.md +63 -0
- package/template/index.html +19 -0
- package/template/package.json +21 -0
- package/template/src/App.tsx +31 -0
- package/template/src/main.tsx +12 -0
- package/template/src/pages/index.tsx +8 -0
- package/template/src/vite-env.d.ts +1 -0
- package/template/tsconfig.json +20 -0
- package/template/vite.config.ts +15 -0
- package/tsconfig.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Revine
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/revine)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A minimal React framework with file-based routing and TypeScript-first approach.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- ⚡️ Vite-powered development
|
|
11
|
+
- 🗂 File-based routing (Next.js style)
|
|
12
|
+
- 🛠 TypeScript support out-of-the-box
|
|
13
|
+
- 🚀 Zero-config setup
|
|
14
|
+
- 🔥 Hot Module Replacement (HMR)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
Create a new project with:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx revine my-project
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Documentation
|
|
25
|
+
|
|
26
|
+
### CLI Options
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx revine <project-name>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Project Structure
|
|
33
|
+
|
|
34
|
+
Generated projects follow this structure:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
my-project/
|
|
38
|
+
├── src/
|
|
39
|
+
│ ├── pages/ # Route components
|
|
40
|
+
│ │ └── index.tsx
|
|
41
|
+
│ ├── App.tsx # Router configuration
|
|
42
|
+
│ └── main.tsx # Entry point
|
|
43
|
+
├── public/ # Static assets
|
|
44
|
+
├── vite.config.ts # Vite configuration
|
|
45
|
+
└── package.json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Routing Convention
|
|
49
|
+
|
|
50
|
+
src/pages/index.tsx → /
|
|
51
|
+
|
|
52
|
+
src/pages/about.tsx → /about
|
|
53
|
+
|
|
54
|
+
src/pages/blog/[slug].tsx → /blog/:slug
|
|
55
|
+
|
|
56
|
+
## Contributing
|
|
57
|
+
|
|
58
|
+
### Clone repository
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/your-username/revine.git
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Install dependencies
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Build and link locally
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm run build
|
|
74
|
+
npm link
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Test locally
|
|
78
|
+
|
|
79
|
+
revine test-project
|
|
80
|
+
|
|
81
|
+
### Thank you for contributing!
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
// locals
|
|
7
|
+
import { getDirname } from "../lib/utils/paths.js";
|
|
8
|
+
import { validateDirectory } from "../lib/setup/directory.js";
|
|
9
|
+
import { updatePackageJson } from "../lib/setup/package.js";
|
|
10
|
+
import { setupTailwind } from "../lib/setup/tailwind.js";
|
|
11
|
+
import { runInstall } from "../lib/utils/exec.js";
|
|
12
|
+
const __dirname = getDirname(import.meta.url);
|
|
13
|
+
export function createCommand() {
|
|
14
|
+
const command = new Command("create")
|
|
15
|
+
.description("Create a new Revine project")
|
|
16
|
+
.argument("<project-name>")
|
|
17
|
+
.option("-f, --force", "Force creation in non-empty directory")
|
|
18
|
+
.action(async (projectName, options) => {
|
|
19
|
+
try {
|
|
20
|
+
const templateDir = path.join(__dirname, "../../template");
|
|
21
|
+
const projectDir = path.resolve(projectName);
|
|
22
|
+
const isCurrentDir = [".", "./"].includes(projectName);
|
|
23
|
+
// Validate directory
|
|
24
|
+
validateDirectory(projectDir, isCurrentDir, options.force);
|
|
25
|
+
// Copy template
|
|
26
|
+
console.log(chalk.cyan(`Creating project in ${projectDir}...`));
|
|
27
|
+
fs.copySync(templateDir, projectDir, { overwrite: options.force });
|
|
28
|
+
// Update package.json
|
|
29
|
+
const { useTailwind } = await inquirer.prompt([
|
|
30
|
+
{
|
|
31
|
+
type: "confirm",
|
|
32
|
+
name: "useTailwind",
|
|
33
|
+
message: "Would you like to set up Tailwind CSS?",
|
|
34
|
+
default: true,
|
|
35
|
+
},
|
|
36
|
+
]);
|
|
37
|
+
await updatePackageJson(projectDir, isCurrentDir ? path.basename(projectDir) : projectName, useTailwind);
|
|
38
|
+
// Update README
|
|
39
|
+
const readmePath = path.join(projectDir, "README.md");
|
|
40
|
+
let readmeContent = fs.readFileSync(readmePath, "utf-8");
|
|
41
|
+
fs.writeFileSync(readmePath, readmeContent.replace(/%PROJECT_NAME%/g, projectName));
|
|
42
|
+
// Install dependencies
|
|
43
|
+
console.log(chalk.cyan("\nInstalling dependencies..."));
|
|
44
|
+
runInstall(projectDir);
|
|
45
|
+
// Setup Tailwind
|
|
46
|
+
if (useTailwind) {
|
|
47
|
+
setupTailwind(projectDir);
|
|
48
|
+
}
|
|
49
|
+
// Final message
|
|
50
|
+
console.log(chalk.green("\nSuccess! Created project at"), chalk.yellow(projectDir));
|
|
51
|
+
console.log(chalk.cyan("\nStart developing with:"));
|
|
52
|
+
if (!isCurrentDir)
|
|
53
|
+
console.log(` cd ${projectName}`);
|
|
54
|
+
console.log(" npm run dev\n");
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
let message = "Unknown error occurred";
|
|
58
|
+
if (error instanceof Error)
|
|
59
|
+
message = error.message;
|
|
60
|
+
console.log(chalk.red("Error:"), message);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return command;
|
|
65
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { spawnSync } from "child_process";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import fs from "fs-extra";
|
|
6
|
+
import inquirer from "inquirer";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
// Get directory paths in ESM
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
const program = new Command();
|
|
13
|
+
program
|
|
14
|
+
.version("0.1.0")
|
|
15
|
+
.argument("<project-name>")
|
|
16
|
+
.option("-f, --force", "Force creation in non-empty directory")
|
|
17
|
+
.action(async (projectName, options) => {
|
|
18
|
+
const templateDir = path.join(__dirname, "../template");
|
|
19
|
+
const projectDir = path.resolve(projectName);
|
|
20
|
+
const isCurrentDir = [".", "./"].includes(projectName);
|
|
21
|
+
// ... [keep existing directory checks the same] ...
|
|
22
|
+
try {
|
|
23
|
+
console.log(chalk.cyan(`Creating project in ${projectDir}...`));
|
|
24
|
+
fs.copySync(templateDir, projectDir, { overwrite: options.force });
|
|
25
|
+
// Update package.json with ESM configuration
|
|
26
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
27
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
28
|
+
const finalProjectName = isCurrentDir
|
|
29
|
+
? path.basename(projectDir)
|
|
30
|
+
: projectName;
|
|
31
|
+
packageJson.name = finalProjectName;
|
|
32
|
+
packageJson.type = "module"; // Add ESM type declaration
|
|
33
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
34
|
+
// Add Tailwind prompt
|
|
35
|
+
const { useTailwind } = await inquirer.prompt([
|
|
36
|
+
{
|
|
37
|
+
type: "confirm",
|
|
38
|
+
name: "useTailwind",
|
|
39
|
+
message: "Would you like to set up Tailwind CSS?",
|
|
40
|
+
default: true,
|
|
41
|
+
},
|
|
42
|
+
]);
|
|
43
|
+
// Add Tailwind v4 dependencies if selected
|
|
44
|
+
if (useTailwind) {
|
|
45
|
+
packageJson.devDependencies = {
|
|
46
|
+
...packageJson.devDependencies,
|
|
47
|
+
tailwindcss: "^4.0.0",
|
|
48
|
+
"@tailwindcss/vite": "^4.0.0",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
52
|
+
// Update README
|
|
53
|
+
const readmePath = path.join(projectDir, "README.md");
|
|
54
|
+
let readmeContent = fs.readFileSync(readmePath, "utf-8");
|
|
55
|
+
readmeContent = readmeContent.replace(/%PROJECT_NAME%/g, finalProjectName);
|
|
56
|
+
fs.writeFileSync(readmePath, readmeContent);
|
|
57
|
+
// Install dependencies with error handling
|
|
58
|
+
console.log(chalk.cyan("\nInstalling dependencies..."));
|
|
59
|
+
const installResult = spawnSync(npmCmd, ["install"], {
|
|
60
|
+
stdio: "inherit",
|
|
61
|
+
cwd: projectDir,
|
|
62
|
+
shell: true,
|
|
63
|
+
});
|
|
64
|
+
if (installResult.error || installResult.status !== 0) {
|
|
65
|
+
console.log(chalk.red("\nError installing dependencies!", installResult.error));
|
|
66
|
+
console.log(chalk.yellow("Try running manually: npm install"));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
// Setup Tailwind after dependencies are installed
|
|
70
|
+
if (useTailwind) {
|
|
71
|
+
console.log(chalk.cyan("\nSetting up Tailwind CSS v4..."));
|
|
72
|
+
// Update Vite config to add Tailwind plugin
|
|
73
|
+
const viteConfigPath = path.join(projectDir, "vite.config.ts");
|
|
74
|
+
let viteConfigContent = fs.readFileSync(viteConfigPath, "utf-8");
|
|
75
|
+
// Add Tailwind import
|
|
76
|
+
viteConfigContent = viteConfigContent.replace("import react from '@vitejs/plugin-react';", "import react from '@vitejs/plugin-react';\nimport tailwindcss from '@tailwindcss/vite';");
|
|
77
|
+
// Add Tailwind plugin to existing config
|
|
78
|
+
viteConfigContent = viteConfigContent.replace("plugins: [react()]", "plugins: [\n react(),\n tailwindcss()\n ]");
|
|
79
|
+
fs.writeFileSync(viteConfigPath, viteConfigContent);
|
|
80
|
+
fs.writeFileSync(viteConfigPath, viteConfigContent);
|
|
81
|
+
// Create CSS file with import
|
|
82
|
+
const cssDir = path.join(projectDir, "src", "styles");
|
|
83
|
+
fs.ensureDirSync(cssDir);
|
|
84
|
+
fs.writeFileSync(path.join(cssDir, "global.css"), "@import 'tailwindcss';\n");
|
|
85
|
+
// Add CSS import to main.tsx
|
|
86
|
+
const mainTsxPath = path.join(projectDir, "src", "main.tsx");
|
|
87
|
+
const mainContent = `import './styles/global.css';\n${fs.readFileSync(mainTsxPath, "utf-8")}`;
|
|
88
|
+
fs.writeFileSync(mainTsxPath, mainContent);
|
|
89
|
+
}
|
|
90
|
+
console.log(chalk.green("\nSuccess! Created project at"), chalk.yellow(projectDir));
|
|
91
|
+
console.log(chalk.cyan("\nStart developing with:"));
|
|
92
|
+
if (!isCurrentDir)
|
|
93
|
+
console.log(` cd ${projectName}`);
|
|
94
|
+
console.log(" npm run dev\n");
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.log(chalk.red("Error:"), error);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
export function validateDirectory(projectDir, isCurrentDir, force) {
|
|
4
|
+
if (fs.existsSync(projectDir)) {
|
|
5
|
+
if (!isCurrentDir && !force) {
|
|
6
|
+
console.log(chalk.red(`Error: Directory "${projectDir}" already exists.`));
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
const existingFiles = fs
|
|
10
|
+
.readdirSync(projectDir)
|
|
11
|
+
.filter((file) => file !== ".git");
|
|
12
|
+
if (existingFiles.length > 0 && !force) {
|
|
13
|
+
console.log(chalk.red(`Error: Directory "${projectDir}" is not empty.`));
|
|
14
|
+
console.log(chalk.yellow("Use --force to override existing files"));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
fs.mkdirpSync(projectDir);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
export async function updatePackageJson(projectDir, projectName, useTailwind) {
|
|
4
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
5
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
6
|
+
packageJson.name = projectName;
|
|
7
|
+
packageJson.type = "module";
|
|
8
|
+
if (useTailwind) {
|
|
9
|
+
packageJson.devDependencies = {
|
|
10
|
+
...packageJson.devDependencies,
|
|
11
|
+
tailwindcss: "^4.0.0",
|
|
12
|
+
"@tailwindcss/vite": "^4.0.0",
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
16
|
+
return packageJson;
|
|
17
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
export function setupTailwind(projectDir) {
|
|
5
|
+
console.log(chalk.cyan("\nSetting up Tailwind CSS..."));
|
|
6
|
+
// Update Vite config
|
|
7
|
+
const viteConfigPath = path.join(projectDir, "vite.config.ts");
|
|
8
|
+
let viteConfig = fs.readFileSync(viteConfigPath, "utf-8");
|
|
9
|
+
viteConfig = viteConfig
|
|
10
|
+
.replace("import react from '@vitejs/plugin-react';", "import react from '@vitejs/plugin-react';\nimport tailwindcss from '@tailwindcss/vite';")
|
|
11
|
+
.replace("plugins: [react()]", "plugins: [\n react(),\n tailwindcss()\n ]");
|
|
12
|
+
fs.writeFileSync(viteConfigPath, viteConfig);
|
|
13
|
+
// Create styles directory
|
|
14
|
+
const cssDir = path.join(projectDir, "src", "styles");
|
|
15
|
+
fs.ensureDirSync(cssDir);
|
|
16
|
+
// Create CSS file
|
|
17
|
+
fs.writeFileSync(path.join(cssDir, "global.css"), "@import 'tailwindcss';\n");
|
|
18
|
+
// Update main entry file
|
|
19
|
+
const mainTsxPath = path.join(projectDir, "src", "main.tsx");
|
|
20
|
+
const mainContent = `import './styles/global.css';\n${fs.readFileSync(mainTsxPath, "utf-8")}`;
|
|
21
|
+
fs.writeFileSync(mainTsxPath, mainContent);
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { spawnSync } from "child_process";
|
|
2
|
+
import { platform } from "os";
|
|
3
|
+
export function getNpmCommand() {
|
|
4
|
+
return platform() === "win32" ? "npm.cmd" : "npm";
|
|
5
|
+
}
|
|
6
|
+
export function runInstall(cwd) {
|
|
7
|
+
const result = spawnSync(getNpmCommand(), ["install"], {
|
|
8
|
+
stdio: "inherit",
|
|
9
|
+
cwd,
|
|
10
|
+
shell: true,
|
|
11
|
+
});
|
|
12
|
+
if (result.error || result.status !== 0) {
|
|
13
|
+
throw new Error("Dependency installation failed");
|
|
14
|
+
}
|
|
15
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "revine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A react framework, but better.",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "Rachit Bharadwaj",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"revine": "dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsc -w",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"chalk": "^5.4.1",
|
|
19
|
+
"commander": "^13.1.0",
|
|
20
|
+
"cross-spawn": "^7.0.6",
|
|
21
|
+
"fs-extra": "^11.3.0",
|
|
22
|
+
"inquirer": "^12.4.1"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/fs-extra": "^11.0.4",
|
|
26
|
+
"@types/node": "^22.13.0",
|
|
27
|
+
"typescript": "^5.7.3"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { spawnSync } from "child_process";
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
import inquirer from "inquirer";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
|
|
11
|
+
// Get directory paths in ESM
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
|
|
15
|
+
const program = new Command();
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.version("0.1.0")
|
|
19
|
+
.argument("<project-name>")
|
|
20
|
+
.option("-f, --force", "Force creation in non-empty directory")
|
|
21
|
+
.action(async (projectName: string, options: { force?: boolean }) => {
|
|
22
|
+
const templateDir = path.join(__dirname, "../template");
|
|
23
|
+
const projectDir = path.resolve(projectName);
|
|
24
|
+
const isCurrentDir = [".", "./"].includes(projectName);
|
|
25
|
+
|
|
26
|
+
// ... [keep existing directory checks the same] ...
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
console.log(chalk.cyan(`Creating project in ${projectDir}...`));
|
|
30
|
+
fs.copySync(templateDir, projectDir, { overwrite: options.force });
|
|
31
|
+
|
|
32
|
+
// Update package.json with ESM configuration
|
|
33
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
34
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
35
|
+
const finalProjectName = isCurrentDir
|
|
36
|
+
? path.basename(projectDir)
|
|
37
|
+
: projectName;
|
|
38
|
+
|
|
39
|
+
packageJson.name = finalProjectName;
|
|
40
|
+
packageJson.type = "module"; // Add ESM type declaration
|
|
41
|
+
|
|
42
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
43
|
+
|
|
44
|
+
// Add Tailwind prompt
|
|
45
|
+
const { useTailwind } = await inquirer.prompt([
|
|
46
|
+
{
|
|
47
|
+
type: "confirm",
|
|
48
|
+
name: "useTailwind",
|
|
49
|
+
message: "Would you like to set up Tailwind CSS?",
|
|
50
|
+
default: true,
|
|
51
|
+
},
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
// Add Tailwind v4 dependencies if selected
|
|
55
|
+
if (useTailwind) {
|
|
56
|
+
packageJson.devDependencies = {
|
|
57
|
+
...packageJson.devDependencies,
|
|
58
|
+
tailwindcss: "^4.0.0",
|
|
59
|
+
"@tailwindcss/vite": "^4.0.0",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
64
|
+
|
|
65
|
+
// Update README
|
|
66
|
+
const readmePath = path.join(projectDir, "README.md");
|
|
67
|
+
let readmeContent = fs.readFileSync(readmePath, "utf-8");
|
|
68
|
+
readmeContent = readmeContent.replace(
|
|
69
|
+
/%PROJECT_NAME%/g,
|
|
70
|
+
finalProjectName
|
|
71
|
+
);
|
|
72
|
+
fs.writeFileSync(readmePath, readmeContent);
|
|
73
|
+
|
|
74
|
+
// Install dependencies with error handling
|
|
75
|
+
console.log(chalk.cyan("\nInstalling dependencies..."));
|
|
76
|
+
const installResult = spawnSync(npmCmd, ["install"], {
|
|
77
|
+
stdio: "inherit",
|
|
78
|
+
cwd: projectDir,
|
|
79
|
+
shell: true,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (installResult.error || installResult.status !== 0) {
|
|
83
|
+
console.log(
|
|
84
|
+
chalk.red("\nError installing dependencies!", installResult.error)
|
|
85
|
+
);
|
|
86
|
+
console.log(chalk.yellow("Try running manually: npm install"));
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Setup Tailwind after dependencies are installed
|
|
91
|
+
if (useTailwind) {
|
|
92
|
+
console.log(chalk.cyan("\nSetting up Tailwind CSS v4..."));
|
|
93
|
+
|
|
94
|
+
// Update Vite config to add Tailwind plugin
|
|
95
|
+
const viteConfigPath = path.join(projectDir, "vite.config.ts");
|
|
96
|
+
let viteConfigContent = fs.readFileSync(viteConfigPath, "utf-8");
|
|
97
|
+
|
|
98
|
+
// Add Tailwind import
|
|
99
|
+
viteConfigContent = viteConfigContent.replace(
|
|
100
|
+
"import react from '@vitejs/plugin-react';",
|
|
101
|
+
"import react from '@vitejs/plugin-react';\nimport tailwindcss from '@tailwindcss/vite';"
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Add Tailwind plugin to existing config
|
|
105
|
+
viteConfigContent = viteConfigContent.replace(
|
|
106
|
+
"plugins: [react()]",
|
|
107
|
+
"plugins: [\n react(),\n tailwindcss()\n ]"
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
fs.writeFileSync(viteConfigPath, viteConfigContent);
|
|
111
|
+
fs.writeFileSync(viteConfigPath, viteConfigContent);
|
|
112
|
+
|
|
113
|
+
// Create CSS file with import
|
|
114
|
+
const cssDir = path.join(projectDir, "src", "styles");
|
|
115
|
+
fs.ensureDirSync(cssDir);
|
|
116
|
+
fs.writeFileSync(
|
|
117
|
+
path.join(cssDir, "global.css"),
|
|
118
|
+
"@import 'tailwindcss';\n"
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Add CSS import to main.tsx
|
|
122
|
+
const mainTsxPath = path.join(projectDir, "src", "main.tsx");
|
|
123
|
+
const mainContent = `import './styles/global.css';\n${fs.readFileSync(
|
|
124
|
+
mainTsxPath,
|
|
125
|
+
"utf-8"
|
|
126
|
+
)}`;
|
|
127
|
+
fs.writeFileSync(mainTsxPath, mainContent);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.log(
|
|
131
|
+
chalk.green("\nSuccess! Created project at"),
|
|
132
|
+
chalk.yellow(projectDir)
|
|
133
|
+
);
|
|
134
|
+
console.log(chalk.cyan("\nStart developing with:"));
|
|
135
|
+
if (!isCurrentDir) console.log(` cd ${projectName}`);
|
|
136
|
+
console.log(" npm run dev\n");
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.log(chalk.red("Error:"), error);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
program.parse(process.argv);
|
|
@@ -0,0 +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
|
+
```
|
|
63
|
+
The build artifacts will be in dist/ directory.
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
<meta name="description" content="This project is built using Revine" />
|
|
7
|
+
<meta name="theme-color" content="#ffffff" />
|
|
8
|
+
<link rel="icon" href="/favicon.ico" />
|
|
9
|
+
<link rel="stylesheet" href="/assets/index.css" />
|
|
10
|
+
<title>Revine App</title>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
15
|
+
<noscript>
|
|
16
|
+
<h1>This application requires JavaScript to run.</h1>
|
|
17
|
+
</noscript>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{project-name}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"dev": "vite",
|
|
6
|
+
"build": "vite build",
|
|
7
|
+
"preview": "vite preview"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"react": "^18.2.0",
|
|
11
|
+
"react-dom": "^18.2.0",
|
|
12
|
+
"react-router-dom": "^6.22.3"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/react": "^18.2.45",
|
|
16
|
+
"@types/react-dom": "^18.2.18",
|
|
17
|
+
"typescript": "^5.3.3",
|
|
18
|
+
"vite": "^5.0.12",
|
|
19
|
+
"@vitejs/plugin-react": "^4.2.1"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
|
2
|
+
import { lazy, Suspense, ComponentType } from "react";
|
|
3
|
+
|
|
4
|
+
const pages = import.meta.glob("./pages/**/*.tsx");
|
|
5
|
+
|
|
6
|
+
const routes = Object.entries(pages).map(([path, component]) => {
|
|
7
|
+
const routePath = path
|
|
8
|
+
.replace(/\.\/pages\//i, "")
|
|
9
|
+
.replace(/\.tsx$/i, "")
|
|
10
|
+
.replace(/\/index$/i, "")
|
|
11
|
+
.replace(/\[(\w+)\]/g, ":$1");
|
|
12
|
+
|
|
13
|
+
const Component = lazy(
|
|
14
|
+
component as unknown as () => Promise<{ default: ComponentType }>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
path: routePath === "index" ? "/" : `/${routePath}`,
|
|
19
|
+
element: (
|
|
20
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
21
|
+
<Component />
|
|
22
|
+
</Suspense>
|
|
23
|
+
),
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const router = createBrowserRouter(routes);
|
|
28
|
+
|
|
29
|
+
export default function App() {
|
|
30
|
+
return <RouterProvider router={router} />;
|
|
31
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import App from "./App";
|
|
4
|
+
|
|
5
|
+
const container = document.getElementById("root")!;
|
|
6
|
+
const root = createRoot(container);
|
|
7
|
+
|
|
8
|
+
root.render(
|
|
9
|
+
<React.StrictMode>
|
|
10
|
+
<App />
|
|
11
|
+
</React.StrictMode>
|
|
12
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"noEmit": true,
|
|
12
|
+
"jsx": "react-jsx",
|
|
13
|
+
"strict": true,
|
|
14
|
+
"noUnusedLocals": true,
|
|
15
|
+
"noUnusedParameters": true,
|
|
16
|
+
"noFallthroughCasesInSwitch": true,
|
|
17
|
+
"types": ["vite/client"]
|
|
18
|
+
},
|
|
19
|
+
"include": ["src"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
server: {
|
|
7
|
+
open: true,
|
|
8
|
+
port: 3000,
|
|
9
|
+
host: true
|
|
10
|
+
},
|
|
11
|
+
build: {
|
|
12
|
+
outDir: 'dist',
|
|
13
|
+
emptyOutDir: true,
|
|
14
|
+
}
|
|
15
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ES2020",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*"],
|
|
13
|
+
"exclude": ["src/template/**/*"]
|
|
14
|
+
}
|