revine 0.9.1 → 1.0.1
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 +1 -1
- package/dist/client.d.ts +8 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +4 -0
- package/dist/components/Link.d.ts +8 -0
- package/dist/components/Link.d.ts.map +1 -0
- package/dist/components/Link.js +5 -0
- package/dist/components/NavLink.d.ts +8 -0
- package/dist/components/NavLink.d.ts.map +1 -0
- package/dist/components/NavLink.js +5 -0
- package/dist/index.js +33 -26
- package/dist/runtime/bundler/defaults/vite.d.ts +6 -0
- package/dist/runtime/bundler/defaults/vite.d.ts.map +1 -1
- package/dist/runtime/bundler/defaults/vite.js +8 -2
- package/dist/runtime/bundler/revinePlugin.d.ts +0 -7
- package/dist/runtime/bundler/revinePlugin.d.ts.map +1 -1
- package/dist/runtime/bundler/revinePlugin.js +70 -27
- package/dist/runtime/bundler/viteLoggerPlugin.d.ts.map +1 -1
- package/dist/runtime/bundler/viteLoggerPlugin.js +2 -2
- package/dist/runtime/defineConfig.d.ts +6 -0
- package/dist/runtime/defineConfig.d.ts.map +1 -0
- package/dist/runtime/defineConfig.js +3 -0
- package/dist/runtime/routing.d.ts +2 -0
- package/dist/runtime/routing.d.ts.map +1 -0
- package/dist/runtime/routing.js +1 -0
- package/dist/runtime/types.d.ts +5 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/setup/dependencies.d.ts.map +1 -1
- package/dist/setup/dependencies.js +1 -8
- package/package.json +7 -21
- package/src/client.ts +14 -0
- package/src/components/Link.tsx +18 -0
- package/src/components/NavLink.tsx +18 -0
- package/src/index.ts +41 -31
- package/src/runtime/bundler/defaults/vite.ts +8 -2
- package/src/runtime/bundler/revinePlugin.ts +71 -28
- package/src/runtime/bundler/viteLoggerPlugin.ts +4 -3
- package/src/runtime/defineConfig.ts +9 -0
- package/src/runtime/routing.ts +4 -0
- package/src/runtime/types.ts +5 -0
- package/src/setup/dependencies.ts +1 -9
- package/template/package.json +1 -2
- package/template/revine.config.ts +4 -2
- package/template/src/pages/index.tsx +18 -16
- package/template/src/root.tsx +2 -2
- package/tsconfig.json +4 -2
- package/dist/runtime/routing/fileBased.d.ts +0 -2
- package/dist/runtime/routing/fileBased.d.ts.map +0 -1
- package/dist/runtime/routing/fileBased.js +0 -29
- package/src/runtime/routing/fileBased.tsx +0 -46
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ src/pages/blog/[slug].tsx → /blog/:slug
|
|
|
58
58
|
### Clone repository
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
|
-
git clone https://github.com/your-username/revine.git
|
|
61
|
+
git clone [https://github.com/your-username/revine.git](https://github.com/rachit-bharadwaj/revine)
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
### Install dependencies
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { Outlet, RouterProvider, useLocation, useNavigate, useParams, useSearchParams } from "react-router-dom";
|
|
2
|
+
export type { NavLinkProps } from "./components/NavLink.js";
|
|
3
|
+
export { Link } from "./components/Link.js";
|
|
4
|
+
export { NavLink } from "./components/NavLink.js";
|
|
5
|
+
export { defineConfig } from "./runtime/defineConfig.js";
|
|
6
|
+
export type { LayoutProps } from "./runtime/types.js";
|
|
7
|
+
export type { LinkProps } from "./components/Link.js";
|
|
8
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,cAAc,EACd,WAAW,EACX,WAAW,EACX,SAAS,EACT,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type LinkProps as RouterLinkProps } from "react-router-dom";
|
|
3
|
+
export interface LinkProps extends Omit<RouterLinkProps, "to"> {
|
|
4
|
+
href: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare function Link({ href, children, ...rest }: LinkProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=Link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../src/components/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAEL,KAAK,SAAS,IAAI,eAAe,EAClC,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,2CAM1D"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type NavLinkProps as RouterNavLinkProps } from "react-router-dom";
|
|
3
|
+
export interface NavLinkProps extends Omit<RouterNavLinkProps, "to"> {
|
|
4
|
+
href: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare function NavLink({ href, children, ...rest }: NavLinkProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=NavLink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NavLink.d.ts","sourceRoot":"","sources":["../../src/components/NavLink.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAEL,KAAK,YAAY,IAAI,kBAAkB,EACxC,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,wBAAgB,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,YAAY,2CAMhE"}
|
package/dist/index.js
CHANGED
|
@@ -1,48 +1,55 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import {
|
|
4
|
-
import { spawn } from "child_process";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
5
4
|
import path from "path";
|
|
6
5
|
import { fileURLToPath } from "url";
|
|
6
|
+
import { createProject } from "./commands/createProject.js";
|
|
7
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
8
|
const __dirname = path.dirname(__filename);
|
|
9
|
+
const pkgPath = path.resolve(__dirname, "../package.json");
|
|
10
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
9
11
|
const program = new Command();
|
|
10
|
-
// Main command handler for direct project creation
|
|
11
12
|
const handleProjectCreation = async (projectName, options) => {
|
|
12
13
|
await createProject(projectName, options);
|
|
13
14
|
};
|
|
14
|
-
|
|
15
|
-
const runViteCommand = (command) => {
|
|
16
|
-
// Path to the compiled vite.config.js in dist
|
|
15
|
+
const runViteCommand = async (command) => {
|
|
17
16
|
const configPath = path.resolve(__dirname, "runtime/bundler/vite.config.js");
|
|
18
|
-
|
|
17
|
+
// Set the config path as env variable — vite reads VITE_CONFIG_FILE
|
|
18
|
+
process.env.VITE_CONFIG_PATH = configPath;
|
|
19
|
+
// Dynamically import vite's programmatic API
|
|
20
|
+
const vitePath = path.resolve(process.cwd(), "node_modules/vite/dist/node/index.js");
|
|
21
|
+
const vite = await import(vitePath);
|
|
22
|
+
// Load the revine config
|
|
23
|
+
const { generateRevineViteConfig } = await import(path.resolve(__dirname, "runtime/bundler/generateConfig.js"));
|
|
24
|
+
const config = await generateRevineViteConfig();
|
|
19
25
|
if (command === "dev") {
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
const server = await vite.createServer({
|
|
27
|
+
...config,
|
|
28
|
+
configFile: false, // we pass config directly, no file needed
|
|
29
|
+
});
|
|
30
|
+
await server.listen();
|
|
31
|
+
server.printUrls();
|
|
22
32
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
+
else if (command === "build") {
|
|
34
|
+
await vite.build({
|
|
35
|
+
...config,
|
|
36
|
+
configFile: false,
|
|
37
|
+
});
|
|
33
38
|
}
|
|
34
|
-
else if (
|
|
35
|
-
|
|
39
|
+
else if (command === "preview") {
|
|
40
|
+
const server = await vite.preview({
|
|
41
|
+
...config,
|
|
42
|
+
configFile: false,
|
|
43
|
+
});
|
|
44
|
+
server.printUrls();
|
|
36
45
|
}
|
|
37
46
|
};
|
|
38
|
-
// Root command
|
|
47
|
+
// Root command — handles: npx revine <project-name>
|
|
39
48
|
program
|
|
40
|
-
.version(
|
|
49
|
+
.version(pkg.version)
|
|
41
50
|
.argument("[project-name/command]")
|
|
42
51
|
.option("-f, --force", "Force creation in non-empty directory")
|
|
43
52
|
.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
53
|
const knownCommands = ["create", "dev", "build", "preview"];
|
|
47
54
|
if (arg && !knownCommands.includes(arg)) {
|
|
48
55
|
await handleProjectCreation(arg, options);
|
|
@@ -51,7 +58,7 @@ program
|
|
|
51
58
|
program.help();
|
|
52
59
|
}
|
|
53
60
|
});
|
|
54
|
-
//
|
|
61
|
+
// npx revine create <project-name>
|
|
55
62
|
program
|
|
56
63
|
.command("create")
|
|
57
64
|
.argument("<project-name>")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../../../../src/runtime/bundler/defaults/vite.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../../../../src/runtime/bundler/defaults/vite.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;CAmB7B,CAAC"}
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import react from "@vitejs/plugin-react";
|
|
2
|
-
import { revineLoggerPlugin } from "../viteLoggerPlugin.js";
|
|
3
2
|
import { revinePlugin } from "../revinePlugin.js";
|
|
3
|
+
import { revineLoggerPlugin } from "../viteLoggerPlugin.js";
|
|
4
4
|
export const defaultViteConfig = {
|
|
5
5
|
plugins: [react(), revinePlugin(), revineLoggerPlugin()],
|
|
6
6
|
logLevel: "silent",
|
|
7
7
|
server: {
|
|
8
8
|
clearScreen: false,
|
|
9
|
-
open:
|
|
9
|
+
open: false,
|
|
10
10
|
port: 3000,
|
|
11
11
|
host: true,
|
|
12
12
|
},
|
|
13
13
|
build: {
|
|
14
14
|
outDir: "build",
|
|
15
15
|
emptyOutDir: true,
|
|
16
|
+
rollupOptions: {
|
|
17
|
+
external: ["revine"],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
optimizeDeps: {
|
|
21
|
+
exclude: ["revine"],
|
|
16
22
|
},
|
|
17
23
|
};
|
|
@@ -1,9 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Revine Vite plugin.
|
|
3
|
-
*
|
|
4
|
-
* Provides a virtual module for `revine/routing` so that:
|
|
5
|
-
* - `import.meta.glob` is resolved by Vite in the *project* context (not node_modules)
|
|
6
|
-
* - React runtime is resolved from the project's own node_modules
|
|
7
|
-
*/
|
|
8
1
|
export declare function revinePlugin(): any;
|
|
9
2
|
//# sourceMappingURL=revinePlugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"revinePlugin.d.ts","sourceRoot":"","sources":["../../../src/runtime/bundler/revinePlugin.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"revinePlugin.d.ts","sourceRoot":"","sources":["../../../src/runtime/bundler/revinePlugin.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,IAAI,GAAG,CA+GlC"}
|
|
@@ -1,58 +1,101 @@
|
|
|
1
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
2
|
export function revinePlugin() {
|
|
11
3
|
return {
|
|
12
4
|
name: "revine",
|
|
5
|
+
enforce: "pre",
|
|
13
6
|
resolveId(id) {
|
|
14
7
|
if (id === "revine/routing") {
|
|
15
8
|
return VIRTUAL_ROUTING_ID;
|
|
16
9
|
}
|
|
17
10
|
},
|
|
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
11
|
load(id) {
|
|
22
12
|
if (id === VIRTUAL_ROUTING_ID) {
|
|
23
13
|
return `
|
|
24
14
|
import { createBrowserRouter } from "react-router-dom";
|
|
25
15
|
import { lazy, Suspense, createElement } from "react";
|
|
26
16
|
|
|
27
|
-
// Eagerly load NotFound from the project's src directory.
|
|
28
17
|
const notFoundModules = import.meta.glob("/src/NotFound.tsx", { eager: true });
|
|
29
18
|
const NotFoundComponent = Object.values(notFoundModules)[0]?.default;
|
|
30
19
|
|
|
31
|
-
// Lazily load all page components under /src/pages.
|
|
32
20
|
const pages = import.meta.glob("/src/pages/**/*.tsx");
|
|
21
|
+
const layoutModules = import.meta.glob("/src/pages/**/layout.tsx", { eager: true });
|
|
22
|
+
const loadingModules = import.meta.glob("/src/pages/**/loading.tsx", { eager: true });
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
function getLayoutsForPath(filePath) {
|
|
25
|
+
const parts = filePath.split("/");
|
|
26
|
+
parts.pop();
|
|
27
|
+
const layouts = [];
|
|
28
|
+
const accumulated = [];
|
|
29
|
+
for (const part of parts) {
|
|
30
|
+
accumulated.push(part);
|
|
31
|
+
const key = accumulated.join("/") + "/layout.tsx";
|
|
32
|
+
if (layoutModules[key] && layoutModules[key].default) {
|
|
33
|
+
layouts.push(layoutModules[key].default);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return layouts;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getLoadingForPath(filePath) {
|
|
40
|
+
const parts = filePath.split("/");
|
|
41
|
+
parts.pop();
|
|
42
|
+
while (parts.length >= 2) {
|
|
43
|
+
const key = parts.join("/") + "/loading.tsx";
|
|
44
|
+
if (loadingModules[key] && loadingModules[key].default) {
|
|
45
|
+
return loadingModules[key].default;
|
|
46
|
+
}
|
|
47
|
+
parts.pop();
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
41
51
|
|
|
42
|
-
|
|
52
|
+
function wrapWithLayouts(element, layouts) {
|
|
53
|
+
return layouts.reduceRight((wrapped, Layout) => {
|
|
54
|
+
return createElement(Layout, null, wrapped);
|
|
55
|
+
}, element);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function toRoutePath(filePath) {
|
|
59
|
+
let p = filePath;
|
|
60
|
+
p = p.replace(/[\\\\]/g, "/");
|
|
61
|
+
p = p.replace(/.*[/]pages[/]/, "");
|
|
62
|
+
p = p.replace(/[.]tsx$/i, "");
|
|
63
|
+
p = p.replace(/[/]index$/, "");
|
|
64
|
+
p = p.replace(/[(][^)]+[)][/]/g, "");
|
|
65
|
+
p = p.replace(/[[]([\\w]+)[\\]]/g, ":$1");
|
|
66
|
+
if (p === "index" || p === "") return "/";
|
|
67
|
+
return "/" + p;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const pageEntries = Object.entries(pages).filter(([filePath]) => {
|
|
71
|
+
if (filePath.endsWith("/layout.tsx")) return false;
|
|
72
|
+
if (filePath.endsWith("/loading.tsx")) return false;
|
|
73
|
+
const segments = filePath.split("/");
|
|
74
|
+
return !segments.some((s) => s.startsWith("_"));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const routes = pageEntries.map(([filePath, component]) => {
|
|
78
|
+
const routePath = toRoutePath(filePath);
|
|
43
79
|
const Component = lazy(component);
|
|
80
|
+
const layouts = getLayoutsForPath(filePath);
|
|
81
|
+
const Loading = getLoadingForPath(filePath);
|
|
82
|
+
|
|
83
|
+
const fallback = Loading
|
|
84
|
+
? createElement(Loading)
|
|
85
|
+
: createElement("div", null, "Loading\\u2026");
|
|
86
|
+
|
|
87
|
+
const pageElement = createElement(
|
|
88
|
+
Suspense,
|
|
89
|
+
{ fallback },
|
|
90
|
+
createElement(Component)
|
|
91
|
+
);
|
|
44
92
|
|
|
45
93
|
return {
|
|
46
94
|
path: routePath,
|
|
47
|
-
element:
|
|
48
|
-
Suspense,
|
|
49
|
-
{ fallback: createElement("div", null, "Loading\u2026") },
|
|
50
|
-
createElement(Component)
|
|
51
|
-
),
|
|
95
|
+
element: layouts.length > 0 ? wrapWithLayouts(pageElement, layouts) : pageElement,
|
|
52
96
|
};
|
|
53
97
|
});
|
|
54
98
|
|
|
55
|
-
// 404 fallback
|
|
56
99
|
routes.push({
|
|
57
100
|
path: "*",
|
|
58
101
|
element: NotFoundComponent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viteLoggerPlugin.d.ts","sourceRoot":"","sources":["../../../src/runtime/bundler/viteLoggerPlugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"viteLoggerPlugin.d.ts","sourceRoot":"","sources":["../../../src/runtime/bundler/viteLoggerPlugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAElD,wBAAgB,kBAAkB,IAAI,MAAM,CA8B3C"}
|
|
@@ -7,13 +7,13 @@ export function revineLoggerPlugin() {
|
|
|
7
7
|
configureServer(server) {
|
|
8
8
|
server.httpServer?.once("listening", () => {
|
|
9
9
|
const protocol = server.config.server.https ? "https" : "http";
|
|
10
|
-
const
|
|
10
|
+
const localUrl = server.resolvedUrls?.local[0] || `http://localhost:3000`;
|
|
11
11
|
const { network = [] } = server.resolvedUrls ?? {};
|
|
12
12
|
// Use the 'indigo' instance in place of 'chalk.cyan'
|
|
13
13
|
console.log(indigo("─────────────────────────────────────────────"));
|
|
14
14
|
console.log(indigo.bold("🚀 Revine Dev Server is now running!"));
|
|
15
15
|
console.log(indigo("─────────────────────────────────────────────"));
|
|
16
|
-
console.log(indigo(`Local: ${chalk.green(
|
|
16
|
+
console.log(indigo(`Local: ${chalk.green(localUrl)}`));
|
|
17
17
|
if (network.length) {
|
|
18
18
|
network.forEach((url) => {
|
|
19
19
|
console.log(indigo(`Network: ${chalk.green(url)}`));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineConfig.d.ts","sourceRoot":"","sources":["../../src/runtime/defineConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAEvC,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAE/D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/runtime/routing.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,SAAS,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../src/setup/dependencies.ts"],"names":[],"mappings":"AAGA,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../src/setup/dependencies.ts"],"names":[],"mappings":"AAGA,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc3E"}
|
|
@@ -6,18 +6,11 @@ export async function installDependencies(projectDir) {
|
|
|
6
6
|
const installResult = spawnSync(npmCmd, ["install"], {
|
|
7
7
|
stdio: "inherit",
|
|
8
8
|
cwd: projectDir,
|
|
9
|
-
shell:
|
|
9
|
+
shell: false,
|
|
10
10
|
});
|
|
11
11
|
if (installResult.error || installResult.status !== 0) {
|
|
12
12
|
logError("Error installing dependencies:", installResult.error);
|
|
13
13
|
logInfo("Try running manually: npm install");
|
|
14
14
|
process.exit(1);
|
|
15
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
|
-
});
|
|
23
16
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "revine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A react framework, but better.",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "MIT",
|
|
6
6
|
"author": "Rachit Bharadwaj",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "dist/index.js",
|
|
@@ -11,28 +11,15 @@
|
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
14
|
-
"import": "./dist/
|
|
15
|
-
"types": "./dist/
|
|
14
|
+
"import": "./dist/client.js",
|
|
15
|
+
"types": "./dist/client.d.ts"
|
|
16
16
|
},
|
|
17
17
|
"./routing": {
|
|
18
|
-
"import": "./dist/runtime/routing
|
|
19
|
-
"types": "./dist/runtime/routing
|
|
20
|
-
},
|
|
21
|
-
"./bundler/*": {
|
|
22
|
-
"import": "./dist/runtime/bundler/*.js",
|
|
23
|
-
"types": "./dist/runtime/bundler/*.d.ts"
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"typesVersions": {
|
|
27
|
-
"*": {
|
|
28
|
-
"routing": [
|
|
29
|
-
"./dist/runtime/routing/fileBased.d.ts"
|
|
30
|
-
],
|
|
31
|
-
"bundler/*": [
|
|
32
|
-
"./dist/runtime/bundler/*.d.ts"
|
|
33
|
-
]
|
|
18
|
+
"import": "./dist/runtime/routing.js",
|
|
19
|
+
"types": "./dist/runtime/routing.d.ts"
|
|
34
20
|
}
|
|
35
21
|
},
|
|
22
|
+
"typesVersions": {},
|
|
36
23
|
"scripts": {
|
|
37
24
|
"build": "tsc",
|
|
38
25
|
"dev": "tsc -w",
|
|
@@ -42,7 +29,6 @@
|
|
|
42
29
|
"@vitejs/plugin-react": "^4.2.1",
|
|
43
30
|
"chalk": "^5.4.1",
|
|
44
31
|
"commander": "^13.1.0",
|
|
45
|
-
"cross-spawn": "^7.0.6",
|
|
46
32
|
"fs-extra": "^11.3.0",
|
|
47
33
|
"inquirer": "^12.4.1",
|
|
48
34
|
"lodash-es": "^4.17.21",
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export {
|
|
2
|
+
Outlet,
|
|
3
|
+
RouterProvider,
|
|
4
|
+
useLocation,
|
|
5
|
+
useNavigate,
|
|
6
|
+
useParams,
|
|
7
|
+
useSearchParams
|
|
8
|
+
} from "react-router-dom";
|
|
9
|
+
export type { NavLinkProps } from "./components/NavLink.js";
|
|
10
|
+
export { Link } from "./components/Link.js";
|
|
11
|
+
export { NavLink } from "./components/NavLink.js";
|
|
12
|
+
export { defineConfig } from "./runtime/defineConfig.js";
|
|
13
|
+
export type { LayoutProps } from "./runtime/types.js";
|
|
14
|
+
export type { LinkProps } from "./components/Link.js";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Link as RouterLink,
|
|
4
|
+
type LinkProps as RouterLinkProps,
|
|
5
|
+
} from "react-router-dom";
|
|
6
|
+
|
|
7
|
+
export interface LinkProps extends Omit<RouterLinkProps, "to"> {
|
|
8
|
+
href: string;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Link({ href, children, ...rest }: LinkProps) {
|
|
13
|
+
return (
|
|
14
|
+
<RouterLink to={href} {...rest}>
|
|
15
|
+
{children}
|
|
16
|
+
</RouterLink>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import {
|
|
3
|
+
NavLink as RouterNavLink,
|
|
4
|
+
type NavLinkProps as RouterNavLinkProps,
|
|
5
|
+
} from "react-router-dom";
|
|
6
|
+
|
|
7
|
+
export interface NavLinkProps extends Omit<RouterNavLinkProps, "to"> {
|
|
8
|
+
href: string;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function NavLink({ href, children, ...rest }: NavLinkProps) {
|
|
13
|
+
return (
|
|
14
|
+
<RouterNavLink to={href} {...rest}>
|
|
15
|
+
{children}
|
|
16
|
+
</RouterNavLink>
|
|
17
|
+
);
|
|
18
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import {
|
|
4
|
-
import { spawn } from "child_process";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
5
4
|
import path from "path";
|
|
6
5
|
import { fileURLToPath } from "url";
|
|
6
|
+
import { createProject } from "./commands/createProject.js";
|
|
7
7
|
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = path.dirname(__filename);
|
|
10
10
|
|
|
11
|
+
const pkgPath = path.resolve(__dirname, "../package.json");
|
|
12
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
13
|
+
|
|
11
14
|
const program = new Command();
|
|
12
15
|
|
|
13
|
-
// Main command handler for direct project creation
|
|
14
16
|
const handleProjectCreation = async (
|
|
15
17
|
projectName: string,
|
|
16
18
|
options: { force?: boolean },
|
|
@@ -18,44 +20,52 @@ const handleProjectCreation = async (
|
|
|
18
20
|
await createProject(projectName, options);
|
|
19
21
|
};
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
const runViteCommand = (command: string) => {
|
|
23
|
-
// Path to the compiled vite.config.js in dist
|
|
23
|
+
const runViteCommand = async (command: string) => {
|
|
24
24
|
const configPath = path.resolve(__dirname, "runtime/bundler/vite.config.js");
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// Vite dev doesn't need 'dev' argument, just calling vite is enough
|
|
29
|
-
args.shift();
|
|
30
|
-
}
|
|
26
|
+
// Set the config path as env variable — vite reads VITE_CONFIG_FILE
|
|
27
|
+
process.env.VITE_CONFIG_PATH = configPath;
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
// Dynamically import vite's programmatic API
|
|
30
|
+
const vitePath = path.resolve(
|
|
31
|
+
process.cwd(),
|
|
32
|
+
"node_modules/vite/dist/node/index.js",
|
|
33
|
+
);
|
|
34
|
+
const vite = await import(vitePath);
|
|
37
35
|
|
|
38
|
-
//
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
await
|
|
46
|
-
|
|
47
|
-
|
|
36
|
+
// Load the revine config
|
|
37
|
+
const { generateRevineViteConfig } = await import(
|
|
38
|
+
path.resolve(__dirname, "runtime/bundler/generateConfig.js")
|
|
39
|
+
);
|
|
40
|
+
const config = await generateRevineViteConfig();
|
|
41
|
+
|
|
42
|
+
if (command === "dev") {
|
|
43
|
+
const server = await vite.createServer({
|
|
44
|
+
...config,
|
|
45
|
+
configFile: false, // we pass config directly, no file needed
|
|
46
|
+
});
|
|
47
|
+
await server.listen();
|
|
48
|
+
server.printUrls();
|
|
49
|
+
} else if (command === "build") {
|
|
50
|
+
await vite.build({
|
|
51
|
+
...config,
|
|
52
|
+
configFile: false,
|
|
53
|
+
});
|
|
54
|
+
} else if (command === "preview") {
|
|
55
|
+
const server = await vite.preview({
|
|
56
|
+
...config,
|
|
57
|
+
configFile: false,
|
|
58
|
+
});
|
|
59
|
+
server.printUrls();
|
|
48
60
|
}
|
|
49
61
|
};
|
|
50
62
|
|
|
51
|
-
// Root command
|
|
63
|
+
// Root command — handles: npx revine <project-name>
|
|
52
64
|
program
|
|
53
|
-
.version(
|
|
65
|
+
.version(pkg.version)
|
|
54
66
|
.argument("[project-name/command]")
|
|
55
67
|
.option("-f, --force", "Force creation in non-empty directory")
|
|
56
68
|
.action(async (arg: string | undefined, options: { force?: boolean }) => {
|
|
57
|
-
// If it's a known command, Commander will handle it in the subcommand action.
|
|
58
|
-
// We only handle it here if it's NOT a known command.
|
|
59
69
|
const knownCommands = ["create", "dev", "build", "preview"];
|
|
60
70
|
if (arg && !knownCommands.includes(arg)) {
|
|
61
71
|
await handleProjectCreation(arg, options);
|
|
@@ -64,7 +74,7 @@ program
|
|
|
64
74
|
}
|
|
65
75
|
});
|
|
66
76
|
|
|
67
|
-
//
|
|
77
|
+
// npx revine create <project-name>
|
|
68
78
|
program
|
|
69
79
|
.command("create")
|
|
70
80
|
.argument("<project-name>")
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import react from "@vitejs/plugin-react";
|
|
2
|
-
import { revineLoggerPlugin } from "../viteLoggerPlugin.js";
|
|
3
2
|
import { revinePlugin } from "../revinePlugin.js";
|
|
3
|
+
import { revineLoggerPlugin } from "../viteLoggerPlugin.js";
|
|
4
4
|
|
|
5
5
|
export const defaultViteConfig = {
|
|
6
6
|
plugins: [react(), revinePlugin(), revineLoggerPlugin()],
|
|
7
7
|
logLevel: "silent",
|
|
8
8
|
server: {
|
|
9
9
|
clearScreen: false,
|
|
10
|
-
open:
|
|
10
|
+
open: false,
|
|
11
11
|
port: 3000,
|
|
12
12
|
host: true,
|
|
13
13
|
},
|
|
14
14
|
build: {
|
|
15
15
|
outDir: "build",
|
|
16
16
|
emptyOutDir: true,
|
|
17
|
+
rollupOptions: {
|
|
18
|
+
external: ["revine"],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
optimizeDeps: {
|
|
22
|
+
exclude: ["revine"],
|
|
17
23
|
},
|
|
18
24
|
};
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
const VIRTUAL_ROUTING_ID = "\0revine:routing";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* The Revine Vite plugin.
|
|
5
|
-
*
|
|
6
|
-
* Provides a virtual module for `revine/routing` so that:
|
|
7
|
-
* - `import.meta.glob` is resolved by Vite in the *project* context (not node_modules)
|
|
8
|
-
* - React runtime is resolved from the project's own node_modules
|
|
9
|
-
*/
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
3
|
export function revinePlugin(): any {
|
|
12
4
|
return {
|
|
13
5
|
name: "revine",
|
|
6
|
+
enforce: "pre",
|
|
14
7
|
|
|
15
8
|
resolveId(id: string) {
|
|
16
9
|
if (id === "revine/routing") {
|
|
@@ -18,44 +11,94 @@ export function revinePlugin(): any {
|
|
|
18
11
|
}
|
|
19
12
|
},
|
|
20
13
|
|
|
21
|
-
// Return the routing source as a virtual module.
|
|
22
|
-
// Because it's virtual (not inside node_modules), Vite processes
|
|
23
|
-
// import.meta.glob and all imports normally in the project context.
|
|
24
14
|
load(id: string) {
|
|
25
15
|
if (id === VIRTUAL_ROUTING_ID) {
|
|
26
16
|
return `
|
|
27
17
|
import { createBrowserRouter } from "react-router-dom";
|
|
28
18
|
import { lazy, Suspense, createElement } from "react";
|
|
29
19
|
|
|
30
|
-
// Eagerly load NotFound from the project's src directory.
|
|
31
20
|
const notFoundModules = import.meta.glob("/src/NotFound.tsx", { eager: true });
|
|
32
21
|
const NotFoundComponent = Object.values(notFoundModules)[0]?.default;
|
|
33
22
|
|
|
34
|
-
// Lazily load all page components under /src/pages.
|
|
35
23
|
const pages = import.meta.glob("/src/pages/**/*.tsx");
|
|
24
|
+
const layoutModules = import.meta.glob("/src/pages/**/layout.tsx", { eager: true });
|
|
25
|
+
const loadingModules = import.meta.glob("/src/pages/**/loading.tsx", { eager: true });
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
27
|
+
function getLayoutsForPath(filePath) {
|
|
28
|
+
const parts = filePath.split("/");
|
|
29
|
+
parts.pop();
|
|
30
|
+
const layouts = [];
|
|
31
|
+
const accumulated = [];
|
|
32
|
+
for (const part of parts) {
|
|
33
|
+
accumulated.push(part);
|
|
34
|
+
const key = accumulated.join("/") + "/layout.tsx";
|
|
35
|
+
if (layoutModules[key] && layoutModules[key].default) {
|
|
36
|
+
layouts.push(layoutModules[key].default);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return layouts;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getLoadingForPath(filePath) {
|
|
43
|
+
const parts = filePath.split("/");
|
|
44
|
+
parts.pop();
|
|
45
|
+
while (parts.length >= 2) {
|
|
46
|
+
const key = parts.join("/") + "/loading.tsx";
|
|
47
|
+
if (loadingModules[key] && loadingModules[key].default) {
|
|
48
|
+
return loadingModules[key].default;
|
|
49
|
+
}
|
|
50
|
+
parts.pop();
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function wrapWithLayouts(element, layouts) {
|
|
56
|
+
return layouts.reduceRight((wrapped, Layout) => {
|
|
57
|
+
return createElement(Layout, null, wrapped);
|
|
58
|
+
}, element);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function toRoutePath(filePath) {
|
|
62
|
+
let p = filePath;
|
|
63
|
+
p = p.replace(/[\\\\]/g, "/");
|
|
64
|
+
p = p.replace(/.*[/]pages[/]/, "");
|
|
65
|
+
p = p.replace(/[.]tsx$/i, "");
|
|
66
|
+
p = p.replace(/[/]index$/, "");
|
|
67
|
+
p = p.replace(/[(][^)]+[)][/]/g, "");
|
|
68
|
+
p = p.replace(/[[]([\\w]+)[\\]]/g, ":$1");
|
|
69
|
+
if (p === "index" || p === "") return "/";
|
|
70
|
+
return "/" + p;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const pageEntries = Object.entries(pages).filter(([filePath]) => {
|
|
74
|
+
if (filePath.endsWith("/layout.tsx")) return false;
|
|
75
|
+
if (filePath.endsWith("/loading.tsx")) return false;
|
|
76
|
+
const segments = filePath.split("/");
|
|
77
|
+
return !segments.some((s) => s.startsWith("_"));
|
|
78
|
+
});
|
|
44
79
|
|
|
45
|
-
|
|
80
|
+
const routes = pageEntries.map(([filePath, component]) => {
|
|
81
|
+
const routePath = toRoutePath(filePath);
|
|
46
82
|
const Component = lazy(component);
|
|
83
|
+
const layouts = getLayoutsForPath(filePath);
|
|
84
|
+
const Loading = getLoadingForPath(filePath);
|
|
85
|
+
|
|
86
|
+
const fallback = Loading
|
|
87
|
+
? createElement(Loading)
|
|
88
|
+
: createElement("div", null, "Loading\\u2026");
|
|
89
|
+
|
|
90
|
+
const pageElement = createElement(
|
|
91
|
+
Suspense,
|
|
92
|
+
{ fallback },
|
|
93
|
+
createElement(Component)
|
|
94
|
+
);
|
|
47
95
|
|
|
48
96
|
return {
|
|
49
97
|
path: routePath,
|
|
50
|
-
element:
|
|
51
|
-
Suspense,
|
|
52
|
-
{ fallback: createElement("div", null, "Loading\u2026") },
|
|
53
|
-
createElement(Component)
|
|
54
|
-
),
|
|
98
|
+
element: layouts.length > 0 ? wrapWithLayouts(pageElement, layouts) : pageElement,
|
|
55
99
|
};
|
|
56
100
|
});
|
|
57
101
|
|
|
58
|
-
// 404 fallback
|
|
59
102
|
routes.push({
|
|
60
103
|
path: "*",
|
|
61
104
|
element: NotFoundComponent
|
|
@@ -68,4 +111,4 @@ export const router = createBrowserRouter(routes);
|
|
|
68
111
|
}
|
|
69
112
|
},
|
|
70
113
|
};
|
|
71
|
-
}
|
|
114
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Plugin, ViteDevServer } from "vite";
|
|
2
1
|
import chalk from "chalk";
|
|
2
|
+
import type { Plugin, ViteDevServer } from "vite";
|
|
3
3
|
|
|
4
4
|
export function revineLoggerPlugin(): Plugin {
|
|
5
5
|
// custom chalk instance pointing to the indigo color
|
|
@@ -10,14 +10,15 @@ export function revineLoggerPlugin(): Plugin {
|
|
|
10
10
|
configureServer(server: ViteDevServer) {
|
|
11
11
|
server.httpServer?.once("listening", () => {
|
|
12
12
|
const protocol = server.config.server.https ? "https" : "http";
|
|
13
|
-
const
|
|
13
|
+
const localUrl =
|
|
14
|
+
server.resolvedUrls?.local[0] || `http://localhost:3000`;
|
|
14
15
|
const { network = [] } = server.resolvedUrls ?? {};
|
|
15
16
|
|
|
16
17
|
// Use the 'indigo' instance in place of 'chalk.cyan'
|
|
17
18
|
console.log(indigo("─────────────────────────────────────────────"));
|
|
18
19
|
console.log(indigo.bold("🚀 Revine Dev Server is now running!"));
|
|
19
20
|
console.log(indigo("─────────────────────────────────────────────"));
|
|
20
|
-
console.log(indigo(`Local: ${chalk.green(
|
|
21
|
+
console.log(indigo(`Local: ${chalk.green(localUrl)}`));
|
|
21
22
|
|
|
22
23
|
if (network.length) {
|
|
23
24
|
network.forEach((url: string) => {
|
|
@@ -8,19 +8,11 @@ export async function installDependencies(projectDir: string): Promise<void> {
|
|
|
8
8
|
const installResult = spawnSync(npmCmd, ["install"], {
|
|
9
9
|
stdio: "inherit",
|
|
10
10
|
cwd: projectDir,
|
|
11
|
-
shell:
|
|
11
|
+
shell: false,
|
|
12
12
|
});
|
|
13
13
|
if (installResult.error || installResult.status !== 0) {
|
|
14
14
|
logError("Error installing dependencies:", installResult.error);
|
|
15
15
|
logInfo("Try running manually: npm install");
|
|
16
16
|
process.exit(1);
|
|
17
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
18
|
}
|
package/template/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Link } from "revine";
|
|
2
|
+
|
|
1
3
|
export default function HomePage() {
|
|
2
4
|
return (
|
|
3
5
|
<main>
|
|
@@ -11,51 +13,51 @@ export default function HomePage() {
|
|
|
11
13
|
|
|
12
14
|
{/* CTA Buttons */}
|
|
13
15
|
<div className="cta">
|
|
14
|
-
<
|
|
16
|
+
<Link href="#get-started" className="primary-btn">
|
|
15
17
|
Get Started
|
|
16
|
-
</
|
|
17
|
-
<
|
|
18
|
+
</Link>
|
|
19
|
+
<Link href="#docs" className="secondary-btn">
|
|
18
20
|
Read Docs
|
|
19
|
-
</
|
|
21
|
+
</Link>
|
|
20
22
|
</div>
|
|
21
23
|
|
|
22
24
|
{/* Features Section */}
|
|
23
25
|
<div className="features">
|
|
24
|
-
<
|
|
26
|
+
<Link href="#fast">
|
|
25
27
|
<h3>Lightning Fast</h3>
|
|
26
28
|
<p>Built on Vite for ultra-fast development and instant HMR.</p>
|
|
27
|
-
</
|
|
28
|
-
<
|
|
29
|
+
</Link>
|
|
30
|
+
<Link href="#routing">
|
|
29
31
|
<h3>Simple File-based Routing</h3>
|
|
30
32
|
<p>
|
|
31
33
|
Create pages in <code>src/pages</code> and Revine will handle the
|
|
32
34
|
rest.
|
|
33
35
|
</p>
|
|
34
|
-
</
|
|
35
|
-
<
|
|
36
|
+
</Link>
|
|
37
|
+
<Link href="#tailwind">
|
|
36
38
|
<h3>Tailwind Integration</h3>
|
|
37
39
|
<p>
|
|
38
40
|
Pre-configured for Tailwind CSS, so you can style quickly and
|
|
39
41
|
easily.
|
|
40
42
|
</p>
|
|
41
|
-
</
|
|
42
|
-
<
|
|
43
|
+
</Link>
|
|
44
|
+
<Link href="#dev-experience">
|
|
43
45
|
<h3>Great DX</h3>
|
|
44
46
|
<p>Minimal config, fast builds, custom logging, and more.</p>
|
|
45
|
-
</
|
|
46
|
-
<
|
|
47
|
+
</Link>
|
|
48
|
+
<Link href="#abstract">
|
|
47
49
|
<h3>Abstracted Internals</h3>
|
|
48
50
|
<p>
|
|
49
51
|
A .revine folder houses the complex Vite config. Keep your root
|
|
50
52
|
clean.
|
|
51
53
|
</p>
|
|
52
|
-
</
|
|
53
|
-
<
|
|
54
|
+
</Link>
|
|
55
|
+
<Link href="#customize">
|
|
54
56
|
<h3>Fully Customizable</h3>
|
|
55
57
|
<p>
|
|
56
58
|
Easily extend or override settings in <code>revine.config.ts</code>.
|
|
57
59
|
</p>
|
|
58
|
-
</
|
|
60
|
+
</Link>
|
|
59
61
|
</div>
|
|
60
62
|
</main>
|
|
61
63
|
);
|
package/template/src/root.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { createRoot } from "react-dom/client";
|
|
3
|
-
import { RouterProvider } from "
|
|
3
|
+
import { RouterProvider } from "revine";
|
|
4
4
|
import { router } from "revine/routing";
|
|
5
5
|
import "./styles/global.css";
|
|
6
6
|
|
|
@@ -11,4 +11,4 @@ root.render(
|
|
|
11
11
|
<React.StrictMode>
|
|
12
12
|
<RouterProvider router={router} />
|
|
13
13
|
</React.StrictMode>,
|
|
14
|
-
);
|
|
14
|
+
);
|
package/tsconfig.json
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2020",
|
|
4
4
|
"module": "ES2020",
|
|
5
|
-
"moduleResolution": "
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"rootDir": "src",
|
|
6
7
|
"outDir": "dist",
|
|
7
8
|
"strict": true,
|
|
8
9
|
"esModuleInterop": true,
|
|
@@ -11,7 +12,8 @@
|
|
|
11
12
|
"jsx": "react-jsx",
|
|
12
13
|
"declaration": true,
|
|
13
14
|
"declarationMap": true,
|
|
14
|
-
"emitDeclarationOnly": false
|
|
15
|
+
"emitDeclarationOnly": false,
|
|
16
|
+
"resolveJsonModule": true
|
|
15
17
|
},
|
|
16
18
|
"include": ["src/**/*"],
|
|
17
19
|
"exclude": ["src/template/**/*"]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fileBased.d.ts","sourceRoot":"","sources":["../../../src/runtime/routing/fileBased.tsx"],"names":[],"mappings":"AA6CA,eAAO,MAAM,MAAM,oCAA8B,CAAC"}
|
|
@@ -1,29 +0,0 @@
|
|
|
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);
|
|
@@ -1,46 +0,0 @@
|
|
|
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);
|