diff --git a/.changeset/early-pumas-pump.md b/.changeset/early-pumas-pump.md
new file mode 100644
index 00000000..7f90064b
--- /dev/null
+++ b/.changeset/early-pumas-pump.md
@@ -0,0 +1,7 @@
+---
+"@vinxi/server-functions": patch
+"vinxi": patch
+"solid-ssr-basic": patch
+---
+
+(feat): deep support for `server.baseURL` API from nitro in dev & prod,
diff --git a/examples/react/rsc/spa/app/client.tsx b/examples/react/rsc/spa/app/client.tsx
index ba2063da..9d5990a2 100644
--- a/examples/react/rsc/spa/app/client.tsx
+++ b/examples/react/rsc/spa/app/client.tsx
@@ -11,7 +11,11 @@ import { ServerComponent } from "./server-component";
document.addEventListener("click", async (e) => {
console.log(sayHello, "hello");
- const result = await fetchServerAction("/_server", sayHello["$$id"], []);
+ const result = await fetchServerAction(
+ import.meta.env.SERVER_BASE_URL + "/_server",
+ sayHello["$$id"],
+ [],
+ );
console.log(result);
// sayHello();
});
diff --git a/examples/solid/ssr/basic/app/app.tsx b/examples/solid/ssr/basic/app/app.tsx
index 9739c0b6..3067a79c 100644
--- a/examples/solid/ssr/basic/app/app.tsx
+++ b/examples/solid/ssr/basic/app/app.tsx
@@ -6,7 +6,10 @@ export default function App({ assets, scripts }) {
return (
-
+
{assets}
diff --git a/packages/vinxi-server-functions/client-runtime.js b/packages/vinxi-server-functions/client-runtime.js
index 82ab62eb..97d3c555 100644
--- a/packages/vinxi-server-functions/client-runtime.js
+++ b/packages/vinxi-server-functions/client-runtime.js
@@ -15,13 +15,19 @@ export function createServerReference(fn, id, name) {
return new Proxy(fn, {
get(target, prop, receiver) {
if (prop === "url") {
- return "/_server" + `id=${id}&name=${name}`;
+ return (
+ import.meta.env.SERVER_BASE_URL + "/_server" + `id=${id}&name=${name}`
+ );
}
return Reflect.get(target, prop, receiver);
},
apply(target, thisArg, args) {
- return fetchServerAction("/_server", `${id}#${name}`, args);
+ return fetchServerAction(
+ `${import.meta.env.SERVER_BASE_URL}/_server`,
+ `${id}#${name}`,
+ args,
+ );
},
});
}
diff --git a/packages/vinxi-server-functions/server-runtime.js b/packages/vinxi-server-functions/server-runtime.js
index bc0953cd..60538b7f 100644
--- a/packages/vinxi-server-functions/server-runtime.js
+++ b/packages/vinxi-server-functions/server-runtime.js
@@ -2,7 +2,9 @@ export function createServerReference(fn, id, name) {
return new Proxy(fn, {
get(target, prop, receiver) {
if (prop === "url") {
- return "/_server" + `id=${id}&name=${name}`;
+ return (
+ import.meta.env.SERVER_BASE_URL + "/_server" + `id=${id}&name=${name}`
+ );
}
return Reflect.get(target, prop, receiver);
diff --git a/packages/vinxi/lib/app.js b/packages/vinxi/lib/app.js
index 4293cfa9..92d8cecc 100644
--- a/packages/vinxi/lib/app.js
+++ b/packages/vinxi/lib/app.js
@@ -12,7 +12,7 @@ import { resolveRouterConfig, routerSchema } from "./router-modes.js";
routers?: import("./router-modes.js").RouterSchemaInput[];
name?:
string;
- server?: import('nitropack').NitroConfig;
+ server?: Omit;
root?: string
}} AppOptions */
@@ -20,7 +20,7 @@ import { resolveRouterConfig, routerSchema } from "./router-modes.js";
config: {
name: string;
devtools: boolean;
- server: import("nitropack").NitroConfig;
+ server: Omit;
routers: import("./router-mode.js").Router[];
root: string;
};
diff --git a/packages/vinxi/lib/build.js b/packages/vinxi/lib/build.js
index 1a7cdb78..c2722c4a 100644
--- a/packages/vinxi/lib/build.js
+++ b/packages/vinxi/lib/build.js
@@ -83,6 +83,7 @@ export async function createBuild(app, buildConfig) {
"node-fetch-native/polyfill": require.resolve(
"node-fetch-native/polyfill",
),
+ ...(app.config.server.alias ?? {}),
// "unstorage/drivers/fs-lite": require.resolve("unstorage/drivers/fs-lite"),
// "unstorage/drivers/fs": require.resolve("unstorage/drivers/fs"),
// defu: require.resolve("defu"),
diff --git a/packages/vinxi/lib/dev-server.js b/packages/vinxi/lib/dev-server.js
index 9fa99fe1..b66d3abe 100644
--- a/packages/vinxi/lib/dev-server.js
+++ b/packages/vinxi/lib/dev-server.js
@@ -3,7 +3,7 @@ import { inspect } from "@vinxi/devtools";
import { fileURLToPath } from "node:url";
import { consola, withLogger } from "./logger.js";
-import { normalize } from "./path.js";
+import { join, normalize } from "./path.js";
export * from "./router-dev-plugins.js";
@@ -57,9 +57,12 @@ export async function createViteHandler(router, app, serveConfig) {
...(((await router.plugins?.(router)) ?? []).filter(Boolean) || []),
].filter(Boolean);
+ let base = join(app.config.server.baseURL ?? "/", router.base);
+
+ console.log(base);
const viteDevServer = await createViteDevServer({
configFile: false,
- base: router.base,
+ base,
plugins,
optimizeDeps: {
force: serveConfig.force,
@@ -122,7 +125,7 @@ export async function createDevServer(
publicAssets: [
...app.config.routers
.map((router) => {
- return router.internals.mode.dev.publicAssets?.(router, app.config);
+ return router.internals.mode.dev.publicAssets?.(router, app);
})
.filter(
/**
diff --git a/packages/vinxi/lib/manifest/dev-server-manifest.js b/packages/vinxi/lib/manifest/dev-server-manifest.js
index 145a9c4a..28d5e844 100644
--- a/packages/vinxi/lib/manifest/dev-server-manifest.js
+++ b/packages/vinxi/lib/manifest/dev-server-manifest.js
@@ -16,6 +16,8 @@ export function createDevManifest(app) {
let router = app.getRouter(bundlerName);
+ let base = join(app.config.server.baseURL ?? "", router.base);
+
if (router.mode === "static") {
return {
json() {
@@ -27,7 +29,7 @@ export function createDevManifest(app) {
routes() {
return [];
},
- base: router.base,
+ base,
target: "static",
mode: router.mode,
handler: undefined,
@@ -64,7 +66,7 @@ export function createDevManifest(app) {
return {};
},
handler: router.handler,
- base: router.base,
+ base,
target: router.target,
mode: router.mode,
chunks: new Proxy(
@@ -83,7 +85,7 @@ export function createDevManifest(app) {
if (router.target === "browser") {
return {
output: {
- path: join(router.base, "@fs", absolutePath),
+ path: join(base, "@fs", absolutePath),
},
};
} else {
@@ -234,7 +236,7 @@ export function createDevManifest(app) {
attrs: {
key: "vite-client",
type: "module",
- src: join(router.base, "@vite", "client"),
+ src: join(base, "@vite", "client"),
},
},
]
@@ -242,7 +244,7 @@ export function createDevManifest(app) {
].filter(Boolean);
},
output: {
- path: join(router.base, "@fs", absolutePath),
+ path: join(base, "@fs", absolutePath),
},
};
} else {
diff --git a/packages/vinxi/lib/manifest/prod-server-manifest.js b/packages/vinxi/lib/manifest/prod-server-manifest.js
index 8719450b..e24a5c1b 100644
--- a/packages/vinxi/lib/manifest/prod-server-manifest.js
+++ b/packages/vinxi/lib/manifest/prod-server-manifest.js
@@ -1,3 +1,4 @@
+import { joinURL } from "ufo";
import invariant from "vinxi/lib/invariant";
import { handlerModule, join, virtualId } from "vinxi/lib/path";
@@ -7,21 +8,19 @@ import findAssetsInViteManifest from "./vite-manifest.js";
/** @typedef {import("../app.js").App & { config: { buildManifest: { [key:string]: any } }}} ProdApp */
-function createHtmlTagsForAssets(router, assets) {
- return assets.filter(
- (asset) =>
- asset.endsWith(".css") || asset.endsWith(".js"),
- )
- .map((asset) => ({
- tag: "link",
- attrs: {
- href: join(router.base, asset),
- key: join(router.base, asset),
- ...(asset.endsWith(".css")
- ? { rel: "stylesheet", precendence: "high" }
- : { rel: "modulepreload" }),
- },
- }));
+function createHtmlTagsForAssets(router, app, assets) {
+ return assets
+ .filter((asset) => asset.endsWith(".css") || asset.endsWith(".js"))
+ .map((asset) => ({
+ tag: "link",
+ attrs: {
+ href: joinURL(app.config.server.baseURL ?? "", router.base, asset),
+ key: join(app.config.server.baseURL ?? "", router.base, asset),
+ ...(asset.endsWith(".css")
+ ? { rel: "stylesheet", precendence: "high" }
+ : { rel: "modulepreload" }),
+ },
+ }));
}
/**
@@ -121,7 +120,11 @@ export function createProdManifest(app) {
: input;
return {
assets() {
- return createHtmlTagsForAssets(router, findAssetsInViteManifest(bundlerManifest, id));
+ return createHtmlTagsForAssets(
+ router,
+ app,
+ findAssetsInViteManifest(bundlerManifest, id),
+ );
},
output: {
path: join(
@@ -139,17 +142,26 @@ export function createProdManifest(app) {
return {
import() {
return import(
- /* @vite-ignore */ join(
+ /* @vite-ignore */ joinURL(
+ app.config.server.baseURL ?? "",
router.base,
bundlerManifest[id].file,
)
);
},
assets() {
- return createHtmlTagsForAssets(router, findAssetsInViteManifest(bundlerManifest, id));
+ return createHtmlTagsForAssets(
+ router,
+ app,
+ findAssetsInViteManifest(bundlerManifest, id),
+ );
},
output: {
- path: join(router.base, bundlerManifest[id].file),
+ path: joinURL(
+ app.config.server.baseURL ?? "",
+ router.base,
+ bundlerManifest[id].file,
+ ),
},
};
}
diff --git a/packages/vinxi/lib/nitro-dev.js b/packages/vinxi/lib/nitro-dev.js
index a817dbe5..5980d657 100644
--- a/packages/vinxi/lib/nitro-dev.js
+++ b/packages/vinxi/lib/nitro-dev.js
@@ -168,7 +168,10 @@ export function createDevServer(nitro) {
// Dev-only handlers
for (const handler of nitro.options.devHandlers) {
- app.use(handler.route || "/", handler.handler);
+ app.use(
+ joinURL(nitro.options.runtimeConfig.app.baseURL, handler.route ?? "/"),
+ handler.handler,
+ );
}
// User defined dev proxy
diff --git a/packages/vinxi/lib/plugins/config.js b/packages/vinxi/lib/plugins/config.js
index b9cc8935..93e6af2c 100644
--- a/packages/vinxi/lib/plugins/config.js
+++ b/packages/vinxi/lib/plugins/config.js
@@ -1,7 +1,7 @@
/**
*
* @param {string} tag
- * @param {Omit} conf
+ * @param {import('../vite-dev.d.ts').CustomizableConfig} conf
* @returns {import('../vite-dev.d.ts').Plugin}
*/
export function config(tag, conf) {
diff --git a/packages/vinxi/lib/plugins/manifest.js b/packages/vinxi/lib/plugins/manifest.js
index 271fcda1..68aba71c 100644
--- a/packages/vinxi/lib/plugins/manifest.js
+++ b/packages/vinxi/lib/plugins/manifest.js
@@ -29,6 +29,9 @@ export function manifest() {
"import.meta.env.ROUTER_NAME": JSON.stringify(router.name),
"import.meta.env.ROUTER_HANDLER": JSON.stringify(router.handler),
"import.meta.env.CWD": JSON.stringify(router.root),
+ "import.meta.env.SERVER_BASE_URL": JSON.stringify(
+ app.config.server.baseURL ?? "",
+ ),
"import.meta.env.ROUTERS": JSON.stringify(
app.config.routers.map((router) => router.name),
),
@@ -67,10 +70,13 @@ export function manifest() {
export function injectVinxiClient() {
/** @type {import('../router-mode.js').Router} */
let router;
+ /** @type {import('../app.js').App} */
+ let app;
return {
name: "vinxi:inject-client-runtime",
configResolved(config) {
router = config.router;
+ app = config.app;
},
apply: "serve",
transformIndexHtml(html) {
@@ -80,6 +86,7 @@ export function injectVinxiClient() {
attrs: {
type: "module",
src: join(
+ app.config.server.baseURL ?? "",
router.base,
"@fs",
`${fileURLToPath(
diff --git a/packages/vinxi/lib/vite-dev.d.ts b/packages/vinxi/lib/vite-dev.d.ts
index 97097684..a27f1bca 100644
--- a/packages/vinxi/lib/vite-dev.d.ts
+++ b/packages/vinxi/lib/vite-dev.d.ts
@@ -1,8 +1,8 @@
import { Plugin as VitePlugin, ResolvedConfig as _ResolvedConfig } from "vite";
import { App } from "./app.js";
-import { Router } from "./router-mode.js";
import { DevConfig } from "./dev-server.js";
+import { Router } from "./router-mode.js";
declare module "vite" {
interface UserConfig {
@@ -28,4 +28,27 @@ export type ViteConfig = _ResolvedConfig & { router: Router; app: App };
export type Plugin = VitePlugin;
+export type CustomizableConfig = Omit<
+ import("vite").InlineConfig,
+ | "appType"
+ | "app"
+ | "router"
+ | "base"
+ | "root"
+ | "publicDir"
+ | "mode"
+ | "server"
+ | "preview"
+ | "clearScreen"
+ | "configFile"
+ | "envFile"
+> & {
+ build?: Omit<
+ import("vite").InlineConfig["build"],
+ "outDir" | "ssr" | "ssrManifest" | "rollupOptions"
+ > & {
+ rollupOptions?: Omit;
+ };
+};
+
export type { ConfigEnv as ConfigEnv } from "vite";