Skip to content

Commit

Permalink
feat: new extension vike-solid-query
Browse files Browse the repository at this point in the history
  • Loading branch information
phonzammi committed Sep 1, 2024
1 parent b6a669c commit b04b04a
Show file tree
Hide file tree
Showing 28 changed files with 1,272 additions and 19 deletions.
2 changes: 2 additions & 0 deletions examples/solid-query/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules/
/dist/
15 changes: 15 additions & 0 deletions examples/solid-query/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Full-fledged example of using `vike-solid`, showcasing:

- [Layout](https://vike.dev/Layout)
- Rendering to `<head>`
- Fetching data with [`data()`](https://vike.dev/data) hook
- [Toggling SSR](https://vike.dev/ssr) on a per-page basis.
- [configs](https://vike.dev/config)
- [Error page](https://vike.dev/error-page)

```bash
git clone [email protected]:vikejs/vike-solid
cd vike-solid/examples/full/
pnpm install
pnpm run dev
```
36 changes: 36 additions & 0 deletions examples/solid-query/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions examples/solid-query/layouts/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* Links */
a {
text-decoration: none;
}
#sidebar a {
padding: 2px 10px;
margin-left: -10px;
}
#sidebar a.is-active {
background-color: #eee;
}

/* Reset */
body {
margin: 0;
font-family: sans-serif;
}
* {
box-sizing: border-box;
}

/* Page Transition Anmiation */
#page-content {
opacity: 1;
transition: opacity 0.3s ease-in-out;
}
body.page-is-transitioning #page-content {
opacity: 0;
}
21 changes: 21 additions & 0 deletions examples/solid-query/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"private": true,
"scripts": {
"dev": "vite dev",
"preview": "vite build && vite preview",
"test": "tsc --noEmit"
},
"dependencies": {
"@tanstack/solid-query": "5.52.2",
"node-fetch": "^3.3.2",
"solid-js": "^1.8.21",
"vike": "^0.4.191",
"vike-solid": "workspace:^",
"vike-solid-query": "workspace:^"
},
"devDependencies": {
"typescript": "^5.5.4",
"vite": "^5.4.2"
},
"type": "module"
}
9 changes: 9 additions & 0 deletions examples/solid-query/pages/+Head.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import logoUrl from "../assets/logo.svg";

export function Head() {
return (
<>
<link rel="icon" href={logoUrl} />
</>
);
}
70 changes: 70 additions & 0 deletions examples/solid-query/pages/+Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import "../layouts/style.css";
import logoUrl from "../assets/logo.svg";
import type { JSX } from "solid-js";

export function Layout(props: { children?: JSX.Element }) {
return (
<div
style={{
display: "flex",
"max-width": "900px",
margin: "auto",
}}
>
<Sidebar>
<Logo />
</Sidebar>
<Content>{props.children}</Content>
</div>
);
}

function Sidebar(props: { children: JSX.Element }) {
return (
<div
id="sidebar"
style={{
padding: "20px",
"flex-shrink": 0,
display: "flex",
"flex-direction": "column",
"line-height": "1.8em",
"border-right": "2px solid #eee",
}}
>
{props.children}
</div>
);
}

function Content(props: { children: JSX.Element }) {
return (
<div id="page-container">
<div
id="page-content"
style={{
padding: "20px",
"padding-bottom": "50px",
"min-height": "100vh",
}}
>
{props.children}
</div>
</div>
);
}

function Logo() {
return (
<div
style={{
"margin-top": "20px",
"margin-bottom": "10px",
}}
>
<a href="/">
<img src={logoUrl} height={64} width={64} />
</a>
</div>
);
}
13 changes: 13 additions & 0 deletions examples/solid-query/pages/+config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import vikeSolid from "vike-solid/config";
import vikeSolidQuery from "vike-solid-query/config";
import type { Config } from "vike/types";

// Default config (can be overridden by pages)
export default {
title: "My Vike + Solid App", // <title>

passToClient: ["routeParams"],
stream: true,
injectScriptsAt: "STREAM",
extends: [vikeSolid, vikeSolidQuery],
} satisfies Config;
18 changes: 18 additions & 0 deletions examples/solid-query/pages/index/+Page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Counter } from "./Counter";
import { Movies } from "./Movies";

export function Page() {
return (
<>
<h1>My Vike + React app</h1>
This page is:
<ul>
<li>Rendered to HTML.</li>
<li>
Interactive while loading. <Counter />
</li>
</ul>
<Movies />
</>
);
}
8 changes: 8 additions & 0 deletions examples/solid-query/pages/index/@id/+Page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { usePageContext } from "vike-solid/usePageContext";
import { Movie } from "./Movie";

export function Page() {
const pageContext = usePageContext();
const id = pageContext.routeParams["id"];
return <Movie id={id} />;
}
68 changes: 68 additions & 0 deletions examples/solid-query/pages/index/@id/Movie.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { createQuery } from "@tanstack/solid-query";
import { QueryBoundary } from "vike-solid-query";
import { Config } from "vike-solid/Config";
import type { MovieDetails } from "../types";

export function Movie(props: { id: string }) {
const query = createQuery(() => ({
queryKey: ["movies", props.id],
queryFn: () => getStarWarsMovie(props.id),
// Disabled to showcase error fallback
retry: false,
}));

return (
<QueryBoundary
query={query}
loadingFallback={<p>Loading movie {props.id}</p>}
errorFallback={(err, reset) => (
<>
<div>Loading movie {props.id} failed</div>
<div>{err.toString()}</div>
<button
onClick={async () => {
reset();
await query.refetch();
}}
>
Retry
</button>
</>
)}
>
{(movie) => (
<>
<Config
title={movie.title}
Head={
<meta name="description" content={`Star Wars Movie ${query.data?.title} from ${query.data?.director}`} />
}
/>
<h1>Star Wars Movies</h1>
<ul>
<li>
Title: <b>{movie.title}</b>
</li>
<li>
Release date: <b>{movie.release_date}</b>
</li>
</ul>
<p>
Source: <a href="https://star-wars.brillout.com">star-wars.brillout.com</a>.
</p>
</>
)}
</QueryBoundary>
);
}

async function getStarWarsMovie(id: string): Promise<MovieDetails> {
await new Promise((r) => setTimeout(r, 500));

if (Math.random() > 0.4) {
throw new Error("Failed to fetch");
}

const response = await fetch(`https://star-wars.brillout.com/api/films/${id}.json`);
return response.json();
}
7 changes: 7 additions & 0 deletions examples/solid-query/pages/index/Counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createSignal } from "solid-js";

export function Counter() {
const [count, setCount] = createSignal(0);

return <button onClick={() => setCount((count) => count + 1)}>Counter {count()}</button>;
}
57 changes: 57 additions & 0 deletions examples/solid-query/pages/index/Movies.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { createQuery } from "@tanstack/solid-query";
import type { MovieDetails } from "./types";
import { QueryBoundary } from "vike-solid-query";
import { For } from "solid-js";
import { navigate } from "vike/client/router";
import { Config } from "vike-solid/Config";
import { Head } from "vike-solid/Head";

export function Movies() {
const query = createQuery(() => ({
queryKey: ["movies"],
queryFn: getStarWarsMovies,
}));

const onNavigate = (id: string) => {
navigate(`/${id}`);
};

return (
<QueryBoundary query={query} loadingFallback={<p>Loading movies ...</p>}>
{(movies) => (
<>
<Config title={`${movies.length} Star Wars movies`} />
<Head>
<meta name="description" content={`List of ${movies.length} Star Wars movies.`} />
</Head>
<h1>Star Wars Movies</h1>
<ol>
<For each={movies}>
{(movie) => (
<li>
<button onClick={() => onNavigate(movie.id)}>{movie.title}</button> ({movie.release_date})
</li>
)}
</For>
</ol>
<p>
Source: <a href="https://star-wars.brillout.com">star-wars.brillout.com</a>.
</p>
</>
)}
</QueryBoundary>
);
}

async function getStarWarsMovies(): Promise<MovieDetails[]> {
// Simulate slow network
await new Promise((r) => setTimeout(r, 2000));

const response = await fetch("https://star-wars.brillout.com/api/films.json");
let movies: MovieDetails[] = ((await response.json()) as any).results;
movies = movies.map((movie: MovieDetails, i: number) => ({
...movie,
id: String(i + 1),
}));
return movies;
}
7 changes: 7 additions & 0 deletions examples/solid-query/pages/index/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type MovieDetails = {
id: string;
title: string;
release_date: string;
director: string;
producer: string;
};
14 changes: 14 additions & 0 deletions examples/solid-query/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"strict": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"target": "ES2021",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"types": ["vike-solid/client"],
"jsx": "preserve",
"jsxImportSource": "solid-js",
"skipLibCheck": true,
"esModuleInterop": true
}
}
7 changes: 7 additions & 0 deletions examples/solid-query/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import vikeSolid from "vike-solid/vite";
import vike from "vike/plugin";
import type { UserConfig } from "vite";

export default {
plugins: [vike(), vikeSolid()],
} satisfies UserConfig;
2 changes: 2 additions & 0 deletions packages/vike-solid-query/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules/
/dist/
Loading

0 comments on commit b04b04a

Please sign in to comment.