Skip to content

Commit

Permalink
WIP: c884f41 added solid start example with common server plugins for…
Browse files Browse the repository at this point in the history
… dev and prod
  • Loading branch information
nksaraf committed Jul 29, 2023
1 parent 826aeff commit 8701a3e
Show file tree
Hide file tree
Showing 20 changed files with 905 additions and 210 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ playwright-report
stats.html
.fixtures
*.code-workspace

# Local Netlify folder
.netlify
dist
93 changes: 81 additions & 12 deletions examples/react/rsc/spa/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { join } from "path";
import { createApp } from "vinxi";
import { virtual } from "vinxi/lib/plugins/virtual";

import { builtinModules } from "node:module";

function hash(str) {
let hash = 0;

Expand All @@ -20,7 +22,7 @@ function serverComponents() {
const clientModules = new Set();
return [
serverComponent({
hash,
hash: (e) => `c_${hash(e)}`,
onServerReference(reference) {
serverModules.add(reference);
},
Expand All @@ -44,6 +46,36 @@ function serverComponents() {
config(inlineConfig, env) {
if (env.command === "build") {
return {
build: {
rollupOptions: {
onwarn: (warning, warn) => {
// suppress warnings about source map issues for now
// these are caused originally by rollup trying to complain about directives
// in the middle of the files
// TODO: fix source map issues
if (warning.code === "SOURCEMAP_ERROR") {
return;
}
},
output: {
// preserve the export names of the server actions in chunks
minifyInternalExports: false,
manualChunks: (chunk) => {
console.log("manula chunks", chunk);
// server references should be emitted as separate chunks
// so that we can load them individually when server actions
// are called. we need to do this in manualChunks because we don't
// want to run a preanalysis pass just to identify these
if (serverModules.has(chunk)) {
return `c_${hash(chunk)}`;
}
},
// we want to control the chunk names so that we can load them
// individually when server actions are called
chunkFileNames: "[name].js",
},
},
},
resolve: {
conditions: [
"node",
Expand Down Expand Up @@ -126,7 +158,7 @@ function clientComponents() {
entry: router.handler,
...Object.fromEntries(
reactServerManifest.client.map((key) => {
return [hash(key), key];
return [`c_${hash(key)}`, key];
}),
),
};
Expand Down Expand Up @@ -236,12 +268,33 @@ function viteServer() {
}

export default createApp({
server: {
externals: {
// traceOptions: {
// conditions: ["import", "default"],
// },
inline: ["h3", "h3-nightly"],
},
plugins: ["#extra-chunks"],
virtual: {
"#extra-chunks": (app) => {
const rscChunks = getChunks(app, "rsc");

return `
const chunks = {};
${rscChunks}
export default function app() {
globalThis.$$chunks = chunks
}
`;
},
},
},
routers: [
{
name: "public",
mode: "static",
dir: "./public",
base: "/",
},
{
name: "rsc",
Expand All @@ -264,14 +317,30 @@ export default createApp({
},
base: "/",
},
// {
// name: "ssr",
// mode: "handler",
// handler: "./app/server.tsx",
// build: {
// target: "node",
// plugins: () => [reactRefresh(), viteServer(), clientComponents()],
// },
// },
],
});
function getChunks(app, routerName) {
const router = app.getRouter(routerName);
const bundlerManifest = JSON.parse(
readFileSync(
join(router.build.outDir, router.base, "manifest.json"),
"utf-8",
),
);

const chunks = Object.entries(bundlerManifest)
.filter(
([name, chunk]) => chunk.file.startsWith("c_") && name !== router.handler,
)
.map(([name, chunk]) => {
return `import * as mod from '${join(
router.build.outDir,
router.base,
chunk.file,
)}';
chunks['${chunk.file}'] = mod
`;
})
.join("\n");
return chunks;
}
1 change: 0 additions & 1 deletion examples/react/rsc/spa/app/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@ export function sayHello() {
}

export function getStore() {
console.log("getStore", store);
return store.count;
}
39 changes: 26 additions & 13 deletions examples/react/rsc/spa/app/react-server.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
import { renderAsset } from "@vinxi/react";
import { renderToPipeableStream } from "@vinxi/react-server-dom-vite/server";
import React, { Suspense } from "react";
import { eventHandler } from "vinxi/runtime/server";
import { eventHandler, sendStream } from "vinxi/runtime/server";

import App from "./app";

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

console.log(id, globalThis.$$chunks);
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,
Expand All @@ -18,11 +32,7 @@ export default eventHandler(async (event) => {
if (serverReference) {
// This is the client-side case
const [filepath, name] = serverReference.split("#");
const action = (
await import(
import.meta.env.MANIFEST["rsc"].inputs[filepath].output.path
)
)[name];
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.
Expand Down Expand Up @@ -68,30 +78,33 @@ export default eventHandler(async (event) => {
}
console.log("rendering");
const reactServerManifest = import.meta.env.MANIFEST["rsc"];
// const serverAssets = await reactServerManifest.inputs[
// reactServerManifest.handler
// ].assets();
const serverAssets = await reactServerManifest.inputs[
reactServerManifest.handler
].assets();
const clientManifest = import.meta.env.MANIFEST["client"];
// const assets = await clientManifest.inputs[clientManifest.handler].assets();
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))} */}
{serverAssets.map((m) => renderAsset(m))}
{assets.map((m) => renderAsset(m))}
</Suspense>
}
/>,
);

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

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

console.log(stream);

return stream;
});
34 changes: 34 additions & 0 deletions examples/react/rsc/ssr/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,40 @@ export default createApp({
handler: "./app/server.tsx",
build: {
target: "node",
serverPlugins: () => [
(app) => {
const router = app.getRoute("rsc");
const bundlerManifest = JSON.parse(
readFileSync(
join(router.build.outDir, router.base, "manifest.json"),
"utf-8",
),
);

const chunks = Object.entries(bundlerManifest)
.filter(
([name, chunk]) => chunk.isEntry && name !== router.handler,
)
.map(([name, chunk]) => {
return `import * as mod from '${join(
router.build.outDir,
router.base,
chunk.file,
)}';
chunks['${chunk.file}'] = mod
`;
})
.join("\n");

return `
const chunks = {};
${chunks}
export default function app() {
globalThis.$$chunks = chunks
}
`;
},
],
plugins: () => [reactRefresh(), viteServer(), clientComponents()],
},
},
Expand Down
8 changes: 8 additions & 0 deletions examples/react/ssr/tanstack-router-app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ class TanstackFileSystemRouter extends BaseFileSystemRouter {
}

export default createApp({
server: {
externals: {
traceOptions: {
conditions: ["default"],
},
inline: ["h3"],
},
},
routers: [
{
name: "public",
Expand Down
16 changes: 15 additions & 1 deletion examples/react/ssr/tanstack-router-app/app/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,21 @@ const router = createRouter(import.meta.env.MANIFEST["client"], undefined);
router.update({
context: {
...router.context,
assets: <Assets />,
assets: (
<>
<Assets />
{import.meta.env.DEV ? (
<script
src={
import.meta.env.MANIFEST["client"].inputs[
import.meta.env.MANIFEST["client"].handler
].output.path
}
type="module"
/>
) : null}
</>
),
},
});
router.hydrate();
Expand Down
Loading

0 comments on commit 8701a3e

Please sign in to comment.