diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a39b5c..c192a0d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,6 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] example: - examples/basic - - examples/onBeforeRender - examples/ssr-spa steps: diff --git a/examples/basic/README.md b/examples/basic/README.md index 9b13f9a..d02f79e 100644 --- a/examples/basic/README.md +++ b/examples/basic/README.md @@ -12,7 +12,3 @@ cd vike-solid/examples/basic/ pnpm install pnpm run dev ``` - -> **NOTE:** for now `pnpm` is required because of the `workspace:` specifier in -> `package.json`. With this, the example makes use of the local `vike-solid` -> implementation instead of the downloading it from npm. diff --git a/examples/basic/package.json b/examples/basic/package.json index 6528131..a290687 100644 --- a/examples/basic/package.json +++ b/examples/basic/package.json @@ -7,11 +7,10 @@ "test": "tsc --noEmit" }, "dependencies": { - "cross-fetch": "^3.1.8", "node-fetch": "^3.3.2", "solid-js": "^1.7.11", "vike-solid": "^0.2.9", - "vike": "^0.4.148" + "vike": "^0.4.159" }, "devDependencies": { "typescript": "^5.1.6" diff --git a/examples/basic/pages/+Head.tsx b/examples/basic/pages/+Head.tsx index 5bd58fe..f3e39f6 100644 --- a/examples/basic/pages/+Head.tsx +++ b/examples/basic/pages/+Head.tsx @@ -5,6 +5,7 @@ import logoUrl from "../assets/logo.svg"; export function Head() { return ( <> + ); diff --git a/examples/basic/pages/+config.h.ts b/examples/basic/pages/+config.h.ts index 330e51a..f411494 100644 --- a/examples/basic/pages/+config.h.ts +++ b/examples/basic/pages/+config.h.ts @@ -5,7 +5,5 @@ import vikeSolid from "vike-solid"; export default { // title: "My Vike Solid App", - // <meta name="description"> - description: "Demo showcasing vike-solid", extends: vikeSolid, } satisfies Config; diff --git a/examples/basic/pages/star-wars/@id/+Page.tsx b/examples/basic/pages/star-wars/@id/+Page.tsx index 9efe771..9e4a0ef 100644 --- a/examples/basic/pages/star-wars/@id/+Page.tsx +++ b/examples/basic/pages/star-wars/@id/+Page.tsx @@ -2,7 +2,7 @@ import type { Data } from "./+data"; import { useData } from "vike-solid/useData"; export default function Page() { - const { movie } = useData<Data>(); + const movie = useData<Data>(); return ( <> <h1>{movie.title}</h1> diff --git a/examples/basic/pages/star-wars/@id/+data.ts b/examples/basic/pages/star-wars/@id/+data.ts index f1df58f..b06dda3 100644 --- a/examples/basic/pages/star-wars/@id/+data.ts +++ b/examples/basic/pages/star-wars/@id/+data.ts @@ -1,29 +1,24 @@ // https://vike.dev/data export { data }; -export type { Data }; +export type Data = Awaited<ReturnType<typeof data>>; -import fetch from "cross-fetch"; +import fetch from "node-fetch"; import type { PageContextServer } from "vike/types"; -import { filterMovieData } from "../filterMovieData"; import type { MovieDetails } from "../types"; -type Data = Awaited<ReturnType<typeof data>>; - const data = async (pageContext: PageContextServer) => { const response = await fetch( - `https://star-wars.brillout.com/api/films/${pageContext.routeParams?.id}.json` + `https://brillout.github.io/star-wars/api/films/${pageContext.routeParams?.id}.json` ); let movie = (await response.json()) as MovieDetails; - // We remove data we don't need because we pass `pageContext.movie` to // the client; we want to minimize what is sent over the network. - movie = filterMovieData(movie); - - const { title } = movie; - - return { - movie, - // The page's <title> - title, - }; + movie = minimize(movie); + return movie; }; + +function minimize(movie: MovieDetails): MovieDetails { + const { id, title, release_date, director, producer } = movie; + movie = { id, title, release_date, director, producer }; + return movie; +} diff --git a/examples/basic/pages/star-wars/@id/+title.ts b/examples/basic/pages/star-wars/@id/+title.ts new file mode 100644 index 0000000..aa4d829 --- /dev/null +++ b/examples/basic/pages/star-wars/@id/+title.ts @@ -0,0 +1,9 @@ +export { title }; + +import type { Data } from "./+data"; +import type { PageContext } from "vike/types"; + +function title(pageContext: PageContext<Data>) { + const movie = pageContext.data; + return movie.title; +} diff --git a/examples/basic/pages/star-wars/filterMovieData.ts b/examples/basic/pages/star-wars/filterMovieData.ts deleted file mode 100644 index d376801..0000000 --- a/examples/basic/pages/star-wars/filterMovieData.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { MovieDetails } from "./types"; - -export { filterMovieData }; - -function filterMovieData( - movie: MovieDetails & Record<string, unknown> -): MovieDetails { - const { id, title, release_date, director, producer } = movie; - movie = { id, title, release_date, director, producer }; - return movie; -} diff --git a/examples/basic/pages/star-wars/index/+Page.tsx b/examples/basic/pages/star-wars/index/+Page.tsx index 563ad92..f9a624e 100644 --- a/examples/basic/pages/star-wars/index/+Page.tsx +++ b/examples/basic/pages/star-wars/index/+Page.tsx @@ -3,7 +3,7 @@ import type { Data } from "./+data"; import { useData } from "vike-solid/useData"; export default function Page() { - const { movies } = useData<Data>(); + const movies = useData<Data>(); return ( <> <h1>Star Wars Movies</h1> @@ -19,7 +19,10 @@ export default function Page() { </ol> <p> Source:{" "} - <a href="https://star-wars.brillout.com">star-wars.brillout.com</a>. + <a href="https://brillout.github.io/star-wars"> + brillout.github.io/star-wars + </a> + . </p> </> ); diff --git a/examples/basic/pages/star-wars/index/+data.ts b/examples/basic/pages/star-wars/index/+data.ts index f2693a6..e060e66 100644 --- a/examples/basic/pages/star-wars/index/+data.ts +++ b/examples/basic/pages/star-wars/index/+data.ts @@ -1,80 +1,24 @@ // https://vike.dev/data export { data }; -export type { Data }; +export type Data = Awaited<ReturnType<typeof data>>; import fetch from "node-fetch"; -//import { filterMovieData } from '../filterMovieData' import type { Movie, MovieDetails } from "../types"; -// export { onBeforePrerenderStart } - -type Data = Awaited<ReturnType<typeof data>>; - const data = async () => { - const movies = await getStarWarsMovies(); - return { - // We remove data we don't need because we pass `pageContext.movies` to - // the client; we want to minimize what is sent over the network. - movies: filterMoviesData(movies), - // The page's <title> - title: getTitle(movies), - }; -}; - -async function getStarWarsMovies(): Promise<MovieDetails[]> { - 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), - })); + const response = await fetch( + "https://brillout.github.io/star-wars/api/films.json" + ); + const moviesData = (await response.json()) as MovieDetails[]; + // We remove data we don't need because the data is passed to the client; we should + // minimize what is sent over the network. + const movies = minimize(moviesData); return movies; -} +}; -function filterMoviesData(movies: MovieDetails[]): Movie[] { - return movies.map((movie: MovieDetails) => { +function minimize(movies: MovieDetails[]): Movie[] { + return movies.map((movie) => { const { title, release_date, id } = movie; return { title, release_date, id }; }); } - -/* -async function onBeforePrerenderStart() { - const movies = await getStarWarsMovies() - return [ - { - url: '/star-wars', - // We already provide `pageContext` here so that vike-solid - // will *not* have to call the `data()` hook defined - // above in this file. - pageContext: { - data: { - movies: filterMoviesData(movies), - title: getTitle(movies) - }, - } - }, - ...movies.map((movie) => { - const url = `/star-wars/${movie.id}` - return { - url, - // Note that we can also provide the `pageContext` of other pages. - // This means that vike-solid will not call any - // `data()` hook and the Star Wars API will be called - // only once (in this `onBeforePrerenderStart()` hook). - pageContext: { - data: { - movie: filterMovieData(movie), - title: movie.title - }, - } - } - }) - ] -} -*/ - -function getTitle(movies: Movie[] | MovieDetails[]): string { - const title = `${movies.length} Star Wars Movies`; - return title; -} diff --git a/examples/basic/pages/star-wars/index/+title.ts b/examples/basic/pages/star-wars/index/+title.ts new file mode 100644 index 0000000..4290615 --- /dev/null +++ b/examples/basic/pages/star-wars/index/+title.ts @@ -0,0 +1,9 @@ +export { title }; + +import type { Data } from "./+data"; +import type { PageContext } from "vike/types"; + +function title(pageContext: PageContext<Data>) { + const movies = pageContext.data; + return `${movies.length} Star Wars Movies`; +} diff --git a/examples/basic/pages/star-wars/types.ts b/examples/basic/pages/star-wars/types.ts index fd78915..ffccdf5 100644 --- a/examples/basic/pages/star-wars/types.ts +++ b/examples/basic/pages/star-wars/types.ts @@ -4,10 +4,7 @@ export type Movie = { release_date: string; }; -export type MovieDetails = { - id: string; - title: string; - release_date: string; +export type MovieDetails = Movie & { director: string; producer: string; }; diff --git a/examples/onBeforeRender/README.md b/examples/onBeforeRender/README.md deleted file mode 100644 index 7562bc2..0000000 --- a/examples/onBeforeRender/README.md +++ /dev/null @@ -1,18 +0,0 @@ -Basic example of using `vike-solid`, showcasing: - -- [layouts](https://vike.dev/layouts) -- rendering to `<head>` -- fetching data with [`onBeforeRender()`](https://vike.dev/onBeforeRender) hooks -- [configs](https://vike.dev/config) -- [error pages](https://vike.dev/error-page) - -```bash -git clone git@github.com:vikejs/vike-solid -cd vike-solid/examples/basic/ -pnpm install -pnpm run dev -``` - -> **NOTE:** for now `pnpm` is required because of the `workspace:` specifier in -> `package.json`. With this, the example makes use of the local `vike-solid` -> implementation instead of the downloading it from npm. diff --git a/examples/onBeforeRender/assets/logo.svg b/examples/onBeforeRender/assets/logo.svg deleted file mode 100644 index 94d3caa..0000000 --- a/examples/onBeforeRender/assets/logo.svg +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg width="175" height="175" fill="none" version="1.1" viewBox="0 0 175 175" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <metadata> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - <dc:title/> - </cc:Work> - </rdf:RDF> - </metadata> - <defs> - <linearGradient id="linearGradient880" x1="108.64" x2="115.51" y1="88.726" y2="136.2" gradientTransform="matrix(1.0498 0 0 1.0498 -2.9171 -2.9658)" gradientUnits="userSpaceOnUse"> - <stop stop-color="#ffea83" offset="0"/> - <stop stop-color="#FFDD35" offset=".083333"/> - <stop stop-color="#FFA800" offset="1"/> - </linearGradient> - <linearGradient id="paint2_linear" x1="48.975" x2="61.299" y1="3.9232" y2="158.04" gradientTransform="translate(-2.832e-5)" gradientUnits="userSpaceOnUse"> - <stop stop-color="#FFEA83" offset="0"/> - <stop stop-color="#FFDD35" offset=".083333"/> - <stop stop-color="#FFA800" offset="1"/> - </linearGradient> - <linearGradient id="paint0_linear-6" x1="-1.4492" x2="116.62" y1="-5.8123" y2="137.08" gradientTransform="translate(-2.832e-5)" gradientUnits="userSpaceOnUse"> - <stop stop-color="#41D1FF" offset="0"/> - <stop stop-color="#BD34FE" offset="1"/> - </linearGradient> - </defs> - <circle cx="87.5" cy="87.5" r="87.5" fill="#c4c4c4"/> - <circle cx="87.5" cy="87.5" r="87.5" fill="url(#paint0_linear-6)"/> - <g transform="translate(632.92 54.355)" fill="#d38787" stroke-width="1.0614"> - <path d="m-549.75 68.457c-5.7533-3.1217-6.1166-5.2295-6.1166-35.489 0-30.458 0.35464-32.448 6.3339-35.54 3.9943-2.0655 24.279-2.2805 26.735-0.28333 0.89718 0.72974 6.7203 6.6637 12.94 13.187l11.309 11.86v19.575c0 18.473-0.12956 19.74-2.3011 22.5-4.0223 5.1136-7.558 5.8565-27.65 5.8099-14.15-0.03287-19.008-0.40294-21.25-1.6191zm42.473-6.3594c2.27-1.59 2.359-2.2909 2.359-18.575v-16.923h-6.9521c-12.443 0-16.4-4.0845-16.4-16.93v-7.4828h-8.9464c-6.7178 0-9.3619 0.41549-10.614 1.668-2.5031 2.5031-2.5031 55.724 0 58.228 2.4502 2.4502 37.058 2.4636 40.553 0.01609zm-1.8867-42.165c0-0.16422-2.8659-3.1346-6.3686-6.6008l-6.3686-6.3022v4.9328c0 6.3185 1.8955 8.2687 8.0366 8.2687 2.5854 0 4.7007-0.13434 4.7007-0.29859zm-57.57 44.279c-5.6185-3.0486-6.1166-5.593-6.1166-31.243 0-18.891 0.31331-24.063 1.6101-26.571 1.809-3.4981 6.5048-6.3339 10.489-6.3339 2.4847 0 2.5814 0.19984 1.541 3.1843-0.61054 1.7514-1.7457 3.1843-2.5226 3.1843-0.77686 0-2.1631 0.75059-3.0805 1.668-2.4923 2.4923-2.4923 47.244 0 49.736 0.91739 0.9174 2.3036 1.668 3.0805 1.668 0.77688 0 1.912 1.4329 2.5226 3.1843 1.0562 3.0298 0.97108 3.1822-1.7537 3.1418-1.575-0.02331-4.1713-0.75194-5.7694-1.6191zm-16.983-4.2458c-5.4392-2.9512-6.1166-5.9415-6.1166-26.997 0-15.096 0.345-19.878 1.6101-22.325 1.7476-3.3796 6.4758-6.3339 10.137-6.3339 1.8666 0 2.1789 0.44955 1.6594 2.3882-0.35184 1.3135-0.64655 2.7465-0.65453 3.1843-8e-3 0.43784-0.69682 0.79608-1.5308 0.79608-0.83399 0-2.2669 0.75059-3.1843 1.668-2.4767 2.4767-2.4767 38.768 0 41.244 0.91741 0.91739 2.2946 1.668 3.0605 1.668 1.196 0 2.6402 2.995 2.6871 5.5726 0.0241 1.3294-4.5804 0.80962-7.6676-0.8655z" style="mix-blend-mode:lighten"/> - <path d="m-552.2 68.911c-5.7533-3.1217-6.1166-5.2295-6.1166-35.489 0-30.458 0.35463-32.448 6.3339-35.54 3.9943-2.0655 24.279-2.2805 26.735-0.28333 0.89718 0.72974 6.7203 6.6637 12.94 13.187l11.309 11.86v19.575c0 18.473-0.12957 19.74-2.3011 22.5-4.0223 5.1136-7.558 5.8565-27.65 5.8099-14.15-0.03287-19.008-0.40294-21.25-1.6191zm42.473-6.3594c2.27-1.59 2.359-2.2909 2.359-18.575v-16.923h-6.952c-12.443 0-16.4-4.0845-16.4-16.93v-7.4828h-8.9464c-6.7179 0-9.3619 0.41549-10.614 1.668-2.5031 2.5031-2.5031 55.724 0 58.228 2.4502 2.4502 37.058 2.4636 40.553 0.01609zm-1.8867-42.165c0-0.16422-2.8659-3.1346-6.3686-6.6008l-6.3686-6.3022v4.9328c0 6.3185 1.8955 8.2688 8.0366 8.2688 2.5854 0 4.7007-0.13434 4.7007-0.29859zm-57.57 44.279c-5.6185-3.0486-6.1166-5.593-6.1166-31.243 0-18.891 0.31331-24.063 1.6101-26.571 1.809-3.4981 6.5048-6.3339 10.489-6.3339 2.4847 0 2.5814 0.19984 1.541 3.1843-0.61054 1.7514-1.7457 3.1843-2.5226 3.1843-0.77687 0-2.1631 0.75059-3.0805 1.668-2.4923 2.4923-2.4923 47.244 0 49.736 0.91741 0.91739 2.3036 1.668 3.0805 1.668 0.77686 0 1.912 1.4329 2.5226 3.1843 1.0562 3.0298 0.97107 3.1822-1.7537 3.1418-1.575-0.02331-4.1713-0.75194-5.7694-1.6191zm-16.983-4.2458c-5.4392-2.9512-6.1166-5.9415-6.1166-26.997 0-15.096 0.34502-19.878 1.6101-22.325 1.7476-3.3796 6.4758-6.3339 10.137-6.3339 1.8666 0 2.1789 0.44955 1.6594 2.3882-0.35182 1.3135-0.64653 2.7465-0.65452 3.1843-8e-3 0.43784-0.69683 0.79608-1.5308 0.79608-0.83397 0-2.2669 0.75059-3.1843 1.668-2.4767 2.4767-2.4767 38.768 0 41.245 0.9174 0.91739 2.2946 1.668 3.0605 1.668 1.196 0 2.6402 2.995 2.6871 5.5726 0.0241 1.3294-4.5804 0.80962-7.6676-0.8655z" fill-opacity=".47466" style="mix-blend-mode:lighten"/> - </g> - <path d="m128.48 88.913-24.027 4.6784c-0.39475 0.07685-0.68766 0.40944-0.71076 0.80849l-1.4782 24.805c-0.0347 0.58371 0.50497 1.0372 1.0792 0.90602l6.6886-1.5338c0.62676-0.14383 1.1916 0.40419 1.0635 1.0299l-1.9874 9.6702c-0.13438 0.65091 0.48084 1.2073 1.1202 1.0142l4.1322-1.2472c0.64041-0.19317 1.2556 0.36535 1.1202 1.0162l-3.158 15.191c-0.19842 0.95011 1.074 1.4677 1.6042 0.653l0.35485-0.54382 19.578-38.827c0.32755-0.64985-0.23727-1.391-0.95641-1.2535l-6.8849 1.3207c-0.6467 0.12389-1.1979-0.47453-1.0152-1.1034l4.4944-15.482c0.18266-0.63012-0.36955-1.2295-1.0173-1.1034z" fill="url(#linearGradient880)" stroke-width="1.0498"/> - <rect x="3" y="3" width="169" height="169" rx="84.5" stroke="url(#paint2_linear)" stroke-width="6" style="mix-blend-mode:soft-light"/> -</svg> diff --git a/examples/onBeforeRender/components/Link.tsx b/examples/onBeforeRender/components/Link.tsx deleted file mode 100644 index 361010d..0000000 --- a/examples/onBeforeRender/components/Link.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createMemo } from "solid-js"; -import { usePageContext } from "vike-solid/usePageContext"; - -export function Link(props: { href: string; children: string }) { - const pageContext = usePageContext(); - const isActive = createMemo(() => - props.href === "/" - ? pageContext.urlPathname === props.href - : pageContext.urlPathname.startsWith(props.href) - ); - return ( - <a href={props.href} class={isActive() ? "is-active" : undefined}> - {props.children} - </a> - ); -} diff --git a/examples/onBeforeRender/layouts/LayoutDefault.tsx b/examples/onBeforeRender/layouts/LayoutDefault.tsx deleted file mode 100644 index 4c947a2..0000000 --- a/examples/onBeforeRender/layouts/LayoutDefault.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import "./style.css"; -import logoUrl from "../assets/logo.svg"; -import { Link } from "../components/Link"; -import type { JSX } from "solid-js"; - -export default function LayoutDefault(props: { children?: JSX.Element }) { - return ( - <div - style={{ - display: "flex", - "max-width": "900px", - margin: "auto", - }} - > - <Sidebar> - <Logo /> - <Link href="/">Welcome</Link> - <Link href="/star-wars">Data Fetching</Link> - </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> - ); -} diff --git a/examples/onBeforeRender/layouts/style.css b/examples/onBeforeRender/layouts/style.css deleted file mode 100644 index 7afa4ca..0000000 --- a/examples/onBeforeRender/layouts/style.css +++ /dev/null @@ -1,29 +0,0 @@ -/* 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; -} diff --git a/examples/onBeforeRender/package.json b/examples/onBeforeRender/package.json deleted file mode 100644 index 6528131..0000000 --- a/examples/onBeforeRender/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "private": true, - "scripts": { - "dev": "vike-solid dev", - "build": "vike-solid build", - "preview": "vike-solid preview", - "test": "tsc --noEmit" - }, - "dependencies": { - "cross-fetch": "^3.1.8", - "node-fetch": "^3.3.2", - "solid-js": "^1.7.11", - "vike-solid": "^0.2.9", - "vike": "^0.4.148" - }, - "devDependencies": { - "typescript": "^5.1.6" - }, - "type": "module" -} diff --git a/examples/onBeforeRender/pages/+config.h.ts b/examples/onBeforeRender/pages/+config.h.ts deleted file mode 100644 index a316842..0000000 --- a/examples/onBeforeRender/pages/+config.h.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Config } from "vike/types"; -import vikeSolid from "vike-solid"; -import Layout from "../layouts/LayoutDefault"; -import Head from "./Head"; - -// Default config (can be overridden by pages) -export default { - Layout, - Head, - // <title> - title: "My Vike Solid App", - // <meta name="description"> - description: "Demo showcasing vike-solid", - extends: vikeSolid, -} satisfies Config; diff --git a/examples/onBeforeRender/pages/Head.tsx b/examples/onBeforeRender/pages/Head.tsx deleted file mode 100644 index f56c9d9..0000000 --- a/examples/onBeforeRender/pages/Head.tsx +++ /dev/null @@ -1,11 +0,0 @@ -// Default <head> (can be overridden by pages) - -import logoUrl from "../assets/logo.svg"; - -export default function Head() { - return ( - <> - <link rel="icon" href={logoUrl} /> - </> - ); -} diff --git a/examples/onBeforeRender/pages/_error/+Page.tsx b/examples/onBeforeRender/pages/_error/+Page.tsx deleted file mode 100644 index 8b384c0..0000000 --- a/examples/onBeforeRender/pages/_error/+Page.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export default function Page(props: { is404: boolean; errorInfo?: string }) { - if (props.is404) { - return ( - <> - <h1>404 Page Not Found</h1> - <p>This page could not be found.</p> - <p>{props.errorInfo}</p> - </> - ); - } else { - return ( - <> - <h1>500 Internal Server Error</h1> - <p>Something went wrong.</p> - </> - ); - } -} diff --git a/examples/onBeforeRender/pages/index/+Page.tsx b/examples/onBeforeRender/pages/index/+Page.tsx deleted file mode 100644 index 3df5011..0000000 --- a/examples/onBeforeRender/pages/index/+Page.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { ClientOnly } from "vike-solid/ClientOnly"; - -export default function Page() { - return ( - <> - <h1>My vike-solid app</h1> - This page is: - <ul> - <li>Rendered to HTML.</li> - - <ClientOnly load={() => import("./Counter")} fallback={<li>Waiting for client-side only component to load (quick)</li>}> - {(Counter) => <li> - Interactive 1. <Counter /> - </li>} - </ClientOnly> - - <ClientOnly load={async () => { - // Wasting time to show the fallback - await new Promise(resolve => setTimeout(resolve, 2000)); - - return import("./Counter"); - }} fallback={<li>Waiting for client-side only component to load (slow)</li>}> - {(Counter) => <li> - Interactive 2. <Counter /> - </li>} - </ClientOnly> - </ul> - </> - ); -} diff --git a/examples/onBeforeRender/pages/index/Counter.tsx b/examples/onBeforeRender/pages/index/Counter.tsx deleted file mode 100644 index 742ab48..0000000 --- a/examples/onBeforeRender/pages/index/Counter.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { createSignal } from "solid-js"; - -export default function Counter() { - const [count, setCount] = createSignal(0); - - return ( - <button onClick={() => setCount((count) => count + 1)}> - Counter {count()} - </button> - ); -} diff --git a/examples/onBeforeRender/pages/star-wars/@id/+Page.tsx b/examples/onBeforeRender/pages/star-wars/@id/+Page.tsx deleted file mode 100644 index 017de2a..0000000 --- a/examples/onBeforeRender/pages/star-wars/@id/+Page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import type { MovieDetails } from "../types"; - -export default function Page(props: { movie: MovieDetails }) { - return ( - <> - <h1>{props.movie.title}</h1> - Release Date: {props.movie.release_date} - <br /> - Director: {props.movie.director} - <br /> - Producer: {props.movie.producer} - </> - ); -} diff --git a/examples/onBeforeRender/pages/star-wars/@id/+onBeforeRender.ts b/examples/onBeforeRender/pages/star-wars/@id/+onBeforeRender.ts deleted file mode 100644 index 9f29415..0000000 --- a/examples/onBeforeRender/pages/star-wars/@id/+onBeforeRender.ts +++ /dev/null @@ -1,32 +0,0 @@ -// https://vike.dev/onBeforeRender -export { onBeforeRender }; - -import fetch from "cross-fetch"; -import type { OnBeforeRenderAsync } from "vike/types"; -import { filterMovieData } from "../filterMovieData"; -import type { MovieDetails } from "../types"; - -const onBeforeRender: OnBeforeRenderAsync = async ( - pageContext -): ReturnType<OnBeforeRenderAsync> => { - const response = await fetch( - `https://star-wars.brillout.com/api/films/${pageContext.routeParams?.id}.json` - ); - let movie = (await response.json()) as MovieDetails; - - // We remove data we don't need because we pass `pageContext.movie` to - // the client; we want to minimize what is sent over the network. - movie = filterMovieData(movie); - - const { title } = movie; - - return { - pageContext: { - pageProps: { - movie, - }, - // The page's <title> - title, - }, - }; -}; diff --git a/examples/onBeforeRender/pages/star-wars/filterMovieData.ts b/examples/onBeforeRender/pages/star-wars/filterMovieData.ts deleted file mode 100644 index d376801..0000000 --- a/examples/onBeforeRender/pages/star-wars/filterMovieData.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { MovieDetails } from "./types"; - -export { filterMovieData }; - -function filterMovieData( - movie: MovieDetails & Record<string, unknown> -): MovieDetails { - const { id, title, release_date, director, producer } = movie; - movie = { id, title, release_date, director, producer }; - return movie; -} diff --git a/examples/onBeforeRender/pages/star-wars/index/+Page.tsx b/examples/onBeforeRender/pages/star-wars/index/+Page.tsx deleted file mode 100644 index 0d36d2f..0000000 --- a/examples/onBeforeRender/pages/star-wars/index/+Page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { For } from "solid-js"; -import type { Movie } from "../types"; - -export default function Page(props: { movies: Movie[] }) { - return ( - <> - <h1>Star Wars Movies</h1> - <ol> - <For each={props.movies}> - {(movie, i) => ( - <li> - <a href={`/star-wars/${movie.id}`}>{movie.title}</a> ( - {movie.release_date}) - </li> - )} - </For> - </ol> - <p> - Source:{" "} - <a href="https://star-wars.brillout.com">star-wars.brillout.com</a>. - </p> - </> - ); -} diff --git a/examples/onBeforeRender/pages/star-wars/index/+onBeforeRender.ts b/examples/onBeforeRender/pages/star-wars/index/+onBeforeRender.ts deleted file mode 100644 index 791594c..0000000 --- a/examples/onBeforeRender/pages/star-wars/index/+onBeforeRender.ts +++ /dev/null @@ -1,84 +0,0 @@ -// https://vike.dev/onBeforeRender -export { onBeforeRender }; - -import fetch from "node-fetch"; -//import { filterMovieData } from '../filterMovieData' -import type { Movie, MovieDetails } from "../types"; -import type { OnBeforeRenderAsync } from "vike/types"; - -// export { prerender } - -const onBeforeRender: OnBeforeRenderAsync = async ( - pageContext -): ReturnType<OnBeforeRenderAsync> => { - const movies = await getStarWarsMovies(); - return { - pageContext: { - pageProps: { - // We remove data we don't need because we pass `pageContext.movies` to - // the client; we want to minimize what is sent over the network. - movies: filterMoviesData(movies), - }, - // The page's <title> - title: getTitle(movies), - }, - }; -} - -async function getStarWarsMovies(): Promise<MovieDetails[]> { - 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; -} - -function filterMoviesData(movies: MovieDetails[]): Movie[] { - return movies.map((movie: MovieDetails) => { - const { title, release_date, id } = movie; - return { title, release_date, id }; - }); -} - -/* -async function prerender() { - const movies = await getStarWarsMovies() - return [ - { - url: '/star-wars', - // We already provide `pageContext` here so that vike-solid - // will *not* have to call the `onBeforeRender()` hook defined - // above in this file. - pageContext: { - pageProps: { - movies: filterMoviesData(movies) - }, - title: getTitle(movies) - } - }, - ...movies.map((movie) => { - const url = `/star-wars/${movie.id}` - return { - url, - // Note that we can also provide the `pageContext` of other pages. - // This means that vike-solid will not call any - // `onBeforeRender()` hook and the Star Wars API will be called - // only once (in this `prerender()` hook). - pageContext: { - pageProps: { - movie: filterMovieData(movie) - }, - title: movie.title - } - } - }) - ] -} -*/ - -function getTitle(movies: Movie[] | MovieDetails[]): string { - const title = `${movies.length} Star Wars Movies`; - return title; -} diff --git a/examples/onBeforeRender/pages/star-wars/types.ts b/examples/onBeforeRender/pages/star-wars/types.ts deleted file mode 100644 index fd78915..0000000 --- a/examples/onBeforeRender/pages/star-wars/types.ts +++ /dev/null @@ -1,13 +0,0 @@ -export type Movie = { - id: string; - title: string; - release_date: string; -}; - -export type MovieDetails = { - id: string; - title: string; - release_date: string; - director: string; - producer: string; -}; diff --git a/examples/onBeforeRender/tsconfig.json b/examples/onBeforeRender/tsconfig.json deleted file mode 100644 index c70b969..0000000 --- a/examples/onBeforeRender/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "module": "ES2020", - "moduleResolution": "node", - "target": "ES2020", - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "types": ["vike-solid/client"], - "jsx": "preserve", - "jsxImportSource": "solid-js", - "skipLibCheck": true, - "esModuleInterop": true - } -} diff --git a/examples/ssr-spa/README.md b/examples/ssr-spa/README.md index ae99435..5ca67b3 100644 --- a/examples/ssr-spa/README.md +++ b/examples/ssr-spa/README.md @@ -7,7 +7,3 @@ cd vike-solid/examples/ssr-spa/ npm install npm run dev ``` - -> **NOTE:** for now `pnpm` is required because of the `workspace:` specifier in -> `package.json`. With this, the example makes use of the local `vike-solid` -> implementation instead of the downloading it from npm. diff --git a/examples/ssr-spa/package.json b/examples/ssr-spa/package.json index 986be48..20d73b9 100644 --- a/examples/ssr-spa/package.json +++ b/examples/ssr-spa/package.json @@ -9,7 +9,7 @@ "dependencies": { "solid-js": "^1.7.11", "vike-solid": "^0.2.9", - "vike": "^0.4.148" + "vike": "^0.4.159" }, "devDependencies": { "typescript": "^5.1.6" diff --git a/examples/ssr-spa/pages/+config.h.ts b/examples/ssr-spa/pages/+config.h.ts index 64687dc..92dfd6f 100644 --- a/examples/ssr-spa/pages/+config.h.ts +++ b/examples/ssr-spa/pages/+config.h.ts @@ -9,8 +9,6 @@ export default { Head, // <title> title: "My Vike Solid App", - // <meta name="description"> - description: "Demo showcasing vike-solid", - ssr: true, // can be removed, this is the default anyway + ssr: true, // can be removed since `true` is the default extends: vikeSolid, } satisfies Config; diff --git a/examples/ssr-spa/pages/Head.tsx b/examples/ssr-spa/pages/Head.tsx index f56c9d9..02ecd1c 100644 --- a/examples/ssr-spa/pages/Head.tsx +++ b/examples/ssr-spa/pages/Head.tsx @@ -5,6 +5,7 @@ import logoUrl from "../assets/logo.svg"; export default function Head() { return ( <> + <meta name="description" content="Demo showcasing Vike + Solid" /> <link rel="icon" href={logoUrl} /> </> ); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1258101..054b76e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,9 +13,6 @@ importers: examples/basic: dependencies: - cross-fetch: - specifier: ^3.1.8 - version: 3.1.8 node-fetch: specifier: ^3.3.2 version: 3.3.2 @@ -23,30 +20,8 @@ importers: specifier: ^1.7.11 version: 1.8.7 vike: - specifier: ^0.4.148 - version: 0.4.152(vite@5.0.11) - vike-solid: - specifier: link:../../vike-solid - version: link:../../vike-solid - devDependencies: - typescript: - specifier: ^5.1.6 - version: 5.3.3 - - examples/onBeforeRender: - dependencies: - cross-fetch: - specifier: ^3.1.8 - version: 3.1.8 - node-fetch: - specifier: ^3.3.2 - version: 3.3.2 - solid-js: - specifier: ^1.7.11 - version: 1.8.7 - vike: - specifier: ^0.4.148 - version: 0.4.153(vite@5.0.11) + specifier: ^0.4.159 + version: 0.4.160(vite@5.0.11) vike-solid: specifier: link:../../vike-solid version: link:../../vike-solid @@ -61,8 +36,8 @@ importers: specifier: ^1.7.11 version: 1.8.7 vike: - specifier: ^0.4.148 - version: 0.4.152(vite@5.0.11) + specifier: ^0.4.159 + version: 0.4.160(vite@5.0.11) vike-solid: specifier: link:../../vike-solid version: link:../../vike-solid @@ -117,8 +92,8 @@ importers: specifier: ^5.3.3 version: 5.3.3 vike: - specifier: ^0.4.156 - version: 0.4.156(vite@5.0.11) + specifier: ^0.4.159 + version: 0.4.160(vite@5.0.11) vite: specifier: ^5.0.11 version: 5.0.11(@types/node@18.17.4) @@ -1329,17 +1304,10 @@ packages: /@brillout/require-shim@0.1.2: resolution: {integrity: sha512-3I4LRHnVZXoSAsEoni5mosq9l6eiJED58d9V954W4CIZ88AUfYBanWGBGbJG3NztaRTpFHEA6wB3Hn93BmmJdg==} - /@brillout/vite-plugin-import-build@0.3.2: - resolution: {integrity: sha512-QuVO20cZ1Qkzir9llCKpzonS29oELGQUyxNyqWh95pAnLB6HXRcix+yDlhdHbS6WyY65ar6B2h0bixKKyGZJPg==} - dependencies: - '@brillout/import': 0.2.3 - dev: false - /@brillout/vite-plugin-server-entry@0.4.3: resolution: {integrity: sha512-JDWFZOsSJfDo9511r7OJDeNON7x5mwIGNZCi1DQWaVuYK2cs9J/eD3Jwypg4M1ex9iAb/WvI+aSAEfsVGmNeMQ==} dependencies: '@brillout/import': 0.2.3 - dev: true /@esbuild/android-arm64@0.19.7: resolution: {integrity: sha512-YEDcw5IT7hW3sFKZBkCAQaOCJQLONVcD4bOyTXMZz5fr66pTHnAet46XAtbXAkJRfIn2YVhdC6R9g4xa27jQ1w==} @@ -1968,14 +1936,6 @@ packages: browserslist: 4.22.2 dev: true - /cross-fetch@3.1.8: - resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} - dependencies: - node-fetch: 2.6.12 - transitivePeerDependencies: - - encoding - dev: false - /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2369,18 +2329,6 @@ packages: resolution: {integrity: sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==} dev: true - /node-fetch@2.6.12: - resolution: {integrity: sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: false - /node-fetch@3.3.2: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2697,10 +2645,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: false - /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true @@ -2756,60 +2700,8 @@ packages: /validate-html-nesting@1.2.2: resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==} - /vike@0.4.152(vite@5.0.11): - resolution: {integrity: sha512-KZ9hOp5eBt156klkK4pAjzkIS9eUIaJ+zy6Le8PUc7Jxqti6CIMFJZOX2RB2grn3u3PXbQdLZuEZWXc+tEaUaA==} - engines: {node: '>=16.0.0'} - hasBin: true - peerDependencies: - react-streaming: '>=0.3.5' - vite: '>=3.1.0' - peerDependenciesMeta: - react-streaming: - optional: true - dependencies: - '@brillout/import': 0.2.3 - '@brillout/json-serializer': 0.5.8 - '@brillout/picocolors': 1.0.10 - '@brillout/require-shim': 0.1.2 - '@brillout/vite-plugin-import-build': 0.3.2 - acorn: 8.10.0 - cac: 6.7.14 - es-module-lexer: 1.3.1 - esbuild: 0.19.7 - fast-glob: 3.3.2 - sirv: 2.0.3 - source-map-support: 0.5.21 - vite: 5.0.11(@types/node@18.17.4) - dev: false - - /vike@0.4.153(vite@5.0.11): - resolution: {integrity: sha512-V7QGZJScVNw6zJxzH1LiXvCP1HlIl06BfuW3DrAD4AUfP+z1teoOEBn11E7jElF5FR6+i8cDmWAZstZdJag/vA==} - engines: {node: '>=16.0.0'} - hasBin: true - peerDependencies: - react-streaming: '>=0.3.5' - vite: '>=3.1.0' - peerDependenciesMeta: - react-streaming: - optional: true - dependencies: - '@brillout/import': 0.2.3 - '@brillout/json-serializer': 0.5.8 - '@brillout/picocolors': 1.0.10 - '@brillout/require-shim': 0.1.2 - '@brillout/vite-plugin-import-build': 0.3.2 - acorn: 8.10.0 - cac: 6.7.14 - es-module-lexer: 1.3.1 - esbuild: 0.19.7 - fast-glob: 3.3.2 - sirv: 2.0.3 - source-map-support: 0.5.21 - vite: 5.0.11(@types/node@18.17.4) - dev: false - - /vike@0.4.156(vite@5.0.11): - resolution: {integrity: sha512-CaeG+clu+oLDKSv4B+6aOYoWNUb/URF6dK3/AeC9NJD0XvsfW8at1yQO5hA3M1SVWpe7c/tUGw1uYVgceT4JMw==} + /vike@0.4.160(vite@5.0.11): + resolution: {integrity: sha512-sC+MR1gkY/wgPSbVOlc05PF429CSja3Cc5Ps7+vgccsIH5fhRTm8gS6TwmEK130stK0xauiS2hK9T7BvFTv5rA==} engines: {node: '>=16.0.0'} hasBin: true peerDependencies: @@ -2832,7 +2724,6 @@ packages: sirv: 2.0.3 source-map-support: 0.5.21 vite: 5.0.11(@types/node@18.17.4) - dev: true /vite-plugin-solid@2.8.0(solid-js@1.8.11)(vite@5.0.11): resolution: {integrity: sha512-n5FAm7ZmTl94VWUoiJCgG7bouF2NlC9CA1wY/qbVnkFbYDWk++bFWyNoU48aLJ+lMtzNeYzJypJXOHzFKxL9xA==} @@ -2904,17 +2795,6 @@ packages: engines: {node: '>= 8'} dev: false - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: false - - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - dev: false - /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} diff --git a/vike-solid/README.md b/vike-solid/README.md index 31df4dd..3bd922d 100644 --- a/vike-solid/README.md +++ b/vike-solid/README.md @@ -5,7 +5,4 @@ SolidJS integration for [Vike](https://github.com/vikejs/vike). -> [!NOTE] -> For integrations with React and Vue, see the other [`vike-*` packages](https://vike.dev/vike-packages). - See [examples/](https://github.com/vikejs/vike-solid/tree/main/examples). diff --git a/vike-solid/package.json b/vike-solid/package.json index a07384c..824c250 100644 --- a/vike-solid/package.json +++ b/vike-solid/package.json @@ -13,7 +13,7 @@ "peerDependencies": { "solid-js": "^1.8.7", "vite": "^4.4 || ^5.0.2", - "vike": "^0.4.152" + "vike": "^0.4.159" }, "devDependencies": { "@babel/core": "^7.23.7", @@ -30,7 +30,7 @@ "tslib": "^2.6.2", "typescript": "^5.3.3", "vite": "^5.0.11", - "vike": "^0.4.156" + "vike": "^0.4.159" }, "exports": { ".": "./dist/+config.js", diff --git a/vike-solid/renderer/+config.ts b/vike-solid/renderer/+config.ts index 21a82c2..88d4e6b 100644 --- a/vike-solid/renderer/+config.ts +++ b/vike-solid/renderer/+config.ts @@ -3,7 +3,7 @@ import type { Component } from "./types.js"; // Depending on the value of `config.meta.ssr`, set other config options' `env` // accordingly. -// See https://vike.dev/meta#modify-existing-configurations +// See https://vike.dev/meta#:~:text=Modifying%20the%20environment%20of%20existing%20hooks const toggleSsrRelatedConfig: ConfigEffect = ({ configDefinedAt, configValue, @@ -27,21 +27,14 @@ const toggleSsrRelatedConfig: ConfigEffect = ({ }; export default { + // https://vike.dev/onRenderHtml onRenderHtml: "import:vike-solid/renderer/onRenderHtml:onRenderHtml", + // https://vike.dev/onRenderClient onRenderClient: "import:vike-solid/renderer/onRenderClient:onRenderClient", - - // TODO/next-major-release: remove pageProps (i.e. tell users to use data() instead of onBeforeRender() to fetch data) - // TODO/next-major-release: remove support for setting title over onBeforeRender() - // A page can define an onBeforeRender() hook to be run on the server, which - // can fetch data and return it as additional page context. Typically it will - // return the page's root Solid component's props and additional data that can - // be used by the renderers. - // It is a cumulative config option, so a web app using vike-solid can extend - // this list. - passToClient: ["pageProps", "title", "lang"], - + // https://vike.dev/clientRouting clientRouting: true, hydrationCanBeAborted: true, + // https://vike.dev/meta meta: { Head: { env: { server: true }, @@ -52,11 +45,8 @@ export default { title: { env: { server: true, client: true }, }, - description: { - env: { server: true }, - }, favicon: { - env: { server: true }, + env: { server: true, client: true }, }, lang: { env: { server: true, client: true }, @@ -72,6 +62,7 @@ export default { } satisfies Config; // We purposely define the ConfigVikeSolid interface in this file: that way we ensure it's always applied whenever the user `import vikeSolid from 'vike-solid'` +// https://vike.dev/pageContext#typescript declare global { namespace VikePackages { interface ConfigVikeSolid { @@ -82,7 +73,6 @@ declare global { /** A component, usually common to several pages, that wraps the root component `Page` */ Layout?: Component; title?: string | ((pageContext: PageContext) => string); - description?: string; favicon?: string; /** * @default 'en' diff --git a/vike-solid/renderer/+onRenderClient.tsx b/vike-solid/renderer/+onRenderClient.tsx index 2b13744..bbb0d8b 100644 --- a/vike-solid/renderer/+onRenderClient.tsx +++ b/vike-solid/renderer/+onRenderClient.tsx @@ -2,11 +2,10 @@ export { onRenderClient }; import { hydrate, render } from "solid-js/web"; -import { getTitle } from "./getTitle"; +import { getHeadSetting } from "./getHeadSetting"; import type { OnRenderClientAsync, PageContextClient } from "vike/types"; import { getPageElement } from "./getPageElement"; import { createStore, reconcile } from "solid-js/store"; -import { getLang } from "./getLang"; const [pageContextStore, setPageContext] = createStore<PageContextClient>( {} as PageContextClient @@ -34,18 +33,37 @@ const onRenderClient: OnRenderClientAsync = async ( } rendered = true; } else { - // Client routing - // See https://vike.dev/server-routing-vs-client-routing + // Client-side navigation setPageContext(reconcile(pageContext)); - // Get the page's `title` config value, which may be different from the - // previous page. It can even be null, in which case we should unset the - // document title. - const title = getTitle(pageContext); - const lang = getLang(pageContext) || 'en' + const title = getHeadSetting("title", pageContext) || ""; + const lang = getHeadSetting("lang", pageContext) || "en"; + const favicon = getHeadSetting("favicon", pageContext); - document.title = title || ""; - document.documentElement.lang = lang + // We skip if the value is undefined because we shouldn't remove values set in HTML (by the Head setting). + // - This also means that previous values will leak: upon client-side navigation, the title set by the previous + // page won't be removed if the next page doesn't override it. But that's okay because usually pages always have + // a favicon and title, which means that previous values are always overridden. Also, as a workaround, the user + // can set the value to `null` to ensure that previous values are overridden. + if (title !== undefined) document.title = title; + if (lang !== undefined) document.documentElement.lang = lang; + if (favicon !== undefined) setFavicon(favicon); } }; + +// https://stackoverflow.com/questions/260857/changing-website-favicon-dynamically/260876#260876 +function setFavicon(faviconUrl: string | null) { + let link: HTMLLinkElement | null = + document.querySelector("link[rel~='icon']"); + if (!faviconUrl) { + if (link) document.head.removeChild(link); + return; + } + if (!link) { + link = document.createElement("link"); + link.rel = "icon"; + document.head.appendChild(link); + } + link.href = faviconUrl; +} diff --git a/vike-solid/renderer/+onRenderHtml.tsx b/vike-solid/renderer/+onRenderHtml.tsx index 8b80720..5ba5adb 100644 --- a/vike-solid/renderer/+onRenderHtml.tsx +++ b/vike-solid/renderer/+onRenderHtml.tsx @@ -6,25 +6,30 @@ import { renderToStream, renderToString, } from "solid-js/web"; -import { dangerouslySkipEscape, escapeInject, stampPipe, version } from "vike/server"; -import { getTitle } from "./getTitle"; +import { + dangerouslySkipEscape, + escapeInject, + stampPipe, + version, +} from "vike/server"; +import { getHeadSetting } from "./getHeadSetting"; import { getPageElement } from "./getPageElement"; import type { OnRenderHtmlAsync } from "vike/types"; import { PageContextProvider } from "./PageContextProvider"; -import { getLang } from "./getLang"; -checkVikeVersion() +checkVikeVersion(); const onRenderHtml: OnRenderHtmlAsync = async ( pageContext ): ReturnType<OnRenderHtmlAsync> => { - const { stream, favicon, description } = pageContext.config + const title = getHeadSetting("title", pageContext); + const favicon = getHeadSetting("favicon", pageContext); + const lang = getHeadSetting("lang", pageContext) || "en"; - const title = getTitle(pageContext); const titleTag = !title ? "" : escapeInject`<title>${title}`; - - const faviconTag = !favicon ? '' : escapeInject`` - const descriptionTag = !description ? '' : escapeInject`` + const faviconTag = !favicon + ? "" + : escapeInject``; const Head = pageContext.config.Head || (() => <>); const headHtml = renderToString(() => ( @@ -33,28 +38,27 @@ const onRenderHtml: OnRenderHtmlAsync = async ( )); - type TPipe = (writable: { write: (v: string) => void; }) => void + type TPipe = (writable: { write: (v: string) => void }) => void; - let pageView: string | ReturnType | TPipe = '' + let pageView: string | ReturnType | TPipe = ""; if (!!pageContext.Page) { - if (!stream) { - pageView = dangerouslySkipEscape(renderToString(() => getPageElement(pageContext))) + if (!pageContext.config.stream) { + pageView = dangerouslySkipEscape( + renderToString(() => getPageElement(pageContext)) + ); } else { - pageView = renderToStream(() => getPageElement(pageContext)).pipe + pageView = renderToStream(() => getPageElement(pageContext)).pipe; stampPipe(pageView, "node-stream"); } } - const lang = getLang(pageContext) || "en"; - const documentHtml = escapeInject` ${titleTag} - ${faviconTag} - ${descriptionTag} ${dangerouslySkipEscape(headHtml)} + ${faviconTag} ${dangerouslySkipEscape(generateHydrationScript())} @@ -68,10 +72,14 @@ const onRenderHtml: OnRenderHtmlAsync = async ( function checkVikeVersion() { if (version) { - const versionParts = version.split('.').map((s) => parseInt(s, 10)) as [number, number, number] - if (versionParts[0] > 0) return - if (versionParts[1] > 4) return - if (versionParts[2] >= 147) return + const versionParts = version.split(".").map((s) => parseInt(s, 10)) as [ + number, + number, + number + ]; + if (versionParts[0] > 0) return; + if (versionParts[1] > 4) return; + if (versionParts[2] >= 147) return; } - throw new Error('Update Vike to its latest version (or vike@0.4.147 and any version above)') + throw new Error("Update Vike to 0.4.147 or above"); } diff --git a/vike-solid/renderer/getHeadSetting.ts b/vike-solid/renderer/getHeadSetting.ts new file mode 100644 index 0000000..fbe47e8 --- /dev/null +++ b/vike-solid/renderer/getHeadSetting.ts @@ -0,0 +1,27 @@ +export { getHeadSetting }; + +import type { PageContext } from "vike/types"; +import { isCallable } from "./utils/isCallable.js"; + +function getHeadSetting( + headSetting: "title" | "favicon" | "lang", + pageContext: PageContext +): undefined | null | string { + const config = pageContext.configEntries[headSetting]?.[0]; + if (!config) return undefined; + const val = config.configValue; + if (typeof val === "string") return val; + if (!val) return null; + if (isCallable(val)) { + const valStr = val(pageContext); + if (typeof valStr! !== "string") { + throw new Error(config.configDefinedAt + " should return a string"); + } + return valStr; + } else { + throw new Error( + config.configDefinedAt + + " should be a string or a function returning a string" + ); + } +} diff --git a/vike-solid/renderer/getLang.ts b/vike-solid/renderer/getLang.ts deleted file mode 100644 index 7059af4..0000000 --- a/vike-solid/renderer/getLang.ts +++ /dev/null @@ -1,36 +0,0 @@ -export { getLang } - -import type { PageContext } from 'vike/types' -import { isCallable } from './utils/isCallable.js' - -/** - * Get the page's lang if defined, either from the config, the additional data fetched by - * the page's data() and onBeforeRender() hooks or from other hooks. - */ -function getLang(pageContext: PageContext): null | string { - // from onBeforeRoute() hook & other hooks, e.g. onPrerenderStart() hook - if (pageContext.lang !== undefined) { - return pageContext.lang - } - - const langConfig = pageContext.configEntries.lang?.[0] - if (!langConfig) { - return null - } - const lang = langConfig.configValue - if (typeof lang === 'string') { - return lang - } - if (!lang) { - return null - } - const { configDefinedAt } = langConfig - if (isCallable(lang)) { - const val = lang(pageContext) - if (typeof val !== 'string') { - throw new Error(configDefinedAt + ' should return a string') - } - return val - } - throw new Error(configDefinedAt + ' should be a string or a function returning a string') -} diff --git a/vike-solid/renderer/getPageElement.tsx b/vike-solid/renderer/getPageElement.tsx index decf032..3b9c3e4 100644 --- a/vike-solid/renderer/getPageElement.tsx +++ b/vike-solid/renderer/getPageElement.tsx @@ -26,13 +26,9 @@ function Layout(props: { children: JSX.Element }) { function Page() { const pageContext = usePageContext(); - // TODO/next-major-release: remove pageProps (i.e. tell users to use data() instead of onBeforeRender() to fetch data) return ( <> - + ); } diff --git a/vike-solid/renderer/getTitle.ts b/vike-solid/renderer/getTitle.ts deleted file mode 100644 index 4f659ec..0000000 --- a/vike-solid/renderer/getTitle.ts +++ /dev/null @@ -1,44 +0,0 @@ -export { getTitle }; - -import type { PageContext } from "vike/types"; -import { isCallable } from "./utils/isCallable"; - -/** - * Get the page's title if defined, either from the additional data fetched by - * the page's data() and onBeforeRender() hook or from the config. - */ -function getTitle(pageContext: PageContext): null | string { - // from data() hook - if (pageContext.data?.title !== undefined) { - return pageContext.data.title; - } - - // TODO/next-major-release: remove support for setting title over onBeforeRender() - // from onBeforeRender() hook - if (pageContext.title !== undefined) { - return pageContext.title; - } - - const titleConfig = pageContext.configEntries.title?.[0]; - if (!titleConfig) { - return null; - } - const title = titleConfig.configValue; - if (typeof title === "string") { - return title; - } - if (!title) { - return null; - } - const { configDefinedAt } = titleConfig; - if (isCallable(title)) { - const val = title(pageContext); - if (typeof val !== "string") { - throw new Error(configDefinedAt + " should return a string"); - } - return val; - } - throw new Error( - configDefinedAt + " should be a string or a function returning a string" - ); -} diff --git a/vike-solid/renderer/types.ts b/vike-solid/renderer/types.ts index 576b9a6..135cc10 100644 --- a/vike-solid/renderer/types.ts +++ b/vike-solid/renderer/types.ts @@ -2,31 +2,13 @@ export type { Component } from "solid-js"; import type { JSX } from "solid-js"; -type Page = (pageProps: PageProps) => JSX.Element; -type PageProps = Record; +type Page = () => JSX.Element; declare global { namespace Vike { interface PageContext { - // Note: Page will typically be undefined in onRenderHtml() when setting the `ssr` config flag - // to `false` (SPA mode). + // Page is undefined in onRenderHtml() when setting the `ssr` config flag to `false` Page?: Page; - - // TODO/next-major-release: remove pageProps (i.e. tell users to use data() instead of onBeforeRender() to fetch data) - /** Properties of the page's root Solid component - e.g. set by onBeforeRender() hook */ - pageProps?: Record; - - // TODO/next-major-release: remove support for setting title over onBeforeRender() - /** <title>${title}</title> - set by onBeforeRender() hook, has precedence over the config */ - title?: string; - - lang?: string; - - // Needed by getTitle() - data?: { - /** <title>${title}</title> - set by data() hook, has precedence over the onBeforeRender() hook */ - title?: string; - }; } } }