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.
- package/README.md +81 -81
- package/dist/commands/createProject.js +20 -2
- package/dist/config/package.js +4 -0
- package/dist/index.js +64 -2
- package/dist/prompts/project.js +11 -8
- package/dist/runtime/bundler/defaults/vite.js +17 -0
- package/dist/runtime/bundler/generateConfig.js +27 -0
- package/dist/runtime/bundler/revinePlugin.js +68 -0
- package/dist/runtime/bundler/utils/loadUserConfig.js +20 -0
- package/dist/runtime/bundler/vite.config.js +7 -0
- package/dist/runtime/bundler/viteLoggerPlugin.js +27 -0
- package/dist/runtime/routing/fileBased.js +29 -0
- package/dist/setup/dependencies.js +8 -0
- package/dist/setup/tailwind.js +128 -133
- package/package.json +44 -29
- package/src/commands/createProject.ts +88 -65
- package/src/config/package.ts +28 -23
- package/src/config/readme.ts +7 -7
- package/src/config/vite.ts +19 -19
- package/src/index.ts +91 -15
- package/src/prompts/git.ts +61 -61
- package/src/prompts/index.ts +3 -3
- package/src/prompts/project.ts +34 -31
- package/src/prompts/tailwind.ts +13 -13
- package/{template/.revine → src/runtime}/bundler/defaults/vite.ts +18 -18
- package/src/runtime/bundler/generateConfig.ts +36 -0
- package/src/runtime/bundler/revinePlugin.ts +71 -0
- package/src/runtime/bundler/utils/loadUserConfig.ts +19 -0
- package/{template/.revine → src/runtime}/bundler/vite.config.ts +8 -8
- package/{template/.revine → src/runtime}/bundler/viteLoggerPlugin.ts +33 -33
- package/{template/.revine → src/runtime}/routing/fileBased.tsx +46 -44
- package/src/setup/dependencies.ts +26 -16
- package/src/setup/tailwind.ts +151 -163
- package/src/utils/file.ts +9 -9
- package/src/utils/logger.ts +9 -9
- package/template/README.md +62 -62
- package/template/index.html +19 -19
- package/template/package.json +21 -24
- package/template/revine.config.ts +13 -13
- package/template/src/NotFound.tsx +13 -13
- package/template/src/pages/index.tsx +62 -62
- package/template/src/root.tsx +14 -14
- package/template/src/styles/global.css +191 -191
- package/template/tsconfig.json +20 -24
- package/tsconfig.json +15 -14
- package/dist/commands/create.js +0 -65
- package/dist/installers/dependencies.js +0 -15
- package/dist/lib/setup/directory.js +0 -21
- package/dist/lib/setup/package.js +0 -17
- package/dist/lib/setup/tailwind.js +0 -22
- package/dist/lib/utils/exec.js +0 -15
- package/dist/lib/utils/paths.js +0 -6
- package/template/.revine/bundler/generateConfig.ts +0 -18
- package/template/.revine/bundler/utils/loadUserConfig.ts +0 -13
- /package/{template/.revine → src/runtime}/bundler/types/vite-env.d.ts +0 -0
package/README.md
CHANGED
|
@@ -1,81 +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!
|
|
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!
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import { fileURLToPath } from "url";
|
|
3
|
+
import fs from "fs-extra";
|
|
3
4
|
import { updatePackageJson } from "../config/package.js";
|
|
4
5
|
import { updateReadme } from "../config/readme.js";
|
|
5
6
|
import { askForTailwindSetup, initGit, runProject } from "../prompts/index.js";
|
|
@@ -16,18 +17,35 @@ export async function createProject(projectName, options) {
|
|
|
16
17
|
const isCurrentDir = [".", "./"].includes(projectName);
|
|
17
18
|
try {
|
|
18
19
|
logInfo(`Creating project in ${projectDir}...`);
|
|
20
|
+
// Ensure the project directory exists
|
|
21
|
+
await fs.ensureDir(projectDir);
|
|
19
22
|
// This copies everything, including hidden directories like .revine
|
|
20
23
|
await copyTemplate(templateDir, projectDir, options.force);
|
|
21
24
|
// Derive final project name
|
|
22
25
|
const finalProjectName = isCurrentDir
|
|
23
26
|
? path.basename(projectDir)
|
|
24
27
|
: projectName;
|
|
25
|
-
//
|
|
28
|
+
// Check if package.json exists after template copy
|
|
26
29
|
const packageJsonPath = path.join(projectDir, "package.json");
|
|
30
|
+
// Create basic package.json if it doesn't exist
|
|
31
|
+
if (!await fs.pathExists(packageJsonPath)) {
|
|
32
|
+
const basicPackageJson = {
|
|
33
|
+
name: finalProjectName,
|
|
34
|
+
version: "0.1.0",
|
|
35
|
+
private: true,
|
|
36
|
+
type: "module"
|
|
37
|
+
};
|
|
38
|
+
await fs.writeJSON(packageJsonPath, basicPackageJson, { spaces: 2 });
|
|
39
|
+
}
|
|
40
|
+
// Update package.json with the correct details
|
|
27
41
|
const useTailwind = await askForTailwindSetup();
|
|
28
42
|
await updatePackageJson(packageJsonPath, finalProjectName, { useTailwind });
|
|
29
|
-
//
|
|
43
|
+
// Check if README exists, create it if it doesn't
|
|
30
44
|
const readmePath = path.join(projectDir, "README.md");
|
|
45
|
+
if (!await fs.pathExists(readmePath)) {
|
|
46
|
+
await fs.writeFile(readmePath, `# ${finalProjectName}\n\nCreated with Revine`);
|
|
47
|
+
}
|
|
48
|
+
// Update README with the project name
|
|
31
49
|
await updateReadme(readmePath, finalProjectName);
|
|
32
50
|
// Install dependencies
|
|
33
51
|
logInfo("\nInstalling dependencies...");
|
package/dist/config/package.js
CHANGED
|
@@ -3,6 +3,10 @@ export async function updatePackageJson(filePath, projectName, options = {}) {
|
|
|
3
3
|
const packageJson = await fs.readJson(filePath);
|
|
4
4
|
packageJson.name = projectName;
|
|
5
5
|
packageJson.type = "module";
|
|
6
|
+
packageJson.dependencies = {
|
|
7
|
+
...packageJson.dependencies,
|
|
8
|
+
revine: "latest",
|
|
9
|
+
};
|
|
6
10
|
if (options.useTailwind) {
|
|
7
11
|
packageJson.devDependencies = {
|
|
8
12
|
...packageJson.devDependencies,
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,74 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { createProject } from "./commands/createProject.js";
|
|
4
|
+
import { spawn } from "child_process";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
4
9
|
const program = new Command();
|
|
10
|
+
// Main command handler for direct project creation
|
|
11
|
+
const handleProjectCreation = async (projectName, options) => {
|
|
12
|
+
await createProject(projectName, options);
|
|
13
|
+
};
|
|
14
|
+
// Helper to run vite with internal config
|
|
15
|
+
const runViteCommand = (command) => {
|
|
16
|
+
// Path to the compiled vite.config.js in dist
|
|
17
|
+
const configPath = path.resolve(__dirname, "runtime/bundler/vite.config.js");
|
|
18
|
+
const args = [command, "--config", configPath];
|
|
19
|
+
if (command === "dev") {
|
|
20
|
+
// Vite dev doesn't need 'dev' argument, just calling vite is enough
|
|
21
|
+
args.shift();
|
|
22
|
+
}
|
|
23
|
+
spawn("npx", ["vite", ...args], {
|
|
24
|
+
stdio: "inherit",
|
|
25
|
+
shell: true,
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
// Main command handler for direct project creation with command check
|
|
29
|
+
const handleRootAction = async (projectName, options) => {
|
|
30
|
+
const knownCommands = ["create", "dev", "build", "preview"];
|
|
31
|
+
if (projectName && !knownCommands.includes(projectName)) {
|
|
32
|
+
await handleProjectCreation(projectName, options);
|
|
33
|
+
}
|
|
34
|
+
else if (!projectName) {
|
|
35
|
+
program.help();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
// Root command
|
|
39
|
+
program
|
|
40
|
+
.version("0.8.0")
|
|
41
|
+
.argument("[project-name/command]")
|
|
42
|
+
.option("-f, --force", "Force creation in non-empty directory")
|
|
43
|
+
.action(async (arg, options) => {
|
|
44
|
+
// If it's a known command, Commander will handle it in the subcommand action.
|
|
45
|
+
// We only handle it here if it's NOT a known command.
|
|
46
|
+
const knownCommands = ["create", "dev", "build", "preview"];
|
|
47
|
+
if (arg && !knownCommands.includes(arg)) {
|
|
48
|
+
await handleProjectCreation(arg, options);
|
|
49
|
+
}
|
|
50
|
+
else if (!arg) {
|
|
51
|
+
program.help();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// Create subcommand (npx revine create my-app)
|
|
5
55
|
program
|
|
6
|
-
.
|
|
56
|
+
.command("create")
|
|
7
57
|
.argument("<project-name>")
|
|
8
58
|
.option("-f, --force", "Force creation in non-empty directory")
|
|
9
59
|
.action(async (projectName, options) => {
|
|
10
|
-
await
|
|
60
|
+
await handleProjectCreation(projectName, options);
|
|
11
61
|
});
|
|
62
|
+
program
|
|
63
|
+
.command("dev")
|
|
64
|
+
.description("Start the development server")
|
|
65
|
+
.action(() => runViteCommand("dev"));
|
|
66
|
+
program
|
|
67
|
+
.command("build")
|
|
68
|
+
.description("Build the project for production")
|
|
69
|
+
.action(() => runViteCommand("build"));
|
|
70
|
+
program
|
|
71
|
+
.command("preview")
|
|
72
|
+
.description("Preview the production build")
|
|
73
|
+
.action(() => runViteCommand("preview"));
|
|
12
74
|
program.parse(process.argv);
|
package/dist/prompts/project.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import inquirer from "inquirer";
|
|
2
|
-
import {
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
3
|
import { logInfo } from "../utils/logger.js";
|
|
4
4
|
/**
|
|
5
5
|
* Ask the user if they want to run the project after setup is complete.
|
|
6
|
-
* If the user confirms, it will
|
|
6
|
+
* If the user confirms, it will start the dev server using the same revine
|
|
7
|
+
* binary that was invoked (i.e. the local build), rather than the npm package.
|
|
7
8
|
* @param projectDir - The directory where the project was set up.
|
|
8
9
|
*/
|
|
9
10
|
export default async function runProject(projectDir) {
|
|
@@ -17,11 +18,13 @@ export default async function runProject(projectDir) {
|
|
|
17
18
|
]);
|
|
18
19
|
if (runProject) {
|
|
19
20
|
logInfo("Running your Revine project on dev server...");
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
// Use the same revine binary that the user invoked (process.argv[1])
|
|
22
|
+
// so that local development always uses the local build.
|
|
23
|
+
const revineBin = process.argv[1];
|
|
24
|
+
spawn("node", [revineBin, "dev"], {
|
|
25
|
+
cwd: projectDir,
|
|
26
|
+
stdio: "inherit",
|
|
27
|
+
shell: false,
|
|
28
|
+
});
|
|
26
29
|
}
|
|
27
30
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import react from "@vitejs/plugin-react";
|
|
2
|
+
import { revineLoggerPlugin } from "../viteLoggerPlugin.js";
|
|
3
|
+
import { revinePlugin } from "../revinePlugin.js";
|
|
4
|
+
export const defaultViteConfig = {
|
|
5
|
+
plugins: [react(), revinePlugin(), revineLoggerPlugin()],
|
|
6
|
+
logLevel: "silent",
|
|
7
|
+
server: {
|
|
8
|
+
clearScreen: false,
|
|
9
|
+
open: true,
|
|
10
|
+
port: 3000,
|
|
11
|
+
host: true,
|
|
12
|
+
},
|
|
13
|
+
build: {
|
|
14
|
+
outDir: "build",
|
|
15
|
+
emptyOutDir: true,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { merge } from "lodash-es";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import { defaultViteConfig } from "./defaults/vite.js";
|
|
5
|
+
import { loadUserConfig } from "./utils/loadUserConfig.js";
|
|
6
|
+
export async function generateRevineViteConfig() {
|
|
7
|
+
// Load the user's revine.config.ts
|
|
8
|
+
const userConfig = (await loadUserConfig());
|
|
9
|
+
// Merge user "vite" overrides with your default config
|
|
10
|
+
const finalConfig = merge({}, defaultViteConfig, userConfig.vite || {});
|
|
11
|
+
// Dynamically add Tailwind if present in the project
|
|
12
|
+
try {
|
|
13
|
+
const projectPkgPath = path.resolve(process.cwd(), "package.json");
|
|
14
|
+
const pkg = await fs.readJson(projectPkgPath);
|
|
15
|
+
const hasTailwind = pkg.devDependencies?.["@tailwindcss/vite"] ||
|
|
16
|
+
pkg.dependencies?.["@tailwindcss/vite"];
|
|
17
|
+
if (hasTailwind) {
|
|
18
|
+
const tailwindModule = "@tailwindcss/vite";
|
|
19
|
+
const { default: tailwindcss } = (await import(tailwindModule));
|
|
20
|
+
finalConfig.plugins = [...(finalConfig.plugins || []), tailwindcss()];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
// Ignore error if package.json not found or tailwind not importable
|
|
25
|
+
}
|
|
26
|
+
return finalConfig;
|
|
27
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const VIRTUAL_ROUTING_ID = "\0revine:routing";
|
|
2
|
+
/**
|
|
3
|
+
* The Revine Vite plugin.
|
|
4
|
+
*
|
|
5
|
+
* Provides a virtual module for `revine/routing` so that:
|
|
6
|
+
* - `import.meta.glob` is resolved by Vite in the *project* context (not node_modules)
|
|
7
|
+
* - React runtime is resolved from the project's own node_modules
|
|
8
|
+
*/
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
export function revinePlugin() {
|
|
11
|
+
return {
|
|
12
|
+
name: "revine",
|
|
13
|
+
resolveId(id) {
|
|
14
|
+
if (id === "revine/routing") {
|
|
15
|
+
return VIRTUAL_ROUTING_ID;
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
// Return the routing source as a virtual module.
|
|
19
|
+
// Because it's virtual (not inside node_modules), Vite processes
|
|
20
|
+
// import.meta.glob and all imports normally in the project context.
|
|
21
|
+
load(id) {
|
|
22
|
+
if (id === VIRTUAL_ROUTING_ID) {
|
|
23
|
+
return `
|
|
24
|
+
import { createBrowserRouter } from "react-router-dom";
|
|
25
|
+
import { lazy, Suspense, createElement } from "react";
|
|
26
|
+
|
|
27
|
+
// Eagerly load NotFound from the project's src directory.
|
|
28
|
+
const notFoundModules = import.meta.glob("/src/NotFound.tsx", { eager: true });
|
|
29
|
+
const NotFoundComponent = Object.values(notFoundModules)[0]?.default;
|
|
30
|
+
|
|
31
|
+
// Lazily load all page components under /src/pages.
|
|
32
|
+
const pages = import.meta.glob("/src/pages/**/*.tsx");
|
|
33
|
+
|
|
34
|
+
const routes = Object.entries(pages).map(([filePath, component]) => {
|
|
35
|
+
let cleaned = filePath.replace(/\\\\/g, "/");
|
|
36
|
+
cleaned = cleaned.replace(/.*\\/pages\\//, "");
|
|
37
|
+
cleaned = cleaned.replace(/\\.tsx$/i, "");
|
|
38
|
+
cleaned = cleaned.replace(/\\/index$/, "");
|
|
39
|
+
cleaned = cleaned.replace(/\\[(\\w+)\\]/g, ":$1");
|
|
40
|
+
if (cleaned === "index") cleaned = "";
|
|
41
|
+
|
|
42
|
+
const routePath = cleaned === "" ? "/" : \`/\${cleaned}\`;
|
|
43
|
+
const Component = lazy(component);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
path: routePath,
|
|
47
|
+
element: createElement(
|
|
48
|
+
Suspense,
|
|
49
|
+
{ fallback: createElement("div", null, "Loading\u2026") },
|
|
50
|
+
createElement(Component)
|
|
51
|
+
),
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// 404 fallback
|
|
56
|
+
routes.push({
|
|
57
|
+
path: "*",
|
|
58
|
+
element: NotFoundComponent
|
|
59
|
+
? createElement(NotFoundComponent)
|
|
60
|
+
: createElement("div", null, "404 - Page Not Found"),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export const router = createBrowserRouter(routes);
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { pathToFileURL } from "url";
|
|
3
|
+
export async function loadUserConfig() {
|
|
4
|
+
const configPath = path.resolve(process.cwd(), "revine.config.ts");
|
|
5
|
+
try {
|
|
6
|
+
const configModule = await import(pathToFileURL(configPath).href);
|
|
7
|
+
return configModule.default || {};
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
// If .ts fails, try .js or just return empty
|
|
11
|
+
try {
|
|
12
|
+
const configPathJs = path.resolve(process.cwd(), "revine.config.js");
|
|
13
|
+
const configModule = await import(pathToFileURL(configPathJs).href);
|
|
14
|
+
return configModule.default || {};
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import { generateRevineViteConfig } from "./generateConfig.js";
|
|
3
|
+
// Vite supports async config. We can do:
|
|
4
|
+
export default defineConfig(async () => {
|
|
5
|
+
// Merge defaults + user overrides
|
|
6
|
+
return (await generateRevineViteConfig());
|
|
7
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
export function revineLoggerPlugin() {
|
|
3
|
+
// custom chalk instance pointing to the indigo color
|
|
4
|
+
const indigo = chalk.hex("#6d28d9");
|
|
5
|
+
return {
|
|
6
|
+
name: "revine-logger",
|
|
7
|
+
configureServer(server) {
|
|
8
|
+
server.httpServer?.once("listening", () => {
|
|
9
|
+
const protocol = server.config.server.https ? "https" : "http";
|
|
10
|
+
const host = server.resolvedUrls?.local[0] || "localhost:3000";
|
|
11
|
+
const { network = [] } = server.resolvedUrls ?? {};
|
|
12
|
+
// Use the 'indigo' instance in place of 'chalk.cyan'
|
|
13
|
+
console.log(indigo("─────────────────────────────────────────────"));
|
|
14
|
+
console.log(indigo.bold("🚀 Revine Dev Server is now running!"));
|
|
15
|
+
console.log(indigo("─────────────────────────────────────────────"));
|
|
16
|
+
console.log(indigo(`Local: ${chalk.green(`${protocol}://${host}`)}`));
|
|
17
|
+
if (network.length) {
|
|
18
|
+
network.forEach((url) => {
|
|
19
|
+
console.log(indigo(`Network: ${chalk.green(url)}`));
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
console.log(indigo("─────────────────────────────────────────────"));
|
|
23
|
+
console.log("");
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createBrowserRouter } from "react-router-dom";
|
|
3
|
+
import { lazy, Suspense } from "react";
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
import NotFound from "/src/NotFound";
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
const pages = import.meta.glob("/src/pages/**/*.tsx");
|
|
8
|
+
const routes = Object.entries(pages).map(([filePath, component]) => {
|
|
9
|
+
let cleaned = filePath.replace(/\\/g, "/");
|
|
10
|
+
cleaned = cleaned.replace(/.*\/pages\//, "");
|
|
11
|
+
cleaned = cleaned.replace(/\.tsx$/i, "");
|
|
12
|
+
cleaned = cleaned.replace(/\/index$/, "");
|
|
13
|
+
cleaned = cleaned.replace(/\[(\w+)\]/g, ":$1");
|
|
14
|
+
if (cleaned === "index") {
|
|
15
|
+
cleaned = "";
|
|
16
|
+
}
|
|
17
|
+
const routePath = cleaned === "" ? "/" : `/${cleaned}`;
|
|
18
|
+
const Component = lazy(component);
|
|
19
|
+
return {
|
|
20
|
+
path: routePath,
|
|
21
|
+
element: (_jsx(Suspense, { fallback: _jsx("div", { children: "Loading..." }), children: _jsx(Component, {}) })),
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
// fallback route for 404s
|
|
25
|
+
routes.push({
|
|
26
|
+
path: "*",
|
|
27
|
+
element: _jsx(NotFound, {}),
|
|
28
|
+
});
|
|
29
|
+
export const router = createBrowserRouter(routes);
|
|
@@ -2,6 +2,7 @@ import { spawnSync } from "child_process";
|
|
|
2
2
|
import { logError, logInfo } from "../utils/logger.js";
|
|
3
3
|
export async function installDependencies(projectDir) {
|
|
4
4
|
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
5
|
+
// Step 1: npm install
|
|
5
6
|
const installResult = spawnSync(npmCmd, ["install"], {
|
|
6
7
|
stdio: "inherit",
|
|
7
8
|
cwd: projectDir,
|
|
@@ -12,4 +13,11 @@ export async function installDependencies(projectDir) {
|
|
|
12
13
|
logInfo("Try running manually: npm install");
|
|
13
14
|
process.exit(1);
|
|
14
15
|
}
|
|
16
|
+
// Step 2: Link local revine if available (replaces npm version with local build)
|
|
17
|
+
// This is a no-op if revine hasn't been globally linked via `npm link` in the revine repo.
|
|
18
|
+
spawnSync(npmCmd, ["link", "revine"], {
|
|
19
|
+
stdio: "pipe", // suppress output — silently skip if not linked
|
|
20
|
+
cwd: projectDir,
|
|
21
|
+
shell: true,
|
|
22
|
+
});
|
|
15
23
|
}
|