Skip to content

Commit

Permalink
added solid start example with common server plugins for dev and prod
Browse files Browse the repository at this point in the history
  • Loading branch information
nksaraf committed Jul 26, 2023
1 parent a63df01 commit c884f41
Show file tree
Hide file tree
Showing 31 changed files with 701 additions and 81 deletions.
1 change: 1 addition & 0 deletions examples/solid/ssr/solid-start/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vercel
91 changes: 91 additions & 0 deletions examples/solid/ssr/solid-start/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import fs from "fs";
import { createApp } from "vinxi";
import {
BaseFileSystemRouter,
analyzeModule,
cleanPath,
} from "vinxi/file-system-router";
import solid from "vite-plugin-solid";

class SolidStartFileSystemRouter extends BaseFileSystemRouter {
toPath(src) {
const routePath = cleanPath(src, this.config)
// remove the initial slash
.slice(1)
.replace(/index$/, "")
.replace(/\[([^\/]+)\]/g, (_, m) => {
if (m.length > 3 && m.startsWith("...")) {
return `*${m.slice(3)}`;
}
if (m.length > 2 && m.startsWith("[") && m.endsWith("]")) {
return `:${m.slice(1, -1)}?`;
}
return `:${m}`;
});

return routePath?.length > 0 ? `/${routePath}` : "/";
}

toRoute(src) {
let path = this.toPath(src);

const [_, exports] = analyzeModule(src);
const hasRouteData = exports.find((e) => e.n === "routeData");
return {
$component: {
src: src,
pick: ["default", "$css"],
},
$$data: hasRouteData
? {
src: src,
pick: ["routeData"],
}
: undefined,
path,
filePath: src,
};
}
}

function createSolidStartApp({ client = {}, server = {} } = {}) {
return createApp({
routers: [
{
name: "public",
mode: "static",
dir: "./public",
base: "/",
},
{
name: "client",
mode: "build",
handler: "./src/entry-client.tsx",
style: SolidStartFileSystemRouter,
dir: "./src/routes",
build: {
target: "browser",
plugins: () => [
solid({
ssr: true,
}),
],
},
base: "/_build",
},
{
name: "ssr",
mode: "handler",
handler: "./src/entry-server.tsx",
dir: "./src/routes",
style: SolidStartFileSystemRouter,
build: {
target: "node",
plugins: () => [solid({ ssr: true })],
},
},
],
});
}

export default createSolidStartApp();
24 changes: 24 additions & 0 deletions examples/solid/ssr/solid-start/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"type": "module",
"scripts": {
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start"
},
"dependencies": {
"@babel/core": "^7.22.8",
"@picocss/pico": "^1.5.7",
"@solidjs/meta": "^0.28.5",
"@solidjs/router": "^0.8.2",
"@types/babel__core": "^7.20.1",
"@vinxi/solid": "workspace:^",
"autoprefixer": "^10.4.14",
"solid-js": "^1.7.8",
"tailwindcss": "^3.3.2",
"vinxi": "workspace:^",
"vite-plugin-solid": "^2.7.0"
},
"devDependencies": {
"axios": "^1.4.0"
}
}
6 changes: 6 additions & 0 deletions examples/solid/ssr/solid-start/postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Binary file not shown.
12 changes: 12 additions & 0 deletions examples/solid/ssr/solid-start/src/Counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createSignal } from "solid-js";

export function Counter() {
const [count, setCount] = createSignal(0);
return (
<>
<button onClick={() => setCount((count) => count + 1)}>
Click me!!: {count()}!
</button>
</>
);
}
37 changes: 37 additions & 0 deletions examples/solid/ssr/solid-start/src/db.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import axios from "axios";

import { NotFoundError } from "./error";

type PostType = {
id: string;
title: string;
body: string;
};

export const fetchPosts = async () => {
console.log("Fetching posts...");
await new Promise((r) => setTimeout(r, 500));
return axios
.get<PostType[]>("https://jsonplaceholder.typicode.com/posts")
.then((r) => r.data.slice(0, 10));
};

export const fetchPost = async (postId: string) => {
console.log(`Fetching post with id ${postId}...`);
await new Promise((r) => setTimeout(r, 500));
const post = await axios
.get<PostType>(`https://jsonplaceholder.typicode.com/posts/${postId}`)
.then((r) => r.data)
.catch((e) => {
if (e.response.status === 404) {
return null;
}
throw e;
});

if (!post) {
throw new NotFoundError(`Post with id "${postId}" not found!`);
}

return post;
};
60 changes: 60 additions & 0 deletions examples/solid/ssr/solid-start/src/entry-client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/// <reference types="vinxi/client" />
import { MetaProvider } from "@solidjs/meta";
import { Router, Routes } from "@solidjs/router";
import { createAssets, lazyRoute } from "@vinxi/solid";
import { NoHydration, Suspense, hydrate } from "solid-js/web";
import fileRoutes from "vinxi/routes";
import "vinxi/runtime/client";

import App from "./root";

const Assets = createAssets(
import.meta.env.MANIFEST["client"].handler,
import.meta.env.MANIFEST["client"],
);

function createRoute(route) {
return {
path: route.path,
component: lazyRoute(route.$component, import.meta.env.MANIFEST["client"]),
data: route.$$data ? route.$$data.require().routeData : null,
children: route.children ? route.children.map(createRoute) : null,
};
}

const routes = fileRoutes.map(createRoute);

function FileRoutes() {
return routes as any;
}

hydrate(
() => (
<MetaProvider>
<Router>
<App
assets={
<>
<NoHydration></NoHydration>
<Suspense>
<Assets />
</Suspense>
</>
}
scripts={
<>
<NoHydration></NoHydration>
</>
}
>
<Suspense>
<Routes>
<FileRoutes />
</Routes>
</Suspense>
</App>
</Router>
</MetaProvider>
),
document,
);
113 changes: 113 additions & 0 deletions examples/solid/ssr/solid-start/src/entry-server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/// <reference types="vinxi/server" />
import { MetaProvider, renderTags } from "@solidjs/meta";
import { Router, Routes } from "@solidjs/router";
import { lazyRoute, renderAsset } from "@vinxi/solid";
import {
HydrationScript,
NoHydration,
Suspense,
renderToStream,
ssr,
useAssets,
} from "solid-js/web";
import { eventHandler } from "vinxi/runtime/server";

import { join } from "node:path";

import App from "./root";
import { routes } from "./routes";

export default eventHandler(async (event) => {
const events = {};

const clientManifest = import.meta.env.MANIFEST["client"];
const serverManifest = import.meta.env.MANIFEST["ssr"];

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

function createRoute(route) {
return {
...route,
component: lazyRoute(route.$component, clientManifest, serverManifest),
data: route.$$data ? route.$$data.require().routeData : undefined,
children: route.children ? route.children.map(createRoute) : undefined,
};
}

const pageRoutes = routes.map(createRoute);

const FileRoutes = () => {
return pageRoutes as any;
};
console.log(routes);
const tags = [];
function Meta() {
useAssets(() => ssr(renderTags(tags)) as any);
return null;
}

const manifestJson = await clientManifest.json();
const stream = renderToStream(
() => (
<MetaProvider tags={tags}>
<Router
out={{}}
url={join(import.meta.env.BASE_URL, event.path)}
base={import.meta.env.BASE_URL}
>
<App
assets={
<>
<NoHydration>
<Meta />
</NoHydration>
<Suspense>{assets.map((m) => renderAsset(m))}</Suspense>
</>
}
scripts={
<>
<NoHydration>
<HydrationScript />
<script
innerHTML={`window.manifest = ${JSON.stringify(
manifestJson,
)}`}
></script>
<script
type="module"
src={
clientManifest.inputs[clientManifest.handler].output.path
}
/>
</NoHydration>
</>
}
>
<Suspense>
<Routes>
<FileRoutes />
</Routes>
</Suspense>
</App>
</Router>
</MetaProvider>
),
{
onCompleteAll(info) {
events["end"]?.();
},
},
);

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

return {
pipe: stream.pipe.bind(stream),
on: (event, listener) => {
events[event] = listener;
},
};
});
1 change: 1 addition & 0 deletions examples/solid/ssr/solid-start/src/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class NotFoundError extends Error {}
29 changes: 29 additions & 0 deletions examples/solid/ssr/solid-start/src/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// @refresh reload
import { A } from "@solidjs/router";

import { Counter } from "./Counter";
import "./style.css";

export default function App(props) {
return (
<html lang="en">
<head>
<link rel="icon" href="/favicon.ico" />
{props.assets}
</head>
<body>
<section>
<h1>Hello AgentConf with ya asdo!!!</h1>
<A href="/hello">Hello</A>
<A href="/abc">ABC</A>
<A href="/def">DEF</A>
<A href="/">Home</A>
<A href="/posts">Posts</A>
<Counter />
</section>
{props.children}
{props.scripts}
</body>
</html>
);
}
Loading

0 comments on commit c884f41

Please sign in to comment.