Skip to content

Commit

Permalink
docs(changeset): added import() helpers to manifest
Browse files Browse the repository at this point in the history
  • Loading branch information
nksaraf committed Nov 3, 2023
1 parent 3014bf3 commit 0cc2f4a
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 169 deletions.
7 changes: 7 additions & 0 deletions .changeset/stale-badgers-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@vinxi/react": patch
"@vinxi/solid": patch
"vinxi": patch
---

added `import()` helpers to manifest
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ dist
docs/.vitepress/dist
docs/.vitepress/cache
.vitepress
tmp
5 changes: 1 addition & 4 deletions examples/react/rsc/spa/app/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ document.addEventListener("click", async (e) => {

globalThis.__vite__ = createModuleLoader({
loadModule: async (id) => {
return import(
/* @vite-ignore */ import.meta.env.MANIFEST["client"].chunks[id].output
.path
);
return import.meta.env.MANIFEST["client"].chunks[id].import();
},
});

Expand Down
44 changes: 19 additions & 25 deletions examples/react/rsc/spa/app/react-server.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,28 @@
import { renderAsset } from "@vinxi/react";
import { renderToPipeableStream } from "@vinxi/react-server-dom/server";
import { Suspense } from "react";
import { eventHandler } from "vinxi/server";
import { eventHandler, setHeaders } from "vinxi/server";

import App from "./app";

export default eventHandler(async (event) => {
async function loadModule(id) {
if (import.meta.env.DEV) {
return await import(
import.meta.env.MANIFEST["rsc"].chunks[id].output.path
);
}
const reactServerManifest = import.meta.env.MANIFEST["rsc"];
const clientManifest = import.meta.env.MANIFEST["client"];

if (globalThis.$$chunks[id + ".js"]) {
return globalThis.$$chunks[id + ".js"];
}
return await import(import.meta.env.MANIFEST["rsc"].chunks[id].output.path);
}
if (event.node.req.method === "POST") {
const {
renderToPipeableStream,
decodeReply,
decodeReplyFromBusboy,
decodeAction,
} = await import("@vinxi/react-server-dom/server");
const serverReference = event.node.req.headers["server-action"];
const serverReference = event.headers.get("server-action");
if (serverReference) {
// This is the client-side case
const [filepath, name] = serverReference.split("#");
const action = (await loadModule(filepath))[name];
const action = (await reactServerManifest.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,
// you'd have a manifest verifying this before even importing it.
Expand Down Expand Up @@ -69,14 +62,13 @@ export default eventHandler(async (event) => {
throw new Error("Invalid request");
}
}
const reactServerManifest = import.meta.env.MANIFEST["rsc"];

const serverAssets = await reactServerManifest.inputs[
reactServerManifest.handler
].assets();
const clientManifest = import.meta.env.MANIFEST["client"];

const assets = await clientManifest.inputs[clientManifest.handler].assets();

const events = {};
const stream = renderToPipeableStream(
<App
assets={
Expand All @@ -88,15 +80,17 @@ export default eventHandler(async (event) => {
/>,
);

// @ts-ignore
stream._read = () => {};
// @ts-ignore
stream.on = (event, listener) => {
events[event] = listener;
};
// // @ts-ignore
// stream._read = () => {};
// // @ts-ignore
// stream.on = (event, listener) => {
// events[event] = listener;
// };

event.node.res.setHeader("Content-Type", "text/x-component");
event.node.res.setHeader("Router", "rsc");
setHeaders(event, {
"Content-Type": "text/x-component",
Router: "rsc",
});

return stream;
});
74 changes: 10 additions & 64 deletions examples/react/rsc/spa/app/server-action.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,20 @@
// import { renderAsset } from "@vinxi/react";
// import { renderToPipeableStream } from "@vinxi/react-server-dom/server";
// import React, { Suspense } from "react";
import { eventHandler, sendStream } from "vinxi/server";

// import App from "./app";
import { eventHandler, readRawBody, setHeader } from "vinxi/server";

export default eventHandler(async (event) => {
async function loadModule(id) {
if (import.meta.env.DEV) {
return await import(
import.meta.env.MANIFEST["rsc"].chunks[id].output.path
);
}

if (globalThis.$$chunks[id + ".js"]) {
return globalThis.$$chunks[id + ".js"];
}
return await import(import.meta.env.MANIFEST["rsc"].chunks[id].output.path);
}
if (event.node.req.method === "POST") {
if (event.method === "POST") {
const {
renderToPipeableStream,
decodeReply,
decodeReplyFromBusboy,
decodeAction,
} = await import("@vinxi/react-server-dom/server");
const serverReference = event.node.req.headers["server-action"];
const serverReference = event.headers.get("server-action");
if (serverReference) {
// This is the client-side case
const [filepath, name] = serverReference.split("#");
const action = (await loadModule(filepath))[name];
const action = (
await import.meta.env.MANIFEST["server"].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,
// you'd have a manifest verifying this before even importing it.
Expand All @@ -45,16 +30,7 @@ export default eventHandler(async (event) => {
// req.pipe(bb);
// args = await reply;
// } else {
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 text = await readRawBody(event);
console.log(text);

args = await decodeReply(text);
Expand All @@ -74,11 +50,12 @@ export default eventHandler(async (event) => {
events[event] = listener;
};

event.node.res.setHeader("Content-Type", "application/json");
event.node.res.setHeader("Router", "server");
setHeader(event, "Content-Type", "application/json");
setHeader(event, "Router", "server");

return stream;
} catch (x) {
console.error(x);
// We handle the error on the client
}
// Refresh the client and return the value
Expand All @@ -87,35 +64,4 @@ export default eventHandler(async (event) => {
throw new Error("Invalid request");
}
}
console.log("rendering");
// const reactServerManifest = import.meta.env.MANIFEST["rsc"];
// const serverAssets = await reactServerManifest.inputs[
// reactServerManifest.handler
// ].assets();
// const clientManifest = import.meta.env.MANIFEST["client"];
// const assets = await clientManifest.inputs[clientManifest.handler].assets();

// const events = {};
// const stream = renderToPipeableStream(
// <App
// assets={
// <Suspense>
// {serverAssets.map((m) => renderAsset(m))}
// {assets.map((m) => renderAsset(m))}
// </Suspense>
// }
// />,
// );

// // @ts-ignore
// stream._read = () => {};
// // @ts-ignore
// stream.on = (event, listener) => {
// events[event] = listener;
// };

// event.node.res.setHeader("Content-Type", "text/x-component");
// event.node.res.setHeader("Router", "rsc");

// return result;
});
2 changes: 1 addition & 1 deletion examples/react/rsc/spa/tmp/count
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4
8
4 changes: 1 addition & 3 deletions packages/vinxi-react/lazy-route.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ export default function lazyRoute(
if (import.meta.env.DEV) {
let manifest = import.meta.env.SSR ? serverManifest : clientManifest;

const mod = await import(
/* @vite-ignore */ manifest.inputs[component.src].output.path
);
const mod = await manifest.inputs[component.src].import();
invariant(
mod[exported],
`Module ${component.src} does not export ${exported}`,
Expand Down
4 changes: 1 addition & 3 deletions packages/vinxi-solid/lazy-route.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ export default function lazyRoute(
if (import.meta.env.DEV) {
let manifest = import.meta.env.SSR ? serverManifest : clientManifest;

const mod = await import(
/* @vite-ignore */ manifest.inputs[component.src].output.path
);
const mod = await manifest.inputs[component.src].import();
invariant(
mod[exported],
`Module ${component.src} does not export ${exported}`,
Expand Down
6 changes: 6 additions & 0 deletions packages/vinxi/lib/dev-server.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { inspect } from "@vinxi/devtools";

import { fileURLToPath } from "node:url";

import { consola, withLogger } from "./logger.js";
import { normalize } from "./path.js";

export * from "./router-dev-plugins.js";

Expand Down Expand Up @@ -65,6 +68,9 @@ export async function createViteHandler(router, app, serveConfig) {
router,
app,
server: {
fs: {
allow: [normalize(fileURLToPath(new URL("../", import.meta.url))), "."],
},
middlewareMode: true,
hmr: {
port,
Expand Down
6 changes: 6 additions & 0 deletions packages/vinxi/lib/manifest/client-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const manifest = new Proxy(
? join(import.meta.env.BASE_URL, "@fs", chunk)
: join(import.meta.env.BASE_URL, chunk + ".js");
return {
import() {
return import(/* @vite-ignore */ outputPath);
},
output: {
path: outputPath,
},
Expand All @@ -42,6 +45,9 @@ const manifest = new Proxy(
? join(import.meta.env.BASE_URL, "@fs", input)
: window.manifest[input].output;
return {
async import() {
return import(/* @vite-ignore */ outputPath);
},
async assets() {
if (import.meta.env.DEV) {
const assetsPath =
Expand Down
18 changes: 16 additions & 2 deletions packages/vinxi/lib/manifest/dev-server-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ export function createDevManifest(app) {
"No manifest for static router",
);

let relativePath = relative(app.config.root, chunk);
if (router.target === "browser") {
return {
output: {
Expand All @@ -70,6 +69,11 @@ export function createDevManifest(app) {
};
} else {
return {
import() {
return router.internals.devServer?.ssrLoadModule(
/* @vite-ignore */ absolutePath,
);
},
output: {
path: join(absolutePath),
},
Expand Down Expand Up @@ -146,6 +150,11 @@ export function createDevManifest(app) {

if (router.target === "browser") {
return {
import() {
return router.internals.devServer?.ssrLoadModule(
/* @vite-ignore */ join(absolutePath),
);
},
async assets() {
return [
...(viteServer
Expand Down Expand Up @@ -186,6 +195,11 @@ export function createDevManifest(app) {
};
} else {
return {
import() {
return router.internals.devServer?.ssrLoadModule(
/* @vite-ignore */ join(absolutePath),
);
},
async assets() {
return [
...(viteServer
Expand All @@ -208,7 +222,7 @@ export function createDevManifest(app) {
];
},
output: {
path: join(router.base, "@fs", absolutePath),
path: absolutePath,
},
};
}
Expand Down
21 changes: 20 additions & 1 deletion packages/vinxi/lib/manifest/prod-server-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,20 @@ export function createProdManifest(app) {
{
get(target, chunk) {
invariant(typeof chunk === "string", "Chunk expected");
const chunkPath = join(
router.outDir,
router.base,
chunk + ".js",
);
return {
import() {
if (globalThis.$$chunks[chunk + ".js"]) {
return globalThis.$$chunks[chunk + ".js"];
}
return import(/* @vite-ignore */ chunkPath);
},
output: {
path: join(router.outDir, router.base, chunk + ".js"),
path: chunkPath,
},
};
},
Expand Down Expand Up @@ -115,6 +126,14 @@ export function createProdManifest(app) {
? virtualId(handlerModule(router))
: input;
return {
import() {
return import(
/* @vite-ignore */ join(
router.base,
bundlerManifest[id].file,
)
);
},
assets() {
return findAssetsInViteManifest(bundlerManifest, id)
.filter((asset) => asset.endsWith(".css"))
Expand Down
1 change: 1 addition & 0 deletions packages/vinxi/types/manifest.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type Manifest = {
chunks: {
[key: string]: {
assets(): Promise<Asset[]>;
import<T = { default: any; [k: string]: any }>(): Promise<T>;
output: {
path: string;
};
Expand Down
5 changes: 1 addition & 4 deletions test/templates/react-rsc/app/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import { ServerComponent } from "./server-component";

globalThis.__vite__ = createModuleLoader({
loadModule: async (id) => {
return import(
/* @vite-ignore */ import.meta.env.MANIFEST["client"].chunks[id].output
.path
);
return import.meta.env.MANIFEST["client"].chunks[id].import();
},
});

Expand Down
Loading

0 comments on commit 0cc2f4a

Please sign in to comment.