diff --git a/.changeset/eleven-birds-return.md b/.changeset/eleven-birds-return.md
new file mode 100644
index 00000000..ec7e8357
--- /dev/null
+++ b/.changeset/eleven-birds-return.md
@@ -0,0 +1,8 @@
+---
+"@vinxi/server-components": patch
+"@vinxi/server-functions": patch
+"@vinxi/plugin-directives": patch
+"vinxi": patch
+---
+
+added a stacks feature to quickly build up app config from the CLI (experimental)
diff --git a/examples/react/rsc/spa/CHANGELOG.md b/examples/react/rsc/spa/CHANGELOG.md
index b3fa89e3..82ad0027 100644
--- a/examples/react/rsc/spa/CHANGELOG.md
+++ b/examples/react/rsc/spa/CHANGELOG.md
@@ -6,8 +6,8 @@
- Updated dependencies [978b04a]
- vinxi@0.0.43
- - @vinxi/plugin-server-components@0.0.35
- - @vinxi/plugin-server-functions@0.0.35
+ - @vinxi/server-components@0.0.35
+ - @vinxi/server-functions@0.0.35
## null
@@ -16,26 +16,26 @@
- Updated dependencies [e8fdad4]
- Updated dependencies [291a5cf]
- vinxi@0.0.42
- - @vinxi/plugin-server-components@0.0.34
- - @vinxi/plugin-server-functions@0.0.34
+ - @vinxi/server-components@0.0.34
+ - @vinxi/server-functions@0.0.34
## null
### Patch Changes
- Updated dependencies [2e52d87]
- - @vinxi/plugin-server-functions@0.0.33
+ - @vinxi/server-functions@0.0.33
- vinxi@0.0.41
- - @vinxi/plugin-server-components@0.0.33
+ - @vinxi/server-components@0.0.33
## null
### Patch Changes
- Updated dependencies [0335776]
- - @vinxi/plugin-server-components@0.0.32
+ - @vinxi/server-components@0.0.32
- vinxi@0.0.40
- - @vinxi/plugin-server-functions@0.0.32
+ - @vinxi/server-functions@0.0.32
## null
@@ -44,8 +44,8 @@
- Updated dependencies [f237894]
- Updated dependencies [d620072]
- vinxi@0.0.39
- - @vinxi/plugin-server-components@0.0.31
- - @vinxi/plugin-server-functions@0.0.31
+ - @vinxi/server-components@0.0.31
+ - @vinxi/server-functions@0.0.31
## null
@@ -53,9 +53,9 @@
- Updated dependencies [1284791]
- Updated dependencies [930b2f2]
- - @vinxi/plugin-server-functions@0.0.30
+ - @vinxi/server-functions@0.0.30
- vinxi@0.0.38
- - @vinxi/plugin-server-components@0.0.30
+ - @vinxi/server-components@0.0.30
## null
diff --git a/examples/react/rsc/spa/app.config.js b/examples/react/rsc/spa/app.config.js
index 4403f60e..34ceb924 100644
--- a/examples/react/rsc/spa/app.config.js
+++ b/examples/react/rsc/spa/app.config.js
@@ -1,5 +1,5 @@
-import { serverComponents } from "@vinxi/plugin-server-components";
-import { serverFunctions } from "@vinxi/plugin-server-functions";
+import { serverComponents } from "@vinxi/server-components/plugin";
+import { serverFunctions } from "@vinxi/server-functions/plugin";
import reactRefresh from "@vitejs/plugin-react";
import { createApp } from "vinxi";
diff --git a/examples/react/rsc/spa/app/server-action.tsx b/examples/react/rsc/spa/app/server-action.tsx
index f10927de..3dab1713 100644
--- a/examples/react/rsc/spa/app/server-action.tsx
+++ b/examples/react/rsc/spa/app/server-action.tsx
@@ -1,19 +1,19 @@
-import { eventHandler, readRawBody, setHeader } from "vinxi/server";
+import { eventHandler, sendStream } from "vinxi/server";
export default eventHandler(async (event) => {
- if (event.method === "POST") {
+ if (event.node.req.method === "POST") {
const {
renderToPipeableStream,
decodeReply,
decodeReplyFromBusboy,
decodeAction,
} = await import("@vinxi/react-server-dom/server");
- const serverReference = event.headers.get("server-action");
+ const serverReference = event.node.req.headers["server-action"];
if (serverReference) {
// This is the client-side case
const [filepath, name] = serverReference.split("#");
const action = (
- await import.meta.env.MANIFEST["server"].chunks[filepath].import()
+ await import.meta.env.MANIFEST["rsc"].chunks[filepath].import()
)[name];
// Validate that this is actually a function we intended to expose and
// not the client trying to invoke arbitrary functions. In a real app,
@@ -23,14 +23,16 @@ export default eventHandler(async (event) => {
}
let args;
- // if (req.is('multipart/form-data')) {
- // // Use busboy to streamingly parse the reply from form-data.
- // const bb = busboy({headers: req.headers});
- // const reply = decodeReplyFromBusboy(bb, moduleBasePath);
- // req.pipe(bb);
- // args = await reply;
- // } else {
- const text = await readRawBody(event);
+ const text = await new Promise((resolve) => {
+ const requestBody = [];
+ event.node.req.on("data", (chunks) => {
+ console.log(chunks);
+ requestBody.push(chunks);
+ });
+ event.node.req.on("end", () => {
+ resolve(requestBody.join(""));
+ });
+ });
console.log(text);
args = await decodeReply(text);
@@ -50,12 +52,11 @@ export default eventHandler(async (event) => {
events[event] = listener;
};
- setHeader(event, "Content-Type", "application/json");
- setHeader(event, "Router", "server");
+ event.node.res.setHeader("Content-Type", "application/json");
+ event.node.res.setHeader("Router", "server");
return stream;
} catch (x) {
- console.error(x);
// We handle the error on the client
}
// Refresh the client and return the value
diff --git a/examples/react/rsc/spa/package.json b/examples/react/rsc/spa/package.json
index 0ce50333..3061c4ae 100644
--- a/examples/react/rsc/spa/package.json
+++ b/examples/react/rsc/spa/package.json
@@ -10,8 +10,8 @@
},
"dependencies": {
"@picocss/pico": "^1.5.10",
- "@vinxi/plugin-server-components": "0.0.35",
- "@vinxi/plugin-server-functions": "0.0.35",
+ "@vinxi/server-components": "0.0.35",
+ "@vinxi/server-functions": "0.0.35",
"@vinxi/react": "0.0.11",
"@vinxi/react-server-dom": "0.0.3",
"@vitejs/plugin-react": "^4.0.4",
diff --git a/examples/react/rsc/spa/tmp/count b/examples/react/rsc/spa/tmp/count
index 301160a9..2edeafb0 100644
--- a/examples/react/rsc/spa/tmp/count
+++ b/examples/react/rsc/spa/tmp/count
@@ -1 +1 @@
-8
\ No newline at end of file
+20
\ No newline at end of file
diff --git a/examples/vanilla/spa/app.config.js b/examples/vanilla/spa/app.config.js
index 9d7d1db1..d19ad803 100644
--- a/examples/vanilla/spa/app.config.js
+++ b/examples/vanilla/spa/app.config.js
@@ -1,4 +1,4 @@
-import { serverFunctions } from "@vinxi/plugin-server-functions";
+import { serverFunctions } from "@vinxi/server-functions/plugin";
import { createApp } from "vinxi";
export default createApp({
@@ -12,7 +12,6 @@ export default createApp({
name: "client",
mode: "spa",
handler: "./index.html",
- target: "browser",
plugins: () => [serverFunctions.client()],
},
serverFunctions.router({
diff --git a/examples/vanilla/spa/app/client.tsx b/examples/vanilla/spa/app/client.tsx
index 4323a8f4..670d7756 100644
--- a/examples/vanilla/spa/app/client.tsx
+++ b/examples/vanilla/spa/app/client.tsx
@@ -20,12 +20,18 @@ const world4 = async (x, y) => {
console.log("hello world 4", x, y);
};
+const world5 = async (x) => {
+ "use server";
+ console.log("hello world 4", x);
+};
+
console.log(
await world(),
await world2(1),
await world3(2, 3),
await world4(5, 6),
await sayHello(),
+ await world5({ hello: 1, world: "aasd", x: true }),
);
console.log("Hello world!");
diff --git a/examples/vanilla/spa/package.json b/examples/vanilla/spa/package.json
index b1409cff..05eb069a 100644
--- a/examples/vanilla/spa/package.json
+++ b/examples/vanilla/spa/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@picocss/pico": "^1.5.10",
- "@vinxi/plugin-server-functions": "workspace:^",
+ "@vinxi/server-functions": "0.0.35",
"autoprefixer": "^10.4.15",
"tailwindcss": "^3.3.3",
"vinxi": "0.0.43"
diff --git a/examples/vanilla/stack/.gitignore b/examples/vanilla/stack/.gitignore
new file mode 100644
index 00000000..e985853e
--- /dev/null
+++ b/examples/vanilla/stack/.gitignore
@@ -0,0 +1 @@
+.vercel
diff --git a/examples/vanilla/stack/CHANGELOG.md b/examples/vanilla/stack/CHANGELOG.md
new file mode 100644
index 00000000..493713fd
--- /dev/null
+++ b/examples/vanilla/stack/CHANGELOG.md
@@ -0,0 +1,104 @@
+# example-vanilla
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [355daea]
+ - @vinxi/plugin-references@0.0.24
+ - vinxi@0.0.34
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [1dec590]
+ - vinxi@0.0.33
+ - @vinxi/plugin-references@0.0.23
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [982147a]
+ - vinxi@0.0.32
+ - @vinxi/plugin-references@0.0.22
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [94f59aa]
+- Updated dependencies [bc82d8e]
+- Updated dependencies [1d8b542]
+- Updated dependencies [5bf5e03]
+- Updated dependencies [4c7fd35]
+- Updated dependencies [0f4b3ee]
+- Updated dependencies [ad62318]
+- Updated dependencies [c223ab6]
+- Updated dependencies [94f59aa]
+ - @vinxi/plugin-references@0.0.21
+ - vinxi@0.0.31
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [fd06048]
+- Updated dependencies [0f14555]
+- Updated dependencies [82267c5]
+ - vinxi@0.0.30
+ - @vinxi/plugin-references@0.0.20
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [8058084]
+ - vinxi@0.0.29
+ - @vinxi/plugin-references@0.0.19
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [b934e84]
+- Updated dependencies [17693dc]
+- Updated dependencies [d6305b8]
+- Updated dependencies [cb91c48]
+- Updated dependencies [085116d]
+- Updated dependencies [f1ee5b8]
+ - vinxi@0.0.28
+ - @vinxi/plugin-references@0.0.18
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [7803042]
+ - vinxi@0.0.27
+ - @vinxi/plugin-references@0.0.17
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [2b17e0d]
+ - vinxi@0.0.26
+ - @vinxi/plugin-references@0.0.16
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [552d8ca]
+ - vinxi@0.0.25
+ - @vinxi/plugin-references@0.0.15
+
+## null
+
+### Patch Changes
+
+- Updated dependencies [47abc3c]
+ - @vinxi/plugin-references@0.0.14
+ - vinxi@0.0.24
diff --git a/examples/vanilla/stack/app/actions.tsx b/examples/vanilla/stack/app/actions.tsx
new file mode 100644
index 00000000..a843ead4
--- /dev/null
+++ b/examples/vanilla/stack/app/actions.tsx
@@ -0,0 +1,12 @@
+"use server";
+
+let store = { count: 0 };
+export function sayHello() {
+ console.log("Hello World");
+ store.count++;
+ return store.count;
+}
+
+export function getStore() {
+ return store.count;
+}
diff --git a/examples/vanilla/stack/app/client.tsx b/examples/vanilla/stack/app/client.tsx
new file mode 100644
index 00000000..670d7756
--- /dev/null
+++ b/examples/vanilla/stack/app/client.tsx
@@ -0,0 +1,38 @@
+///
+import "vinxi/client";
+
+import { sayHello } from "./actions";
+import { world } from "./server-functions";
+import "./style.css";
+
+export async function world2(x) {
+ "use server";
+ console.log("hello world 2", x);
+}
+
+async function world3(x, y) {
+ "use server";
+ console.log("hello world 3", x, y);
+}
+
+const world4 = async (x, y) => {
+ "use server";
+ console.log("hello world 4", x, y);
+};
+
+const world5 = async (x) => {
+ "use server";
+ console.log("hello world 4", x);
+};
+
+console.log(
+ await world(),
+ await world2(1),
+ await world3(2, 3),
+ await world4(5, 6),
+ await sayHello(),
+ await world5({ hello: 1, world: "aasd", x: true }),
+);
+console.log("Hello world!");
+
+document.getElementById("app").innerHTML = `Hello World`;
diff --git a/examples/vanilla/stack/app/middleware.tsx b/examples/vanilla/stack/app/middleware.tsx
new file mode 100644
index 00000000..e59c832b
--- /dev/null
+++ b/examples/vanilla/stack/app/middleware.tsx
@@ -0,0 +1,10 @@
+import { defineMiddleware, getContext, setContext } from "vinxi/server";
+
+export default defineMiddleware({
+ onRequest: (event) => {
+ setContext(event, "help", { foo: "bar" });
+ },
+ onBeforeResponse: (event) => {
+ console.log(getContext(event, "help"));
+ },
+});
diff --git a/examples/vanilla/stack/app/server-functions.tsx b/examples/vanilla/stack/app/server-functions.tsx
new file mode 100644
index 00000000..7b352f32
--- /dev/null
+++ b/examples/vanilla/stack/app/server-functions.tsx
@@ -0,0 +1,4 @@
+export async function world() {
+ "use server";
+ console.log("hello");
+}
diff --git a/examples/vanilla/stack/app/style.css b/examples/vanilla/stack/app/style.css
new file mode 100644
index 00000000..b1284a35
--- /dev/null
+++ b/examples/vanilla/stack/app/style.css
@@ -0,0 +1,7 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+* {
+ color: red;
+}
\ No newline at end of file
diff --git a/examples/vanilla/stack/index.html b/examples/vanilla/stack/index.html
new file mode 100644
index 00000000..e5ae1ec0
--- /dev/null
+++ b/examples/vanilla/stack/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
diff --git a/examples/vanilla/stack/index.ts b/examples/vanilla/stack/index.ts
new file mode 100644
index 00000000..8785b577
--- /dev/null
+++ b/examples/vanilla/stack/index.ts
@@ -0,0 +1,6 @@
+import { eventHandler } from "vinxi/server";
+
+export default eventHandler((event) => {
+ console.log(event.path);
+ return "Hello world";
+});
diff --git a/examples/vanilla/stack/package.json b/examples/vanilla/stack/package.json
new file mode 100644
index 00000000..bc4d64fb
--- /dev/null
+++ b/examples/vanilla/stack/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "example-vanilla-spa",
+ "type": "module",
+ "private": true,
+ "version": null,
+ "scripts": {
+ "dev": "vinxi dev",
+ "build": "vinxi build",
+ "start": "vinxi start"
+ },
+ "dependencies": {
+ "@picocss/pico": "^1.5.10",
+ "@vinxi/server-functions": "workspace:^",
+ "autoprefixer": "^10.4.15",
+ "tailwindcss": "^3.3.3",
+ "vinxi": "0.0.43"
+ },
+ "devDependencies": {
+ "@types/resolve": "^1.20.4"
+ }
+}
diff --git a/examples/vanilla/stack/postcss.config.cjs b/examples/vanilla/stack/postcss.config.cjs
new file mode 100644
index 00000000..33ad091d
--- /dev/null
+++ b/examples/vanilla/stack/postcss.config.cjs
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/examples/vanilla/stack/public/favicon.ico b/examples/vanilla/stack/public/favicon.ico
new file mode 100644
index 00000000..129ee136
Binary files /dev/null and b/examples/vanilla/stack/public/favicon.ico differ
diff --git a/examples/vanilla/stack/tailwind.config.cjs b/examples/vanilla/stack/tailwind.config.cjs
new file mode 100644
index 00000000..e1e70f61
--- /dev/null
+++ b/examples/vanilla/stack/tailwind.config.cjs
@@ -0,0 +1,8 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ["./app/**/*.tsx", "./app/**/*.ts", "./app/**/*.js"],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};
diff --git a/packages/vinxi-directives/plugin.js b/packages/vinxi-directives/plugin.js
index 4a975fc4..b537dee8 100644
--- a/packages/vinxi-directives/plugin.js
+++ b/packages/vinxi-directives/plugin.js
@@ -1,5 +1,3 @@
-import { decorateExportsPlugin, shimExportsPlugin } from "./transform";
-
/**
*
* @param {*} param0
diff --git a/packages/vinxi-directives/transform.js b/packages/vinxi-directives/transform.js
index 25b2fadd..5a3ce609 100644
--- a/packages/vinxi-directives/transform.js
+++ b/packages/vinxi-directives/transform.js
@@ -9,7 +9,7 @@
import { readFileSync } from "fs";
import { print, types, visit } from "recast";
-import { parseAdvanced, parseLoose } from "./parse";
+import { parseAdvanced, parseLoose } from "./parse.js";
/**
*
diff --git a/packages/vinxi-server-components/package.json b/packages/vinxi-server-components/package.json
index 6db311f0..ac64d8c5 100644
--- a/packages/vinxi-server-components/package.json
+++ b/packages/vinxi-server-components/package.json
@@ -1,12 +1,9 @@
{
- "name": "@vinxi/plugin-server-components",
+ "name": "@vinxi/server-components",
"version": "0.0.35",
"type": "module",
"author": "Nikhil Saraf ",
- "files": [
- "*.js",
- "*.d.ts"
- ],
+ "files": ["*.js", "*.d.ts"],
"types": "./index.d.ts",
"exports": {
".": "./index.js",
@@ -14,9 +11,7 @@
},
"typesVersions": {
"*": {
- ".": [
- "./index.d.ts"
- ]
+ ".": ["./index.d.ts"]
}
},
"devDependencies": {
diff --git a/packages/vinxi-server-components/plugin.js b/packages/vinxi-server-components/plugin.js
new file mode 100644
index 00000000..4fe996c5
--- /dev/null
+++ b/packages/vinxi-server-components/plugin.js
@@ -0,0 +1,20 @@
+import { fileURLToPath } from "url";
+
+import { client } from "./client.js";
+import { serverActions } from "./server-action.js";
+import { server } from "./server.js";
+
+export const serverComponents = {
+ client: client,
+ server: server,
+ serverActions: serverActions,
+ serverRouter: (overrides) => ({
+ name: "server",
+ mode: "handler",
+ base: "/_server",
+ handler: fileURLToPath(new URL("./server-handler.js", import.meta.url)),
+ target: "server",
+ ...(overrides ?? {}),
+ plugins: () => [server(), ...(overrides?.plugins?.() ?? [])],
+ }),
+};
diff --git a/packages/vinxi-server-functions/index.js b/packages/vinxi-server-functions/index.js
index 0931cd04..cb23bf8f 100644
--- a/packages/vinxi-server-functions/index.js
+++ b/packages/vinxi-server-functions/index.js
@@ -1,18 +1,18 @@
-import { fileURLToPath } from "url";
+import { createStack } from "vinxi/stack";
-import { client } from "./client.js";
-import { server } from "./server.js";
+import { serverFunctions } from "./plugin.js";
-export const serverFunctions = {
- client: client,
- server: server,
- router: (overrides) => ({
- name: "server",
- mode: "handler",
- base: "/_server",
- handler: fileURLToPath(new URL("./server-handler.js", import.meta.url)),
- target: "server",
- ...(overrides ?? {}),
- plugins: () => [server(), ...(overrides?.plugins?.() ?? [])],
- }),
-};
+export default function serverFns(app) {
+ app.addRouter(serverFunctions.router());
+ const clientRouters = app.config.routers.filter(
+ (router) => router.target === "browser",
+ );
+
+ clientRouters.forEach((router) => {
+ if (router.plugins) {
+ router.plugins = () => [serverFunctions.client(), ...router.plugins()];
+ } else if (router.plugins === undefined) {
+ router.plugins = () => [serverFunctions.client()];
+ }
+ });
+}
diff --git a/packages/vinxi-server-functions/package.json b/packages/vinxi-server-functions/package.json
index 2526a91e..e917a200 100644
--- a/packages/vinxi-server-functions/package.json
+++ b/packages/vinxi-server-functions/package.json
@@ -1,5 +1,5 @@
{
- "name": "@vinxi/plugin-server-functions",
+ "name": "@vinxi/server-functions",
"version": "0.0.35",
"type": "module",
"author": "Nikhil Saraf ",
diff --git a/packages/vinxi-server-functions/plugin.js b/packages/vinxi-server-functions/plugin.js
new file mode 100644
index 00000000..5399f740
--- /dev/null
+++ b/packages/vinxi-server-functions/plugin.js
@@ -0,0 +1,18 @@
+import { fileURLToPath } from "url";
+
+import { client } from "./client.js";
+import { server } from "./server.js";
+
+export const serverFunctions = {
+ client: client,
+ server: server,
+ router: (overrides) => ({
+ name: "server-fns",
+ mode: "handler",
+ base: "/_server",
+ handler: fileURLToPath(new URL("./server-handler.js", import.meta.url)),
+ target: "server",
+ ...(overrides ?? {}),
+ plugins: () => [server(), ...(overrides?.plugins?.() ?? [])],
+ }),
+};
diff --git a/packages/vinxi-server-functions/server-handler.js b/packages/vinxi-server-functions/server-handler.js
index ca180701..35c8de09 100644
--- a/packages/vinxi-server-functions/server-handler.js
+++ b/packages/vinxi-server-functions/server-handler.js
@@ -29,32 +29,28 @@ export async function handleServerAction(event) {
// This is the client-side case
const [filepath, name] = serverReference.split("#");
const action = (await loadModule(filepath))[name];
- // Validate that this is actually a function we intended to expose and
- // not the client trying to invoke arbitrary functions. In a real app,
- // you'd have a manifest verifying this before even importing it.
- // if (action.$$typeof !== Symbol.for("react.server.reference")) {
- // throw new Error("Invalid action");
- // }
- const result = action.apply(null, await toWebRequest(event).json());
+ const text = await new Promise((resolve) => {
+ const requestBody = [];
+ event.node.req.on("data", (chunks) => {
+ console.log(chunks);
+ requestBody.push(chunks);
+ });
+ event.node.req.on("end", () => {
+ resolve(requestBody.join(""));
+ });
+ });
+ const json = JSON.parse(text);
+ const result = action.apply(null, json);
try {
// Wait for any mutations
const response = await result;
- // const stream = renderToPipeableStream(result);
- // // @ts-ignore
- // stream._read = () => {};
- // // @ts-ignore
- // stream.on = (event, listener) => {
- // events[event] = listener;
- // };
event.node.res.setHeader("Content-Type", "application/json");
event.node.res.setHeader("Router", "server");
return JSON.stringify(response ?? null);
} catch (x) {
- // We handle the error on the client
+ console.error(x);
}
- // Refresh the client and return the value
- // return {};
} else {
throw new Error("Invalid request");
}
diff --git a/packages/vinxi/bin/cli.mjs b/packages/vinxi/bin/cli.mjs
index ceaeedbf..8ec62faf 100755
--- a/packages/vinxi/bin/cli.mjs
+++ b/packages/vinxi/bin/cli.mjs
@@ -13,9 +13,11 @@ async function main() {
const command = args._[0];
const rootDir = resolve(args._[1] || ".");
+ console.log(args);
+
const configFile = args.config;
globalThis.MANIFEST = {};
- const app = await loadApp(configFile);
+ const app = await loadApp(configFile, args);
if (command === "dev") {
let devServer;
@@ -32,7 +34,7 @@ async function main() {
watcher.on("all", async (ctx, path) => {
log("change detected in", path);
log("reloading app");
- const newApp = await loadApp(configFile);
+ const newApp = await loadApp(configFile, args);
if (!newApp) return;
restartDevServer(newApp);
});
@@ -61,7 +63,7 @@ async function main() {
fsWatcher.on("all", async (path) => {
log("change detected in", path);
log("reloading app");
- const newApp = await loadApp(configFile);
+ const newApp = await loadApp(configFile, args);
if (!newApp) return;
fsWatcher.close();
@@ -83,7 +85,7 @@ async function main() {
const { createBuild } = await import("../lib/build.js");
await createBuild(app, {});
} else if (command === "start") {
- exec(`node .output/dist/server.js`);
+ await exec(`node .output/server/index.mjs`);
} else {
throw new Error(`Unknown command ${command}`);
}
diff --git a/packages/vinxi/lib/app.d.ts b/packages/vinxi/lib/app.d.ts
new file mode 100644
index 00000000..25add0fa
--- /dev/null
+++ b/packages/vinxi/lib/app.d.ts
@@ -0,0 +1,15 @@
+export type App = {
+ config: {
+ name: string;
+ devtools: boolean;
+ server: import("nitropack").NitroConfig;
+ routers: import("./router-mode.js").Router[];
+ root: string;
+ };
+ addRouter: (router: any) => App;
+ getRouter: (name: string) => import("./router-mode.js").Router;
+ stack: (stack: any) => App;
+ dev(): Promise;
+ build(): Promise;
+ hooks: import("hookable").Hookable;
+};
diff --git a/packages/vinxi/lib/app.js b/packages/vinxi/lib/app.js
index 81a33bbb..c17f2e0c 100644
--- a/packages/vinxi/lib/app.js
+++ b/packages/vinxi/lib/app.js
@@ -1,5 +1,4 @@
// @ts-ignore
-import { devtoolsClient, devtoolsRpc } from "@vinxi/devtools";
import { createHooks } from "hookable";
import { isMainThread } from "worker_threads";
@@ -7,8 +6,30 @@ import invariant, { InvariantError } from "./invariant.js";
import { c, consola, log, withLogger } from "./logger.js";
import { resolveRouterConfig, routerSchema } from "./router-modes.js";
-/** @typedef {{ devtools?: boolean; routers?: import("./router-modes.js").RouterSchemaInput[]; name?: string; server?: import('nitropack').NitroConfig; root?: string }} AppOptions */
-/** @typedef {{ config: { name: string; devtools: boolean; server: import('nitropack').NitroConfig; routers: import("./router-mode.js").Router[]; root: string; }; addRouter: (router: any) => App, getRouter: (name: string) => import("./router-mode.js").Router; dev(): Promise; build(): Promise; hooks: import('hookable').Hookable}} App */
+/** @typedef {{
+ devtools?: boolean;
+ routers?: import("./router-modes.js").RouterSchemaInput[];
+ name?:
+ string;
+ server?: import('nitropack').NitroConfig;
+ root?: string
+}} AppOptions */
+
+/** @typedef {{
+ config: {
+ name: string;
+ devtools: boolean;
+ server: import("nitropack").NitroConfig;
+ routers: import("./router-mode.js").Router[];
+ root: string;
+ };
+ addRouter: (router: any) => App;
+ getRouter: (name: string) => import("./router-mode.js").Router;
+ stack: (stack: (app: App) => void | Promise) => Promise;
+ dev(): Promise;
+ build(): Promise;
+ hooks: import("hookable").Hookable;
+}} App */
/**
*
@@ -20,7 +41,7 @@ export function createApp({
name = "vinxi",
server = {},
root = process.cwd(),
-}) {
+} = {}) {
const hooks = createHooks();
hooks.afterEach((result) => {
const output = result.args[0].router
@@ -103,6 +124,10 @@ export function createApp({
}
return router;
},
+ async stack(stack) {
+ await stack(app);
+ return app;
+ },
async dev() {
if (isMainThread) {
const { createDevServer } = await import("./dev-server.js");
diff --git a/packages/vinxi/lib/build.js b/packages/vinxi/lib/build.js
index 0110282b..5714170a 100644
--- a/packages/vinxi/lib/build.js
+++ b/packages/vinxi/lib/build.js
@@ -67,6 +67,7 @@ export async function createBuild(app, buildConfig) {
const nitro = await createNitro({
...app.config.server,
dev: false,
+
preset:
process.env.TARGET ??
process.env.NITRO_PRESET ??
@@ -93,6 +94,7 @@ export async function createBuild(app, buildConfig) {
"#vinxi/chunks",
...(app.config.server.plugins ?? []),
],
+ buildDir: ".vinxi",
handlers: [
...[...app.config.routers]
.sort((a, b) => a.base.length - b.base.length)
diff --git a/packages/vinxi/lib/load-app.js b/packages/vinxi/lib/load-app.js
index fb642ffb..1c3a16b5 100644
--- a/packages/vinxi/lib/load-app.js
+++ b/packages/vinxi/lib/load-app.js
@@ -1,5 +1,6 @@
import { loadConfig } from "c12";
import chokidar from "chokidar";
+import { fileURLToPath } from "url";
import { createApp } from "./app.js";
@@ -8,7 +9,9 @@ import { createApp } from "./app.js";
* @param {string | undefined} configFile
* @returns {Promise}
*/
-export async function loadApp(configFile = undefined) {
+export async function loadApp(configFile = undefined, args = {}) {
+ const stacks = typeof args.s === "string" ? [args.s] : args.s ?? [];
+ console.log(stacks);
/** @type {{ config: import("./app.js").App }}*/
try {
let { config: app } = await loadConfig(
@@ -41,10 +44,16 @@ export async function loadApp(configFile = undefined) {
if (config.config) {
console.warn("Found vite.config.js with app config");
// @ts-expect-error trying to send c12's config as app
+ //
return config;
} else {
console.warn("No app config found. Assuming SPA app.");
- return createApp({
+
+ if (stacks.length) {
+ return applyStacks(createApp({}), stacks);
+ }
+
+ const app = createApp({
routers: [
{
name: "public",
@@ -60,13 +69,40 @@ export async function loadApp(configFile = undefined) {
},
],
});
+
+ return applyStacks(app, stacks);
}
}
- return app;
+ return applyStacks(app, stacks);
} catch (e) {
console.error(e);
return undefined;
}
}
+
+async function applyStacks(app, s) {
+ const { default: resolve } = await import("resolve");
+ const stacks = await Promise.all(
+ s.map(async (stack) => {
+ if (stack.includes("/") || stack.includes("@")) {
+ var res = resolve.sync(stack, { basedir: app.config.root });
+ const mod = await import(res);
+ return mod.default;
+ }
+ const mod = await import(
+ fileURLToPath(new URL(`../stack/${stack}.js`, import.meta.url))
+ );
+ return mod.default;
+ }),
+ );
+
+ console.log(stacks);
+
+ for (const stack of stacks) {
+ await app.stack(stack);
+ }
+
+ return app;
+}
diff --git a/packages/vinxi/package.json b/packages/vinxi/package.json
index 05b63c86..9f20e1fe 100644
--- a/packages/vinxi/package.json
+++ b/packages/vinxi/package.json
@@ -3,15 +3,7 @@
"version": "0.0.43",
"type": "module",
"author": "Nikhil Saraf ",
- "files": [
- "bin",
- "lib",
- "public",
- "runtime",
- "types",
- "dist/types",
- "*.d.ts"
- ],
+ "files": ["bin", "lib", "public", "runtime", "types", "dist/types", "*.d.ts"],
"scripts": {
"types": "npm run tsc",
"tsc": "rm -rf dist/types && tsc; cp -r types dist/types/types"
@@ -27,6 +19,9 @@
"import": "./lib/dev-server.js",
"types": "./dist/types/lib/dev-server.d.ts"
},
+ "./stack": {
+ "import": "./stack/index.js"
+ },
"./lib/doc": {
"import": "./lib/doc.js"
},
@@ -83,48 +78,20 @@
},
"typesVersions": {
"*": {
- ".": [
- "./dist/types/lib/index.d.ts"
- ],
- "dev-server": [
- "./dist/types/lib/dev-server.d.ts"
- ],
- "server": [
- "./dist/types/runtime/server.d.ts"
- ],
- "party": [
- "./dist/types/runtime/party.d.ts"
- ],
- "css": [
- "./dist/types/runtime/style.d.ts"
- ],
- "client": [
- "./dist/types/runtime/client.d.ts"
- ],
- "fs-router": [
- "./dist/types/lib/fs-router.d.ts"
- ],
- "types/server": [
- "./types/server.d.ts"
- ],
- "types/client": [
- "./types/client.d.ts"
- ],
- "routes": [
- "./types/routes.d.ts"
- ],
- "lib/invariant": [
- "./dist/types/lib/invariant.d.ts"
- ],
- "plugins/config": [
- "./dist/types/lib/plugins/config.d.ts"
- ],
- "plugins/virtual": [
- "./dist/types/lib/plugins/virtual.d.ts"
- ],
- "lib/path": [
- "./dist/types/lib/path.d.ts"
- ]
+ ".": ["./dist/types/lib/index.d.ts"],
+ "dev-server": ["./dist/types/lib/dev-server.d.ts"],
+ "server": ["./dist/types/runtime/server.d.ts"],
+ "party": ["./dist/types/runtime/party.d.ts"],
+ "css": ["./dist/types/runtime/style.d.ts"],
+ "client": ["./dist/types/runtime/client.d.ts"],
+ "fs-router": ["./dist/types/lib/fs-router.d.ts"],
+ "types/server": ["./types/server.d.ts"],
+ "types/client": ["./types/client.d.ts"],
+ "routes": ["./types/routes.d.ts"],
+ "lib/invariant": ["./dist/types/lib/invariant.d.ts"],
+ "plugins/config": ["./dist/types/lib/plugins/config.d.ts"],
+ "plugins/virtual": ["./dist/types/lib/plugins/virtual.d.ts"],
+ "lib/path": ["./dist/types/lib/path.d.ts"]
}
},
"dependencies": {
diff --git a/packages/vinxi/stack/assets.js b/packages/vinxi/stack/assets.js
new file mode 100644
index 00000000..381a6b87
--- /dev/null
+++ b/packages/vinxi/stack/assets.js
@@ -0,0 +1,9 @@
+import { createStack } from "./index.js";
+
+export default createStack((app) => {
+ app.addRouter({
+ name: "public",
+ mode: "static",
+ dir: "./public",
+ });
+});
diff --git a/packages/vinxi/stack/index.js b/packages/vinxi/stack/index.js
new file mode 100644
index 00000000..3cc601b9
--- /dev/null
+++ b/packages/vinxi/stack/index.js
@@ -0,0 +1,5 @@
+export function createStack(
+ /** @type {(app: import('./app.js').App) => import('./app.js').App | void}*/ stack,
+) {
+ return stack;
+}
diff --git a/packages/vinxi/stack/server.js b/packages/vinxi/stack/server.js
new file mode 100644
index 00000000..3fe6aefd
--- /dev/null
+++ b/packages/vinxi/stack/server.js
@@ -0,0 +1,10 @@
+import { createStack } from "./index.js";
+
+export default createStack((app) => {
+ app.addRouter({
+ name: "server",
+ mode: "handler",
+ handler: "./index.ts",
+ target: "server",
+ });
+});
diff --git a/packages/vinxi/stack/spa.js b/packages/vinxi/stack/spa.js
new file mode 100644
index 00000000..f1eb2350
--- /dev/null
+++ b/packages/vinxi/stack/spa.js
@@ -0,0 +1,10 @@
+import { createStack } from "./index.js";
+
+export default createStack((app) => {
+ app.addRouter({
+ name: "client",
+ mode: "spa",
+ handler: "./index.html",
+ target: "browser",
+ });
+});
diff --git a/packages/vinxi/tsconfig.json b/packages/vinxi/tsconfig.json
index e68e6f67..5a968ff3 100644
--- a/packages/vinxi/tsconfig.json
+++ b/packages/vinxi/tsconfig.json
@@ -9,6 +9,7 @@
"strict": true,
"checkJs": true,
"noEmit": false,
+ "rootDir": "./",
"isolatedModules": true,
"declarationMap": true,
"declaration": true,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0aaf7caa..5e916817 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -152,18 +152,18 @@ importers:
'@picocss/pico':
specifier: ^1.5.10
version: 1.5.10
- '@vinxi/plugin-server-components':
+ '@vinxi/server-components':
specifier: 0.0.35
version: link:../../../../packages/vinxi-server-components
- '@vinxi/plugin-server-functions':
- specifier: 0.0.35
- version: link:../../../../packages/vinxi-server-functions
'@vinxi/react':
specifier: 0.0.11
version: link:../../../../packages/vinxi-react
'@vinxi/react-server-dom':
specifier: 0.0.3
version: 0.0.3(react-dom@0.0.0-experimental-035a41c4e-20230704)(react@0.0.0-experimental-035a41c4e-20230704)(vite@4.5.0)
+ '@vinxi/server-functions':
+ specifier: 0.0.35
+ version: link:../../../../packages/vinxi-server-functions
'@vitejs/plugin-react':
specifier: ^4.0.4
version: 4.1.0(vite@4.5.0)
@@ -761,7 +761,7 @@ importers:
'@picocss/pico':
specifier: ^1.5.10
version: 1.5.10
- '@vinxi/plugin-server-functions':
+ '@vinxi/server-functions':
specifier: workspace:^
version: link:../../../packages/vinxi-server-functions
autoprefixer:
@@ -774,6 +774,28 @@ importers:
specifier: 0.0.43
version: link:../../../packages/vinxi
+ examples/vanilla/stack:
+ dependencies:
+ '@picocss/pico':
+ specifier: ^1.5.10
+ version: 1.5.10
+ '@vinxi/server-functions':
+ specifier: workspace:^
+ version: link:../../../packages/vinxi-server-functions
+ autoprefixer:
+ specifier: ^10.4.15
+ version: 10.4.16(postcss@8.4.31)
+ tailwindcss:
+ specifier: ^3.3.3
+ version: 3.3.5
+ vinxi:
+ specifier: 0.0.43
+ version: link:../../../packages/vinxi
+ devDependencies:
+ '@types/resolve':
+ specifier: ^1.20.4
+ version: 1.20.4
+
examples/vanilla/trpc:
dependencies:
'@picocss/pico':
@@ -1354,18 +1376,18 @@ importers:
'@picocss/pico':
specifier: ^1.5.10
version: 1.5.10
- '@vinxi/plugin-server-components':
+ '@vinxi/server-components':
specifier: 0.0.35
version: link:../../../packages/vinxi-server-components
- '@vinxi/plugin-server-functions':
- specifier: 0.0.35
- version: link:../../../packages/vinxi-server-functions
'@vinxi/react':
specifier: 0.0.11
version: link:../../../packages/vinxi-react
'@vinxi/react-server-dom':
specifier: 0.0.3
version: 0.0.3(react-dom@0.0.0-experimental-035a41c4e-20230704)(react@0.0.0-experimental-035a41c4e-20230704)(vite@4.5.0)
+ '@vinxi/server-functions':
+ specifier: 0.0.35
+ version: link:../../../packages/vinxi-server-functions
'@vitejs/plugin-react':
specifier: ^4.0.4
version: 4.1.0(vite@4.5.0)
diff --git a/test/templates/react-rsc/CHANGELOG.md b/test/templates/react-rsc/CHANGELOG.md
index b3fa89e3..82ad0027 100644
--- a/test/templates/react-rsc/CHANGELOG.md
+++ b/test/templates/react-rsc/CHANGELOG.md
@@ -6,8 +6,8 @@
- Updated dependencies [978b04a]
- vinxi@0.0.43
- - @vinxi/plugin-server-components@0.0.35
- - @vinxi/plugin-server-functions@0.0.35
+ - @vinxi/server-components@0.0.35
+ - @vinxi/server-functions@0.0.35
## null
@@ -16,26 +16,26 @@
- Updated dependencies [e8fdad4]
- Updated dependencies [291a5cf]
- vinxi@0.0.42
- - @vinxi/plugin-server-components@0.0.34
- - @vinxi/plugin-server-functions@0.0.34
+ - @vinxi/server-components@0.0.34
+ - @vinxi/server-functions@0.0.34
## null
### Patch Changes
- Updated dependencies [2e52d87]
- - @vinxi/plugin-server-functions@0.0.33
+ - @vinxi/server-functions@0.0.33
- vinxi@0.0.41
- - @vinxi/plugin-server-components@0.0.33
+ - @vinxi/server-components@0.0.33
## null
### Patch Changes
- Updated dependencies [0335776]
- - @vinxi/plugin-server-components@0.0.32
+ - @vinxi/server-components@0.0.32
- vinxi@0.0.40
- - @vinxi/plugin-server-functions@0.0.32
+ - @vinxi/server-functions@0.0.32
## null
@@ -44,8 +44,8 @@
- Updated dependencies [f237894]
- Updated dependencies [d620072]
- vinxi@0.0.39
- - @vinxi/plugin-server-components@0.0.31
- - @vinxi/plugin-server-functions@0.0.31
+ - @vinxi/server-components@0.0.31
+ - @vinxi/server-functions@0.0.31
## null
@@ -53,9 +53,9 @@
- Updated dependencies [1284791]
- Updated dependencies [930b2f2]
- - @vinxi/plugin-server-functions@0.0.30
+ - @vinxi/server-functions@0.0.30
- vinxi@0.0.38
- - @vinxi/plugin-server-components@0.0.30
+ - @vinxi/server-components@0.0.30
## null
diff --git a/test/templates/react-rsc/app.config.js b/test/templates/react-rsc/app.config.js
index 9157d134..263510f3 100644
--- a/test/templates/react-rsc/app.config.js
+++ b/test/templates/react-rsc/app.config.js
@@ -1,5 +1,5 @@
-import { serverComponents } from "@vinxi/plugin-server-components";
-import { serverFunctions } from "@vinxi/plugin-server-functions";
+import { serverComponents } from "@vinxi/server-components/plugin";
+import { serverFunctions } from "@vinxi/server-functions/plugin";
import reactRefresh from "@vitejs/plugin-react";
import { createApp } from "vinxi";
diff --git a/test/templates/react-rsc/package.json b/test/templates/react-rsc/package.json
index 14c3c7f4..d01076be 100644
--- a/test/templates/react-rsc/package.json
+++ b/test/templates/react-rsc/package.json
@@ -10,8 +10,8 @@
},
"dependencies": {
"@picocss/pico": "^1.5.10",
- "@vinxi/plugin-server-functions": "0.0.35",
- "@vinxi/plugin-server-components": "0.0.35",
+ "@vinxi/server-functions": "0.0.35",
+ "@vinxi/server-components": "0.0.35",
"@vinxi/react": "0.0.11",
"@vinxi/react-server-dom": "0.0.3",
"@vitejs/plugin-react": "^4.0.4",